Rename BUFFER_SIZE to REQUEST_SIZE and get the value from an environment
variable. Change the test script to test multiple values.
An example run:
$ ./synch-parallel.sh
Request size: 4096
thread 0: finished OK in 10.000019 seconds
thread 4: finished OK in 10.000003 seconds
thread 2: finished OK in 10.000015 seconds
thread 1: finished OK in 10.000053 seconds
thread 6: finished OK in 10.000075 seconds
thread 7: finished OK in 10.000012 seconds
thread 3: finished OK in 10.000024 seconds
thread 5: finished OK in 10.000000 seconds
TLS: disabled
bytes sent: 2412867584 (230.109 MiB/s)
bytes received: 2419851264 (230.775 MiB/s)
I/O requests: 1179863 (117986 IOPS)
Request size: 262144
thread 2: finished OK in 10.000030 seconds
thread 5: finished OK in 10.000415 seconds
thread 1: finished OK in 10.000500 seconds
thread 3: finished OK in 10.000459 seconds
thread 6: finished OK in 10.000275 seconds
thread 4: finished OK in 10.000520 seconds
thread 7: finished OK in 10.000529 seconds
thread 0: finished OK in 10.000768 seconds
TLS: disabled
bytes sent: 12791840768 (1219.92 MiB/s)
bytes received: 12748324864 (1215.78 MiB/s)
I/O requests: 97428 (9742.8 IOPS)
4k is a good size to test IOPS, and 256k is a good size for getting
maximum throughput. I kept the current default 16k as is.
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
tests/synch-parallel.c | 51 +++++++++++++++++++++++++++++++++--------
tests/synch-parallel.sh | 12 ++++++----
2 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/tests/synch-parallel.c b/tests/synch-parallel.c
index 423e1f0..d6ab1df 100644
--- a/tests/synch-parallel.c
+++ b/tests/synch-parallel.c
@@ -36,82 +36,115 @@
#include <sys/time.h>
#include <pthread.h>
#include <libnbd.h>
#include "byte-swapping.h"
/* We keep a shadow of the RAM disk so we can check integrity of the data. */
static char *ramdisk;
/* This is also defined in synch-parallel.sh and checked here. */
#define EXPORTSIZE (8*1024*1024)
/* How long (seconds) that the test will run for. */
#define RUN_TIME 10
/* Number of threads. */
#define NR_THREADS 8
-#define MiB (1024*1024)
+#define KiB 1024
+#define MiB (1024*KiB)
#define MICROSECONDS 1000000
/* Unix socket. */
static const char *unixsocket;
+static long request_size;
+
struct thread_status {
size_t i; /* Thread index, 0 .. NR_THREADS-1 */
uint64_t offset, length; /* Area assigned to this thread. */
int status; /* Return status. */
unsigned requests; /* Total number of requests made. */
uint64_t bytes_sent, bytes_received; /* Bytes sent and received by thread. */
};
static void *start_thread (void *arg);
static inline int64_t
microtime (void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * MICROSECONDS + tv.tv_usec;
}
+static long
+getenv_long(const char *name, long defval)
+{
+ const char *value;
+ char *end;
+ long res;
+
+ value = getenv (name);
+ if (value == NULL)
+ return defval;
+
+ res = strtol(value, &end, 10);
+ if (*end != '\0' || end == value) {
+ fprintf (stderr, "Invalid value for %s: '%s'\n", name, value);
+ exit (EXIT_FAILURE);
+ }
+
+ return res;
+}
+
int
main (int argc, char *argv[])
{
pthread_t threads[NR_THREADS];
struct thread_status status[NR_THREADS];
size_t i;
int err;
unsigned requests, errors;
uint64_t bytes_sent, bytes_received;
if (argc != 2) {
fprintf (stderr, "%s socket\n", argv[0]);
exit (EXIT_FAILURE);
}
unixsocket = argv[1];
+ request_size = getenv_long ("REQUEST_SIZE", 16*KiB);
+ if (request_size < 4*KiB ||
+ request_size > 512*KiB ||
+ (EXPORTSIZE / NR_THREADS) % request_size != 0) {
+ fprintf (stderr,
+ "Invalid REQUEST_SIZE environment variable: %ld\n",
+ request_size);
+ exit (EXIT_FAILURE);
+ }
+
srand ((microtime () / MICROSECONDS) + getpid ());
/* Initialize the RAM disk with the initial data from
* nbdkit-pattern-filter.
*/
ramdisk = malloc (EXPORTSIZE);
if (ramdisk == NULL) {
perror ("calloc");
exit (EXIT_FAILURE);
}
for (i = 0; i < EXPORTSIZE; i += 8) {
uint64_t d = htobe64 (i);
memcpy (&ramdisk[i], &d, sizeof d);
}
/* Start the worker threads. */
for (i = 0; i < NR_THREADS; ++i) {
status[i].i = i;
status[i].offset = i * EXPORTSIZE / NR_THREADS;
status[i].length = EXPORTSIZE / NR_THREADS;
@@ -152,53 +185,51 @@ main (int argc, char *argv[])
/* Print some stats. */
printf ("TLS: %s\n",
#ifdef TLS
"enabled"
#else
"disabled"
#endif
);
printf ("bytes sent: %" PRIu64 " (%g MiB/s)\n",
bytes_sent, (double) bytes_sent / RUN_TIME / MiB);
printf ("bytes received: %" PRIu64 " (%g MiB/s)\n",
bytes_received, (double) bytes_received / RUN_TIME / MiB);
printf ("I/O requests: %u (%g IOPS)\n",
requests, (double) requests / RUN_TIME);
exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
-#define BUFFER_SIZE 16384
-
static void *
start_thread (void *arg)
{
struct thread_status *status = arg;
struct nbd_handle *nbd;
char *buf;
int cmd;
uint64_t offset;
int64_t start_usec, stop_usec, now_usec;
- buf = calloc (BUFFER_SIZE, 1);
+ buf = calloc (request_size, 1);
if (buf == NULL) {
perror ("calloc");
exit (EXIT_FAILURE);
}
nbd = nbd_create ();
if (nbd == NULL) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
#ifdef TLS
/* Require TLS on the handle and fail if not available or if the
* handshake fails.
*/
if (nbd_set_tls (nbd, LIBNBD_TLS_REQUIRE) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
@@ -217,58 +248,58 @@ start_thread (void *arg)
if (nbd_connect_unix (nbd, unixsocket) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
assert (nbd_get_size (nbd) == EXPORTSIZE);
assert (nbd_can_multi_conn (nbd) > 0);
assert (nbd_is_read_only (nbd) == 0);
start_usec = microtime ();
stop_usec = start_usec + RUN_TIME * MICROSECONDS;
/* Issue commands. */
while (1) {
/* Run until the timer expires. */
now_usec = microtime ();
if (now_usec >= stop_usec)
break;
/* Issue a synchronous read or write command. */
- offset = status->offset + (rand () % (status->length - BUFFER_SIZE));
+ offset = status->offset + (rand () % (status->length - request_size));
cmd = rand () & 1;
if (cmd == 0) {
/* Write block from ramdisk to nbd server. */
- if (nbd_pwrite (nbd, &ramdisk[offset], BUFFER_SIZE, offset, 0) == -1) {
+ if (nbd_pwrite (nbd, &ramdisk[offset], request_size, offset, 0) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
goto error;
}
- status->bytes_sent += BUFFER_SIZE;
+ status->bytes_sent += request_size;
}
else {
/* Read block from nbd server to buf. */
- if (nbd_pread (nbd, buf, BUFFER_SIZE, offset, 0) == -1) {
+ if (nbd_pread (nbd, buf, request_size, offset, 0) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
goto error;
}
- status->bytes_received += BUFFER_SIZE;
- if (memcmp (&ramdisk[offset], buf, BUFFER_SIZE) != 0) {
+ status->bytes_received += request_size;
+ if (memcmp (&ramdisk[offset], buf, request_size) != 0) {
fprintf (stderr, "thread %zu: DATA INTEGRITY ERROR!\n", status->i);
goto error;
}
}
status->requests++;
}
printf ("thread %zu: finished OK in %.6f seconds\n",
status->i, (double) (now_usec - start_usec) / MICROSECONDS);
if (nbd_shutdown (nbd, 0) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
goto error;
}
nbd_close (nbd);
free (buf);
status->status = 0;
diff --git a/tests/synch-parallel.sh b/tests/synch-parallel.sh
index 84c00d8..0ca9060 100755
--- a/tests/synch-parallel.sh
+++ b/tests/synch-parallel.sh
@@ -1,24 +1,28 @@
#!/usr/bin/env bash
# nbd client library in userspace
# Copyright (C) 2019 Red Hat Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Test synchronous parallel high level API requests.
-nbdkit -U - \
- --filter=cow \
- pattern size=8M \
- --run '$VG ./synch-parallel $unixsocket'
+for request_size in 4096 262144; do
+ echo "Request size: $request_size"
+ REQUEST_SIZE=$request_size nbdkit -U - \
+ --filter=cow \
+ pattern size=8M \
+ --run '$VG ./synch-parallel $unixsocket'
+ echo
+done
--
2.31.1