Reputation: 16525
I want to create performance test where I am encrypting data using AES with PKCPadding5/7 depends on provider(IBM or BouncyCastle) on aix system. My question is why first enumeration is so slow and other so fast ?
When I run test with parameters:
Padding: AES/CBC/PKCS7Padding
Provider: BC version 1.47
Number of iteration: 1000
results is:
Time: 392080057 ns
Time: 174662 ns
Time: 160906 ns
Time: 169938 ns
Time: 154344 ns
Time: 155125 ns
Time: 157344 ns
Time: 157203 ns
Time: 157611 ns
Time: 158123 ns
Parameters
Padding: AES/CBC/PKCS5Padding
Provider: IBMJCE version 1.7
Number of iteration: 1000
results is:
Time: 13410344 ns
Time: 185007 ns
Time: 182562 ns
Time: 170687 ns
Time: 203156 ns
Time: 189980 ns
Time: 182608 ns
Time: 174670 ns
Time: 176842 ns
Time: 174463 ns
Code:
for (int j = 0; j < pocetIteraci; j++) {
String text = randomString(46);
long time = System.currentTimeMillis();
sifruj(padding, provider, generateVectot(),text);
time = System.currentTimeMillis() - time;
System.out.println("Time: " + time + " ms");
}
public static byte[] sifruj(String padding, Provider provider, IvParameterSpec finalniInicializacniVektor,String text)
throws Exception {
return zpracuj(padding, provider, text.getBytes("UTF-8"), finalniInicializacniVektor, Cipher.ENCRYPT_MODE);
}
public static byte[] zpracuj(String padding, Provider provider, byte[] data,
IvParameterSpec finalniInicializacniVektor, int mode) throws Exception {
final SecretKeySpec klicSpec = new SecretKeySpec(klic, ALGORITHM_AES);
final Cipher sifra = Cipher.getInstance(padding, provider);
sifra.init(mode, klicSpec, finalniInicializacniVektor);
return sifra.doFinal(data);
}
UPDATED:
The most different (As I expected) is when creating first instance of cipher:
long timeTemp = System.nanoTime();
final Cipher sifra = Cipher.getInstance(padding, provider);
timeTemp = System.nanoTime() - timeTemp;
System.out.println("XXXXXXXXXXXXXXXXX " + timeTemp + " ns");
Why?
Upvotes: 1
Views: 784
Reputation: 7488
Crypto providers usually takes a bit to load. This can be seen by forcing it to load. Here i try with the IBM JCE provider):
public class Test {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
Security.addProvider(new com.ibm.crypto.provider.IBMJCE());
long endTime = System.currentTimeMillis();
System.out.println("Time to load: " + (endTime - startTime));
}
}
Gives:
Time to load: 72
My guess is that you hit this load time the first time you use anything from the provider.
Upvotes: 0
Reputation: 1500893
Revised answer
There's time taken to load and JIT-compile the code on the first call - that's why typically benchmarks don't include the first run. (In fact, many JVMs re-JIT more and more aggressively, so the performance improves over time - so good benchmarks run code lots of times before timing it.)
Additionally, it's not unreasonable to think that a crypto provider may well do some one-time setup, especially if it's trying its best to get some decent entropy. (It could be using SecureRandom
internally, for example.) You might want to time the Cipher.getInstance
, Cipher.init
and Cypher.doFinal
method calls separately, to determine which is the slow part.
Finally, you haven't shown us all the code (generateVectot
?) so there could be things lurking there.
Initial answer
Apparently randomString
is:
simple function which generate random string with certain length and yes is use SecureRandom which instance is crateted just once
Given that you're looking for something which is expensive (as creating and using a SecureRandom
instance is) and only happens once, this sounds like a smoking gun to me.
I suggest you add timing (using System.nanoTime
, not System.currentTimeMillis
) within randomString
to test that hypothesis.
I'd also strongly suggest that you don't use the overload of String.getBytes
which uses the platform default encoding - instead, always specify the encoding explicitly.
Upvotes: 2