Use microtime() for stopping the request loop. With this all threads run for 10.000400 (+-0.000400), so using 10.0 seconds for computing the stats is correct. Because the run time is practically the same in all runs, we get more stable results for multiple runs.
Here are few example runs: $ ./synch-parallel.sh thread 4: finished OK in 10.000023 seconds thread 1: finished OK in 10.000090 seconds thread 0: finished OK in 10.000170 seconds thread 2: finished OK in 10.000159 seconds thread 5: finished OK in 10.000124 seconds thread 3: finished OK in 10.000546 seconds thread 6: finished OK in 10.000705 seconds thread 7: finished OK in 10.000203 seconds TLS: disabled bytes sent: 6558744576 (655.874 Mbytes/s) bytes received: 6567395328 (656.74 Mbytes/s) I/O requests: 801156 (80115.6 IOPS) $ ./synch-parallel.sh thread 1: finished OK in 10.000013 seconds thread 4: finished OK in 10.000083 seconds thread 2: finished OK in 10.000007 seconds thread 0: finished OK in 10.000046 seconds thread 3: finished OK in 10.000080 seconds thread 6: finished OK in 10.000013 seconds thread 7: finished OK in 10.000052 seconds thread 5: finished OK in 10.000266 seconds TLS: disabled bytes sent: 6436765696 (643.677 Mbytes/s) bytes received: 6409781248 (640.978 Mbytes/s) I/O requests: 784091 (78409.1 IOPS) $ ./synch-parallel.sh thread 1: finished OK in 10.000037 seconds thread 0: finished OK in 10.000030 seconds thread 7: finished OK in 10.000017 seconds thread 2: finished OK in 10.000066 seconds thread 5: finished OK in 10.000168 seconds thread 4: finished OK in 10.000037 seconds thread 6: finished OK in 10.000144 seconds thread 3: finished OK in 10.000806 seconds TLS: disabled bytes sent: 6416236544 (641.624 Mbytes/s) bytes received: 6434586624 (643.459 Mbytes/s) I/O requests: 784352 (78435.2 IOPS) Signed-off-by: Nir Soffer <[email protected]> --- tests/synch-parallel.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/synch-parallel.c b/tests/synch-parallel.c index 686e406..72402d7 100644 --- a/tests/synch-parallel.c +++ b/tests/synch-parallel.c @@ -43,98 +43,91 @@ /* 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 MICROSECONDS 1000000 /* Unix socket. */ static const char *unixsocket; struct thread_status { size_t i; /* Thread index, 0 .. NR_THREADS-1 */ - time_t end_time; /* Threads run until this end time. */ 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; } int main (int argc, char *argv[]) { pthread_t threads[NR_THREADS]; struct thread_status status[NR_THREADS]; size_t i; - time_t t; 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]; - /* Get the current time and the end time. */ - time (&t); - t += RUN_TIME; - - srand (t + getpid ()); + 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].end_time = t; status[i].offset = i * EXPORTSIZE / NR_THREADS; status[i].length = EXPORTSIZE / NR_THREADS; status[i].status = 0; status[i].requests = 0; status[i].bytes_sent = status[i].bytes_received = 0; err = pthread_create (&threads[i], NULL, start_thread, &status[i]); if (err != 0) { errno = err; perror ("pthread_create"); exit (EXIT_FAILURE); } } /* Wait for the threads to exit. */ errors = 0; requests = 0; bytes_sent = bytes_received = 0; for (i = 0; i < NR_THREADS; ++i) { err = pthread_join (threads[i], NULL); if (err != 0) { @@ -167,42 +160,41 @@ main (int argc, char *argv[]) bytes_sent, (double) bytes_sent / RUN_TIME / 1000000); printf ("bytes received: %" PRIu64 " (%g Mbytes/s)\n", bytes_received, (double) bytes_received / RUN_TIME / 1000000); 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; - time_t t; - int64_t start_usec, run_usec; + int64_t start_usec, stop_usec, now_usec; buf = calloc (BUFFER_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); @@ -213,77 +205,76 @@ start_thread (void *arg) exit (EXIT_FAILURE); } if (nbd_set_tls_psk_file (nbd, "keys.psk") == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } #endif /* Connect to nbdkit. */ 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. */ - time (&t); - if (t > status->end_time) + now_usec = microtime (); + if (now_usec >= stop_usec) break; /* Issue a synchronous read or write command. */ offset = status->offset + (rand () % (status->length - BUFFER_SIZE)); cmd = rand () & 1; if (cmd == 0) { if (nbd_pwrite (nbd, buf, BUFFER_SIZE, offset, 0) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); goto error; } status->bytes_sent += BUFFER_SIZE; memcpy (&ramdisk[offset], buf, BUFFER_SIZE); } else { if (nbd_pread (nbd, buf, BUFFER_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) { fprintf (stderr, "thread %zu: DATA INTEGRITY ERROR!\n", status->i); goto error; } } status->requests++; } - run_usec = microtime () - start_usec; - printf ("thread %zu: finished OK in %.6f seconds\n", - status->i, (double) run_usec / MICROSECONDS); + 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; pthread_exit (status); error: free (buf); fprintf (stderr, "thread %zu: failed\n", status->i); status->status = -1; pthread_exit (status); } -- 2.31.1 _______________________________________________ Libguestfs mailing list [email protected] https://listman.redhat.com/mailman/listinfo/libguestfs
