Add an RSA signing performance test
authorMatt Caswell <matt@openssl.org>
Fri, 26 May 2023 14:24:54 +0000 (15:24 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 29 May 2023 10:56:57 +0000 (11:56 +0100)
Unlike "speed" this performs RSA operations in parallel using threads
(as opposed to the -multi speed option which uses "fork").

Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/tools/pull/152)

perf/Makefile
perf/README
perf/rsasign.c [new file with mode: 0644]

index 599b810cae79c4572937d837a3780fec4c42d9d1..28e5f3dbd000a6d46ac0dfa5a7546b3e7b23c9fb 100644 (file)
@@ -1,7 +1,7 @@
-all: randbytes handshake sslnew newrawkey
+all: randbytes handshake sslnew newrawkey rsasign
 
 clean:
-       rm libperf.a *.o randbytes handshake sslnew newrawkey
+       rm libperf.a *.o randbytes handshake sslnew newrawkey rsasign
 
 libperf.a: perflib/*.c perflib/*.h
        gcc -I$(TARGET_OSSL_INCLUDE_PATH) -I. -c perflib/*.c
@@ -18,3 +18,6 @@ sslnew: sslnew.c libperf.a
 
 newrawkey:     newrawkey.c libperf.a
        gcc -L$(TARGET_OSSL_LIBRARY_PATH) -L. -I$(TARGET_OSSL_INCLUDE_PATH) -I. -o newrawkey newrawkey.c -lperf -lcrypto
+
+rsasign: rsasign.c libperf.a
+       gcc -L$(TARGET_OSSL_LIBRARY_PATH) -L. -I$(TARGET_OSSL_INCLUDE_PATH) -I. -o rsasign rsasign.c -lperf -lcrypto
index bb2ea8bab2571ed8829f266aebdecead3194c463..aab2d04a4f1d46f44906d6e1437b85c281356b1f 100644 (file)
@@ -80,3 +80,11 @@ take to execute a block of 100 EVP_PKEY_new_raw_public_key_ex() calls.
 
 Note that this test does not support OpenSSL 1.1.1.
 
+rsasign
+-------
+
+The rsasign test repeatedly calls the EVP_PKEY_sign_init()/EVP_PKEY_sign()
+functions in blocks of 100 calls, and 100 blocks per thread, using a 512 bit RSA
+key. The number of threads to use is provided as an argument and the test
+reports the average time take to execute a block of 100
+EVP_PKEY_sign_init()/EVP_PKEY_sign() calls.
diff --git a/perf/rsasign.c b/perf/rsasign.c
new file mode 100644 (file)
index 0000000..fdc189a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/crypto.h>
+#include "perflib/perflib.h"
+
+#define NUM_CALLS_PER_BLOCK         100
+#define NUM_CALL_BLOCKS_PER_THREAD  100
+#define NUM_CALLS_PER_THREAD        (NUM_CALLS_PER_BLOCK * NUM_CALL_BLOCKS_PER_THREAD)
+
+int err = 0;
+EVP_PKEY *rsakey = NULL;
+
+static const char *rsakeypem =
+    "-----BEGIN PRIVATE KEY-----\n"
+    "MIIBVwIBADANBgkqhkiG9w0BAQEFAASCAUEwggE9AgEAAkEAwmjwpbuKfvtBTAiQ\n"
+    "U4OWjPVo0WM1UGGh9EJwgTnJm43l0HwL3GjmPBmToqhUYE6zfWi9jOpQkCSpDnIR\n"
+    "1Pc18QIDAQABAkEAsKZmNFIK8IMhvBL0Ac7J19+OlOSOpzFv1eEhFWsK9FoNnsV/\n"
+    "4Z4KlISNB+b7M5OJxYs4AutQIKr6zmlT7lk7OQIhAPj/LPWwkk+Ts2pBB64CokZ0\n"
+    "C7GCeloMiPc3mCxsWbbnAiEAx+C6ham16nvvVUnYjoWSpNTuAhV61+FR0xKLk797\n"
+    "iWcCIQCEy1KnFaxyVEtzd4so+q6g9HLoELZAID9L2ZKG3qJaMQIhAJFIU8tb9BKg\n"
+    "SvJfXr0ZceHFs8pn+oZ4DJWzYSjfgdf5AiEAmk7Kt7Y8qPVJwb5bJL5CkoBxRwzS\n"
+    "jHZXmRwpxC4tAFo=\n"
+    "-----END PRIVATE KEY-----\n";
+
+static const char *tbs = "0123456789abcdefghij"; /* Length of SHA1 digest */
+
+void do_rsasign(size_t num)
+{
+    int i;
+    unsigned char buf[32];
+    unsigned char sig[64];
+    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(rsakey, NULL);
+    size_t siglen = sizeof(sig);
+
+    for (i = 0; i < NUM_CALLS_PER_THREAD; i++) {
+        if (EVP_PKEY_sign_init(ctx) <= 0
+                || EVP_PKEY_sign(ctx, sig, &siglen, tbs, SHA_DIGEST_LENGTH) <= 0) {
+            err = 1;
+            break;
+        }
+    }
+    EVP_PKEY_CTX_free(ctx);
+}
+
+int main(int argc, char *argv[])
+{
+    int threadcount;
+    OSSL_TIME duration;
+    uint64_t us;
+    double avcalltime;
+    int terse = 0;
+    int argnext;
+    BIO *membio = NULL;
+
+    if ((argc != 2 && argc != 3)
+                || (argc == 3 && strcmp("--terse", argv[1]) != 0)) {
+        printf("Usage: rsasign [--terse] threadcount\n");
+        return EXIT_FAILURE;
+    }
+
+    if (argc == 3) {
+        terse = 1;
+        argnext = 2;
+    } else {
+        argnext = 1;
+    }
+
+    threadcount = atoi(argv[argnext]);
+    if (threadcount < 1) {
+        printf("threadcount must be > 0\n");
+        return EXIT_FAILURE;
+    }
+
+    assert(strlen(tbs) == SHA_DIGEST_LENGTH);
+    membio = BIO_new_mem_buf(rsakeypem, strlen(rsakeypem));
+    if (membio == NULL) {
+        printf("Failed to create internal BIO\n");
+        return EXIT_FAILURE;
+    }
+    rsakey = PEM_read_bio_PrivateKey(membio, NULL, NULL, NULL);
+    BIO_free(membio);
+    if (rsakey == NULL) {
+        printf("Failed to load the RSA key\n");
+        return EXIT_FAILURE;
+    }
+
+    if (!perflib_run_multi_thread_test(do_rsasign, threadcount, &duration)) {
+        printf("Failed to run the test\n");
+        EVP_PKEY_free(rsakey);
+        return EXIT_FAILURE;
+    }
+    EVP_PKEY_free(rsakey);
+
+    if (err) {
+        printf("Error during test\n");
+        return EXIT_FAILURE;
+    }
+
+    us = ossl_time2us(duration);
+
+    avcalltime = (double)us / (NUM_CALL_BLOCKS_PER_THREAD * threadcount);
+
+    if (terse)
+        printf("%lf\n", avcalltime);
+    else
+        printf("Average time per %d RSA signature operations: %lfus\n",
+               NUM_CALLS_PER_BLOCK, avcalltime);
+
+    return EXIT_SUCCESS;
+}