---
.gitignore | 1 +
examples/Makefile.am | 16 +++++
examples/connect-benchmark.c | 112 +++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+)
diff --git a/.gitignore b/.gitignore
index 0d4bef92c..7bc0a6778 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ Makefile.in
/dump/nbddump.1
/examples/aio-connect-read
/examples/batched-read-write
+/examples/connect-benchmark
/examples/connect-command
/examples/connect-uri
/examples/copy-libev
diff --git a/examples/Makefile.am b/examples/Makefile.am
index bad22cb11..b52996a24 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -22,6 +22,7 @@ EXTRA_DIST = LICENSE-FOR-EXAMPLES
noinst_PROGRAMS = \
aio-connect-read \
batched-read-write \
+ connect-benchmark \
connect-command \
connect-uri \
encryption \
@@ -62,6 +63,21 @@ batched_read_write_LDADD = \
$(top_builddir)/lib/libnbd.la \
$(NULL)
+connect_benchmark_SOURCES = \
+ connect-benchmark.c \
+ $(NULL)
+connect_benchmark_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ $(NULL)
+connect_benchmark_CFLAGS = \
+ $(WARNINGS_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(NULL)
+connect_benchmark_LDADD = \
+ $(top_builddir)/lib/libnbd.la \
+ $(PTHREAD_LIBS) \
+ $(NULL)
+
connect_command_SOURCES = \
connect-command.c \
$(NULL)
diff --git a/examples/connect-benchmark.c b/examples/connect-benchmark.c
new file mode 100644
index 000000000..1e153b915
--- /dev/null
+++ b/examples/connect-benchmark.c
@@ -0,0 +1,112 @@
+/* The example benchmarks multiple parallel connections to an NBD
+ * server. You can use it to time how long it takes to connect under
+ * various circumstances (eg. TLS vs no TLS, old vs newstyle, with or
+ * without TCP fastopen). It only does the NBD handshake and then
+ * immediately disconnects.
+ *
+ * Typical usage:
+ * ./examples/connect-benchmark nbd://localhost 16 1000
+ * where the parameters are:
+ * URI of the server
+ * number of threads
+ * total number of connections to make (across all threads)
+ *
+ * Or:
+ * nbdkit null --run './examples/connect-benchmark "$uri" 16 1000'
+ *
+ * Use 'hyperfine' to time multiple runs.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#include <libnbd.h>
+
+static const char *uri;
+static unsigned nr_threads, nr_connections;
+static _Atomic unsigned count = 0;
+
+static void *start_thread (void *arg);
+
+int
+main (int argc, char *argv[])
+{
+ pthread_t *threads;
+ unsigned i;
+ int err;
+
+ if (argc != 4) {
+ fprintf (stderr, "%s URI threads connections\n", argv[0]);
+ exit (EXIT_FAILURE);
+ }
+ uri = argv[1];
+ if (sscanf (argv[2], "%u", &nr_threads) != 1 ||
+ sscanf (argv[3], "%u", &nr_connections) != 1) {
+ fprintf (stderr, "%s: cannot read number of threads or connections\n",
+ argv[0]);
+ exit (EXIT_FAILURE);
+ }
+
+ threads = calloc (nr_threads, sizeof threads[0]);
+ if (threads == NULL) {
+ perror ("calloc");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Start the worker threads, one per connection. */
+ for (i = 0; i < nr_threads; ++i) {
+ err = pthread_create (&threads[i], NULL, start_thread, NULL);
+ if (err != 0) {
+ errno = err;
+ perror ("pthread_create");
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ /* Wait for the threads to exit. */
+ for (i = 0; i < nr_threads; ++i) {
+ err = pthread_join (threads[i], NULL);
+ if (err != 0) {
+ errno = err;
+ perror ("pthread_join");
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ exit (EXIT_SUCCESS);
+}
+
+static void *
+start_thread (void *arg)
+{
+ struct nbd_handle *nbd;
+ unsigned i;
+
+ for (;;) {
+ i = count++;
+ if (i >= nr_connections) break;
+
+ nbd = nbd_create ();
+ if (nbd == NULL) {
+ fprintf (stderr, "%s\n", nbd_get_error ());
+ exit (EXIT_FAILURE);
+ }
+
+ if (nbd_connect_uri (nbd, uri) == -1) {
+ fprintf (stderr, "%s\n", nbd_get_error ());
+ exit (EXIT_FAILURE);
+ }
+
+ nbd_close (nbd);
+ }
+
+ pthread_exit (NULL);
+}
--
2.46.0