From 24fa9b2a04ff24d0f10aa3882e4069c561a2ef04 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Mon, 13 Feb 2017 21:52:41 +0300 Subject: [PATCH 1/2] Do not require Autoconf 2.64, as CentOS 6 provides 2.63. The only required bit from Autoconf 2.64 is AS_VAR_IF. Which is in fact provided, but just in case there is now a fallback implementation in m4/sb_autoconf_compat.m4. --- m4/ax_check_compile_flag.m4 | 2 +- m4/sb_autoconf_compat.m4 | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 m4/sb_autoconf_compat.m4 diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 index ca36397..99a2220 100644 --- a/m4/ax_check_compile_flag.m4 +++ b/m4/ax_check_compile_flag.m4 @@ -58,7 +58,7 @@ #serial 4 AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +[ AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS diff --git a/m4/sb_autoconf_compat.m4 b/m4/sb_autoconf_compat.m4 new file mode 100644 index 0000000..00c4770 --- /dev/null +++ b/m4/sb_autoconf_compat.m4 @@ -0,0 +1,13 @@ +# --------------------------------------------------------------------------- +# Provide various compatibility macros for older Autoconf machines +# Definitions were copied from the Autoconf source code. +# --------------------------------------------------------------------------- +m4_ifdef([AS_VAR_IF],,m4_define([AS_VAR_IF], +[AS_LITERAL_WORD_IF([$1], + [AS_IF(m4_ifval([$2], [[test "x$$1" = x[]$2]], [[${$1:+false} :]])], + [AS_VAR_COPY([as_val], [$1]) + AS_IF(m4_ifval([$2], [[test "x$as_val" = x[]$2]], [[${as_val:+false} :]])], + [AS_IF(m4_ifval([$2], + [[eval test \"x\$"$1"\" = x"_AS_ESCAPE([$2], [`], [\"$])"]], + [[eval \${$1:+false} :]])]), +[$3], [$4])]))dnl From ba8b1d0781dbf9a991c807e98f4834919b9ad51b Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Tue, 14 Feb 2017 20:53:08 +0300 Subject: [PATCH 2/2] Get rid of timers_mutex, improve --report-checkpoints scalability. --- src/db_driver.c | 2 +- src/sb_timer.c | 26 ++++++++++++++++++++++++-- src/sb_timer.h | 22 ++++++++++++++++++++-- src/sysbench.c | 40 +++++----------------------------------- 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/db_driver.c b/src/db_driver.c index 7c69b2e..c4dabb1 100644 --- a/src/db_driver.c +++ b/src/db_driver.c @@ -1083,7 +1083,7 @@ static void db_reset_stats(void) So that intermediate stats are calculated from the current moment rather than from the previous intermediate report */ - sb_timer_checkpoint(&sb_intermediate_timer); + sb_timer_current(&sb_intermediate_timer); if (db_globals.debug) { diff --git a/src/sb_timer.c b/src/sb_timer.c index 8224348..01ddf3b 100644 --- a/src/sb_timer.c +++ b/src/sb_timer.c @@ -42,6 +42,9 @@ void sb_timer_init(sb_timer_t *t) memset(&t->time_start, 0, sizeof(struct timespec)); memset(&t->time_end, 0, sizeof(struct timespec)); + + ck_spinlock_init(&t->lock); + sb_timer_reset(t); } @@ -61,6 +64,8 @@ void sb_timer_reset(sb_timer_t *t) void sb_timer_copy(sb_timer_t *to, sb_timer_t *from) { memcpy(to, from, sizeof(sb_timer_t)); + + ck_spinlock_init(&to->lock); } /* check whether the timer is running */ @@ -71,12 +76,12 @@ bool sb_timer_running(sb_timer_t *t) } /* - get time elapsed since the previous call to sb_timer_checkpoint() for the + get time elapsed since the previous call to sb_timer_current() for the specified timer without stopping it. The first call returns time elapsed since the timer was started. */ -uint64_t sb_timer_checkpoint(sb_timer_t *t) +uint64_t sb_timer_current(sb_timer_t *t) { struct timespec tmp; uint64_t res; @@ -88,6 +93,23 @@ uint64_t sb_timer_checkpoint(sb_timer_t *t) return res; } +/* + Atomically reset a given timer after copying its state into the timer pointed + to by 'old'. +*/ + +void sb_timer_checkpoint(sb_timer_t *t, sb_timer_t *old) +{ + ck_spinlock_lock(&t->lock); + + memcpy(old, t, sizeof(*old)); + ck_spinlock_init(&old->lock); + + sb_timer_reset(t); + + ck_spinlock_unlock(&t->lock); +} + /* get average time per event */ diff --git a/src/sb_timer.h b/src/sb_timer.h index f8daafd..037f8cf 100644 --- a/src/sb_timer.h +++ b/src/sb_timer.h @@ -42,6 +42,7 @@ #include #include "sb_util.h" +#include "ck_spinlock.h" /* Convert nanoseconds to seconds and vice versa */ #define NS2SEC(nsec) ((nsec)/1000000000.) @@ -87,7 +88,10 @@ typedef struct uint64_t max_time; uint64_t sum_time; - char pad[SB_CACHELINE_PAD(sizeof(struct timespec)*2 + sizeof(uint64_t)*5)]; + ck_spinlock_t lock; + + char pad[SB_CACHELINE_PAD(sizeof(struct timespec)*2 + sizeof(uint64_t)*5 + + sizeof(ck_spinlock_t))]; } sb_timer_t; @@ -105,12 +109,18 @@ bool sb_timer_running(sb_timer_t *t); /* start timer */ static inline void sb_timer_start(sb_timer_t *t) { + ck_spinlock_lock(&t->lock); + SB_GETTIME(&t->time_start); + + ck_spinlock_unlock(&t->lock); } /* stop timer */ static inline uint64_t sb_timer_stop(sb_timer_t *t) { + ck_spinlock_lock(&t->lock); + SB_GETTIME(&t->time_end); uint64_t elapsed = TIMESPEC_DIFF(t->time_end, t->time_start) + t->queue_time; @@ -123,6 +133,8 @@ static inline uint64_t sb_timer_stop(sb_timer_t *t) if (SB_UNLIKELY(elapsed > t->max_time)) t->max_time = elapsed; + ck_spinlock_unlock(&t->lock); + return elapsed; } @@ -146,7 +158,13 @@ void sb_timer_copy(sb_timer_t *to, sb_timer_t *from); specified timer without stopping it. The first call returns time elapsed since the timer was started. */ -uint64_t sb_timer_checkpoint(sb_timer_t *t); +uint64_t sb_timer_current(sb_timer_t *t); + +/* + Atomically reset a given timer after copying its state into the timer pointed + to by 'old'. +*/ +void sb_timer_checkpoint(sb_timer_t *t, sb_timer_t *old); /* get average time per event */ uint64_t sb_timer_avg(sb_timer_t *); diff --git a/src/sysbench.c b/src/sysbench.c index afc3c35..ff52eb4 100644 --- a/src/sysbench.c +++ b/src/sysbench.c @@ -147,9 +147,6 @@ static int eventgen_thread_created; /* per-thread timers for response time stats */ static sb_timer_t *timers; -/* Mutex protecting timers. */ -static pthread_mutex_t timers_mutex; - /* Temporary copy of timers for checkpoint reports */ static sb_timer_t *timers_copy; @@ -230,7 +227,7 @@ static void report_intermediate(void) MS2SEC(sb_histogram_get_pct_intermediate(&sb_latency_histogram, sb_globals.percentile)); - stat.time_interval = NS2SEC(sb_timer_checkpoint(&sb_intermediate_timer)); + stat.time_interval = NS2SEC(sb_timer_current(&sb_intermediate_timer)); if (sb_globals.tx_rate > 0) { @@ -375,16 +372,9 @@ static void report_cumulative(void) const unsigned nthreads = sb_globals.threads; - /* Create a temporary copy of timers and reset them */ - if (sb_globals.n_checkpoints > 0) - pthread_mutex_lock(&timers_mutex); - - memcpy(timers_copy, timers, nthreads * sizeof(sb_timer_t)); + /* Atomically reset each timer after copying into its timers_copy slot */ for (i = 0; i < nthreads; i++) - sb_timer_reset(&timers[i]); - - if (sb_globals.n_checkpoints > 0) - pthread_mutex_unlock(&timers_mutex); + sb_timer_checkpoint(&timers[i], &timers_copy[i]); /* Aggregate temporary timers copy */ for(i = 0; i < nthreads; i++) @@ -396,7 +386,7 @@ static void report_cumulative(void) stat.latency_avg = NS2SEC(sb_timer_avg(&t)); stat.latency_sum = NS2SEC(sb_timer_sum(&t)); - stat.time_interval = NS2SEC(sb_timer_checkpoint(&sb_checkpoint_timer)); + stat.time_interval = NS2SEC(sb_timer_current(&sb_checkpoint_timer)); if (current_test && current_test->ops.report_cumulative) current_test->ops.report_cumulative(&stat); @@ -773,15 +763,7 @@ sb_event_t sb_next_event(sb_test_t *test, int thread_id) void sb_event_start(int thread_id) { - sb_timer_t *timer = &timers[thread_id]; - - if (sb_globals.n_checkpoints > 0) - pthread_mutex_lock(&timers_mutex); - - sb_timer_start(timer); - - if (sb_globals.n_checkpoints > 0) - pthread_mutex_unlock(&timers_mutex); + sb_timer_start(&timers[thread_id]); } @@ -790,14 +772,8 @@ void sb_event_stop(int thread_id) sb_timer_t *timer = &timers[thread_id]; long long value; - if (sb_globals.n_checkpoints > 0) - pthread_mutex_lock(&timers_mutex); - value = sb_timer_stop(timer); - if (sb_globals.n_checkpoints > 0) - pthread_mutex_unlock(&timers_mutex); - if (sb_globals.percentile > 0) sb_histogram_update(&sb_latency_histogram, NS2MS(value)); @@ -1416,9 +1392,6 @@ static int init(void) for (unsigned i = 0; i < sb_globals.threads; i++) sb_timer_init(&timers[i]); - if (sb_globals.n_checkpoints > 0) - pthread_mutex_init(&timers_mutex, NULL); - return 0; } @@ -1602,9 +1575,6 @@ end: free(sb_globals.argv); - if (sb_globals.n_checkpoints > 0) - pthread_mutex_destroy(&timers_mutex); - return rc; }