RFR: 8344144: AES/CBC slow at big payloads

Volodymyr Paprotski vpaprotski at openjdk.org
Wed Nov 13 21:19:57 UTC 2024


On Wed, 13 Nov 2024 21:14:58 GMT, Volodymyr Paprotski <vpaprotski at openjdk.org> wrote:

> Measuring throughput with JMH parameters `-f 1 -i 2 -wi 3 -r 20 -w 30  -p algorithm=AES/CBC/NoPadding -p dataSize=30000000 -p provider=SunJCE -p keyLength=128 org.openjdk.bench.javax.crypto.full.AESBench`
> 
> Before:
> 
> Benchmark                (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt   Score   Error  Units
> AESBench.decrypt   AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2  25.383          ops/s
> AESBench.decrypt2  AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2  32.230          ops/s
> AESBench.encrypt   AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2  20.489          ops/s
> AESBench.encrypt2  AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2  21.383          ops/s
> 
> 
> After:
> 
> Benchmark                (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt    Score   Error  Units
> AESBench.decrypt   AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2  215.144          ops/s
> AESBench.decrypt2  AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2  411.265          ops/s
> AESBench.encrypt   AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2   64.341          ops/s
> AESBench.encrypt2  AES/CBC/NoPadding    30000000          128      SunJCE  thrpt    2   73.114          ops/s
> 
> 
> I have not deterministically proven why chunking works: before the change, the CBC intrinsic is not being used; and after chunking, it is. There is quite a bit of GC activity in the default AESBench, so `encrypt2/decrypt2` versions isolate just crypto (see comment below).

If you are trying to reproduce results, the AESBench was modified for large payloads as follows (encrypt2/decrypt2 cause less GC churn by using existing memory):

diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java
index 7e1eecdace4..93cf9a1d30f 100644
--- a/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java
+++ b/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java
@@ -25,6 +25,9 @@
 import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.Param;
 import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.infra.Blackhole;
+import java.security.GeneralSecurityException;
+import org.openjdk.jmh.annotations.Fork;

 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
@@ -36,9 +39,10 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.spec.InvalidParameterSpecException;

+ at Fork(jvmArgsAppend = {"-Xms20g", "-Xmx20g", "-XX:+UseZGC"})
 public class AESBench extends CryptoBase {

-    public static final int SET_SIZE = 128;
+    public static final int SET_SIZE = 8;

     @Param({"AES/ECB/NoPadding", "AES/ECB/PKCS5Padding", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding"})
     private String algorithm;
@@ -53,6 +57,7 @@ public class AESBench extends CryptoBase {
     byte[][] encryptedData;
     private Cipher encryptCipher;
     private Cipher decryptCipher;
+    private byte[] outBuffer;
     int index = 0;

     @Setup
@@ -66,6 +71,7 @@ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, Inv
         decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters());
         data = fillRandom(new byte[SET_SIZE][dataSize]);
         encryptedData = fillEncrypted(data, encryptCipher);
+        outBuffer = new byte[dataSize + 128]; // extra space for tag, etc
     }

     @Benchmark
@@ -75,6 +81,13 @@ public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException {
         return encryptCipher.doFinal(d);
     }

+    @Benchmark
+    public void encrypt2(Blackhole bh) throws GeneralSecurityException {
+        byte[] d = data[index];
+        index = (index +1) % SET_SIZE;
+        bh.consume(encryptCipher.doFinal(d, 0, d.length, outBuffer));
+    }
+
     @Benchmark
     public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException {
         byte[] e = encryptedData[index];
@@ -82,4 +95,11 @@ public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException {
         return decryptCipher.doFinal(e);
     }

+    @Benchmark
+    public void decrypt2(Blackhole bh) throws GeneralSecurityException {
+        byte[] e = encryptedData[index];
+        index = (index +1) % SET_SIZE;
+        bh.consume(decryptCipher.doFinal(e, 0, e.length, outBuffer));
+    }
+
 }

-------------

PR Comment: https://git.openjdk.org/jdk/pull/22086#issuecomment-2474800106


More information about the security-dev mailing list