Add a performance test for constructing an SSL and associated BIO objects
authorMatt Caswell <matt@openssl.org>
Wed, 24 May 2023 13:18:24 +0000 (14:18 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 29 May 2023 10:50:46 +0000 (11:50 +0100)
We repeatedly call SSL_new() and BIO_new() (followed by appropriate free
calls), for a specified number of threads.

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

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

index b70f5a434e5b1cc969370d5138a2d757b583cd1e..6b2514ab1f71e1e14591259c91b30bd29a6f464e 100644 (file)
@@ -1,7 +1,7 @@
-all: randbytes handshake
+all: randbytes handshake sslnew
 
 clean:
-       rm libperf.a *.o randbytes handshake
+       rm libperf.a *.o randbytes handshake sslnew
 
 libperf.a: perflib/*.c perflib/*.h
        gcc -I$(TARGET_OSSL_INCLUDE_PATH) -I. -c perflib/*.c
@@ -12,3 +12,6 @@ randbytes:    randbytes.c libperf.a
 
 handshake: handshake.c libperf.a
        gcc -L$(TARGET_OSSL_LIBRARY_PATH) -L. -I$(TARGET_OSSL_INCLUDE_PATH) -I. -o handshake handshake.c -lperf -lcrypto -lssl
+
+sslnew: sslnew.c libperf.a
+       gcc -L$(TARGET_OSSL_LIBRARY_PATH) -L. -I$(TARGET_OSSL_INCLUDE_PATH) -I. -o sslnew sslnew.c -lperf -lcrypto -lssl
index 680df60f953644845e282e26b467e056e40c9e9a..a039190c7d0c0996b8c4192d0ea8876bb86d4adc 100644 (file)
@@ -60,3 +60,12 @@ threadcount - The number of threads to perform handshakes on in the test
 
 The output is two values: the average time taken for a handshake in us, and the
 average handshakes per second performed over the course of the test.
+
+sslnew
+------
+
+The sslnew test repeatedly constructs a new SSL object and associates it with a
+newly constructed read BIO and a newly constructed write BIO, and finally frees
+them again. It does this in blocks of 100 sets of calls, and 100 blocks per
+threads. The number of threads to use is provided as an argument and the test
+reports the average time taken to execute a block of 100 construction/free calls.
diff --git a/perf/sslnew.c b/perf/sslnew.c
new file mode 100644 (file)
index 0000000..014a897
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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 <openssl/ssl.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;
+static SSL_CTX *ctx;
+
+void do_sslnew(size_t num)
+{
+    int i;
+    SSL *s;
+    BIO *rbio, *wbio;
+
+    for (i = 0; i < NUM_CALLS_PER_THREAD; i++) {
+        s = SSL_new(ctx);
+        rbio = BIO_new(BIO_s_mem());
+        wbio = BIO_new(BIO_s_mem());
+
+        if (s == NULL || rbio == NULL || wbio == NULL) {
+            err = 1;
+            BIO_free(rbio);
+            BIO_free(wbio);
+        } else {
+            /* consumes the rbio/wbio references */
+            SSL_set_bio(s, rbio, wbio);
+        }
+
+        SSL_free(s);
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int threadcount;
+    OSSL_TIME duration;
+    uint64_t us;
+    double avcalltime;
+    int terse = 0;
+    int argnext;
+
+    if ((argc != 2 && argc != 3)
+                || (argc == 3 && strcmp("--terse", argv[1]) != 0)) {
+        printf("Usage: sslnew [--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;
+    }
+
+    ctx = SSL_CTX_new(TLS_server_method());
+    if (ctx == NULL) {
+        printf("Failure to create SSL_CTX\n");
+        return EXIT_FAILURE;
+    }
+
+    if (!perflib_run_multi_thread_test(do_sslnew, threadcount, &duration)) {
+        SSL_CTX_free(ctx);
+        printf("Failed to run the test\n");
+        return EXIT_FAILURE;
+    }
+
+    SSL_CTX_free(ctx);
+
+    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 SSL/BIO creation calls: %lfus\n",
+            NUM_CALLS_PER_BLOCK, avcalltime);
+
+    return EXIT_SUCCESS;
+}