From 2cdd46e2a20707fa59a1ab98c1263b0850a34de9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Thu, 17 Mar 2016 14:53:18 +0300 Subject: [PATCH 1/4] Fixes #22: Timers and reporting thread should wait for worker thread to be initialized A barrier is now used by worker and background threads and the main thread to make sure all threads have initialized before executing events. If some threads fail to initialize within a timeout (hard-coded to 30 seconds for now), bail out with an error message. --- sysbench/Makefile.am | 2 +- sysbench/sb_barrier.c | 96 +++++++++++++++++++++ sysbench/sb_barrier.h | 57 +++++++++++++ sysbench/sysbench.c | 190 +++++++++++++++++++++++++++--------------- 4 files changed, 275 insertions(+), 70 deletions(-) create mode 100644 sysbench/sb_barrier.c create mode 100644 sysbench/sb_barrier.h diff --git a/sysbench/Makefile.am b/sysbench/Makefile.am index 6e30194..4d3099f 100644 --- a/sysbench/Makefile.am +++ b/sysbench/Makefile.am @@ -49,7 +49,7 @@ endif sysbench_SOURCES = sysbench.c sysbench.h sb_timer.c sb_timer.h \ sb_options.c sb_options.h sb_logger.c sb_logger.h sb_list.h db_driver.h \ -db_driver.c sb_percentile.c sb_percentile.h +db_driver.c sb_percentile.c sb_percentile.h sb_barrier.c sb_barrier.h sysbench_LDADD = tests/fileio/libsbfileio.a tests/threads/libsbthreads.a \ tests/memory/libsbmemory.a tests/cpu/libsbcpu.a \ diff --git a/sysbench/sb_barrier.c b/sysbench/sb_barrier.c new file mode 100644 index 0000000..eb8088e --- /dev/null +++ b/sysbench/sb_barrier.c @@ -0,0 +1,96 @@ +/* + Copyright (C) 2016 Alexey Kopytov + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + Thread barrier implementation. It differs from pthread_barrier_t in two ways: + + - it's more portable (will also work on OS X and Windows with existing + pthread_* wrappers in sb_win.c). + + - it allows defining a callback function which is called right before + signaling the participating threads to continue, i.e. as soon as the + required number of threads reach the barrier. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sb_barrier.h" + +int sb_barrier_init(sb_barrier_t *barrier, unsigned int count, + sb_barrier_cb_t callback, void *arg) +{ + if (count == 0) + return 1; + + if (pthread_mutex_init(&barrier->mutex, NULL) || + pthread_cond_init(&barrier->cond, NULL)) + return 1; + + barrier->init_count = count; + barrier->count = count; + barrier->callback = callback; + barrier->arg = arg; + barrier->serial = 0; + + return 0; +} + + +int sb_barrier_wait(sb_barrier_t *barrier) +{ + int res; + + pthread_mutex_lock(&barrier->mutex); + + if (!--barrier->count) + { + barrier->serial++; + barrier->count = barrier->init_count; + + res = SB_BARRIER_SERIAL_THREAD; + + pthread_cond_broadcast(&barrier->cond); + + if (barrier->callback != NULL && barrier->callback(barrier->arg) != 0) + res = -1; + + pthread_mutex_unlock(&barrier->mutex); + + } else { + unsigned int serial = barrier->serial; + + do { + pthread_cond_wait(&barrier->cond, &barrier->mutex); + } while (serial == barrier->serial); + + pthread_mutex_unlock(&barrier->mutex); + + res = 0; + } + + return res; +} + + +void sb_barrier_destroy(sb_barrier_t *barrier) +{ + pthread_mutex_destroy(&barrier->mutex); + pthread_cond_destroy(&barrier->cond); +} diff --git a/sysbench/sb_barrier.h b/sysbench/sb_barrier.h new file mode 100644 index 0000000..a8107e6 --- /dev/null +++ b/sysbench/sb_barrier.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2016 Alexey Kopytov + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Thread barrier implementation. */ + +#ifndef SB_BARRIER_H +#define SB_BARRIER_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_PTHREAD_H +# include +#endif + +#ifdef _WIN32 +#include "sb_win.h" +#endif + +#define SB_BARRIER_SERIAL_THREAD 1 + +typedef int (*sb_barrier_cb_t)(void *); + +typedef struct { + unsigned int count; + unsigned int init_count; + unsigned int serial; + pthread_mutex_t mutex; + pthread_cond_t cond; + sb_barrier_cb_t callback; + void *arg; +} sb_barrier_t; + +int sb_barrier_init(sb_barrier_t *barrier, unsigned int count, + sb_barrier_cb_t callback, void *arg); + +int sb_barrier_wait(sb_barrier_t *barrier); + +void sb_barrier_destroy(sb_barrier_t *barrier); + +#endif /* SB_BARRIER_H */ diff --git a/sysbench/sysbench.c b/sysbench/sysbench.c index c008037..46b9fae 100644 --- a/sysbench/sysbench.c +++ b/sysbench/sysbench.c @@ -68,6 +68,7 @@ #include "sb_options.h" #include "scripting/sb_script.h" #include "db_driver.h" +#include "sb_barrier.h" #define VERSION_STRING PACKAGE" "PACKAGE_VERSION @@ -77,6 +78,9 @@ /* Maximum queue length for the tx-rate mode */ #define MAX_QUEUE_LEN 100000 +/* Wait at most this number of seconds for worker threads to initialize */ +#define THREAD_INIT_TIMEOUT 30 + /* Random numbers distributions */ typedef enum { @@ -163,10 +167,11 @@ sb_list_t tests; sb_globals_t sb_globals; sb_test_t *current_test; +/* Barrier to ensure we start the benchmark run when all workers are ready */ +static sb_barrier_t thread_start_barrier; + /* Mutexes */ -/* used to start test with all threads ready */ -static pthread_mutex_t thread_start_mutex; static pthread_attr_t thread_attr; /* structures to handle queue of events, needed for tx_rate mode */ @@ -182,26 +187,38 @@ static void print_usage(void); static void print_run_mode(sb_test_t *); #ifdef HAVE_ALARM -static void sigalrm_handler(int sig) +static void sigalrm_thread_init_timeout_handler(int sig) { - if (sig == SIGALRM) - { - sb_globals.forced_shutdown_in_progress = 1; + if (sig != SIGALRM) + return; - sb_timer_stop(&sb_globals.exec_timer); - sb_timer_stop(&sb_globals.cumulative_timer1); - sb_timer_stop(&sb_globals.cumulative_timer2); + log_text(LOG_FATAL, + "Worker threads failed to initialize within %u seconds!", + THREAD_INIT_TIMEOUT); - log_text(LOG_FATAL, - "The --max-time limit has expired, forcing shutdown..."); + exit(2); +} - if (current_test && current_test->ops.print_stats) - current_test->ops.print_stats(SB_STAT_CUMULATIVE); +static void sigalrm_forced_shutdown_handler(int sig) +{ + if (sig != SIGALRM) + return; - log_done(); + sb_globals.forced_shutdown_in_progress = 1; - exit(2); - } + sb_timer_stop(&sb_globals.exec_timer); + sb_timer_stop(&sb_globals.cumulative_timer1); + sb_timer_stop(&sb_globals.cumulative_timer2); + + log_text(LOG_FATAL, + "The --max-time limit has expired, forcing shutdown..."); + + if (current_test && current_test->ops.print_stats) + current_test->ops.print_stats(SB_STAT_CUMULATIVE); + + log_done(); + + exit(2); } #endif @@ -456,10 +473,10 @@ void print_run_mode(sb_test_t *test) } -/* Main runner test thread */ +/* Main worker test thread */ -static void *runner_thread(void *arg) +static void *worker_thread(void *arg) { sb_request_t request; sb_thread_ctxt_t *ctxt; @@ -473,20 +490,19 @@ static void *runner_thread(void *arg) test = ctxt->test; thread_id = ctxt->id; - log_text(LOG_DEBUG, "Runner thread started (%d)!", thread_id); if (test->ops.thread_init != NULL && test->ops.thread_init(thread_id) != 0) { + log_text(LOG_DEBUG, "Worker thread (#%d) failed to initialize!", thread_id); sb_globals.error = 1; - return NULL; /* thread initialization failed */ + /* Avoid blocking the main thread */ + sb_barrier_wait(&thread_start_barrier); + return NULL; } - /* - We do this to make sure all threads get to this barrier - about the same time - */ - pthread_mutex_lock(&thread_start_mutex); - sb_globals.num_running++; - pthread_mutex_unlock(&thread_start_mutex); + log_text(LOG_DEBUG, "Worker thread (#%d) started!", thread_id); + + /* Wait for other threads to initialize */ + sb_barrier_wait(&thread_start_barrier); do { @@ -551,11 +567,7 @@ static void *runner_thread(void *arg) if (test->ops.thread_done != NULL) test->ops.thread_done(thread_id); - pthread_mutex_lock(&thread_start_mutex); - sb_globals.num_running--; - pthread_mutex_unlock(&thread_start_mutex); - - return NULL; + return NULL; } static void *eventgen_thread_proc(void *arg) @@ -573,8 +585,8 @@ static void *eventgen_thread_proc(void *arg) log_text(LOG_DEBUG, "Event generating thread started"); - pthread_mutex_lock(&thread_start_mutex); - pthread_mutex_unlock(&thread_start_mutex); + /* Wait for other threads to initialize */ + sb_barrier_wait(&thread_start_barrier); curr_ns = sb_timer_value(&sb_globals.exec_timer); /* emulate exponential distribution with Lambda = tx_rate */ @@ -637,6 +649,11 @@ static void *report_thread_proc(void *arg) (void)arg; /* unused */ + log_text(LOG_DEBUG, "Reporting thread started"); + + /* Wait for other threads to initialize */ + sb_barrier_wait(&thread_start_barrier); + if (current_test->ops.print_stats == NULL) { log_text(LOG_DEBUG, "Reporting not supported by the current test, ", @@ -644,11 +661,6 @@ static void *report_thread_proc(void *arg) return NULL; } - log_text(LOG_DEBUG, "Reporting thread started"); - - pthread_mutex_lock(&thread_start_mutex); - pthread_mutex_unlock(&thread_start_mutex); - pause_ns = interval_ns; prev_ns = sb_timer_value(&sb_globals.exec_timer) + interval_ns; for (;;) @@ -686,18 +698,18 @@ static void *checkpoints_thread_proc(void *arg) (void)arg; /* unused */ + log_text(LOG_DEBUG, "Checkpoints report thread started"); + + /* Wait for other threads to initialize */ + sb_barrier_wait(&thread_start_barrier); + if (current_test->ops.print_stats == NULL) { log_text(LOG_DEBUG, "Reporting not supported by the current test, ", - "terminating the reporting thread"); + "terminating the checkpoints thread"); return NULL; } - log_text(LOG_DEBUG, "Checkpoints report thread started"); - - pthread_mutex_lock(&thread_start_mutex); - pthread_mutex_unlock(&thread_start_mutex); - for (i = 0; i < sb_globals.n_checkpoints; i++) { next_ns = SEC2NS(sb_globals.checkpoints[i]); @@ -723,11 +735,29 @@ static void *checkpoints_thread_proc(void *arg) return NULL; } -/* - Main test function. Start threads. - Wait for them to complete and measure time -*/ +/* Callback to start timers when all threads are ready */ +static int threads_started_callback(void *arg) +{ + (void) arg; /* unused */ + + /* Report initialization errors to the main thread */ + if (sb_globals.error) + return 1; + + sb_globals.num_running = sb_globals.num_threads; + + sb_timer_start(&sb_globals.exec_timer); + sb_timer_start(&sb_globals.cumulative_timer1); + sb_timer_start(&sb_globals.cumulative_timer2); + + return 0; +} + +/* + Main test function. Start threads. + Wait for them to complete and measure time +*/ static int run_test(sb_test_t *test) { @@ -739,6 +769,7 @@ static int run_test(sb_test_t *test) int report_thread_created = 0; int checkpoints_thread_created = 0; int eventgen_thread_created = 0; + unsigned int barrier_threads; /* initialize test */ if (test->ops.init != NULL && test->ops.init() != 0) @@ -769,9 +800,6 @@ static int run_test(sb_test_t *test) sb_globals.event_queue_length = 0; queue_is_full = 0; - /* start mutex used for barrier */ - pthread_mutex_init(&thread_start_mutex,NULL); - pthread_mutex_lock(&thread_start_mutex); sb_globals.num_running = 0; /* initialize attr */ @@ -791,6 +819,19 @@ static int run_test(sb_test_t *test) pthread_mutex_init(&rnd_mutex, NULL); pthread_mutex_init(&report_interval_mutex, NULL); + /* Calculate the required number of threads for the start barrier */ + barrier_threads = 1 + sb_globals.num_threads + + (sb_globals.report_interval > 0) + + (sb_globals.tx_rate > 0) + + (sb_globals.n_checkpoints > 0); + + /* Initialize the start barrier */ + if (sb_barrier_init(&thread_start_barrier, barrier_threads, + threads_started_callback, NULL)) { + log_errno(LOG_FATAL, "sb_barrier_init() failed"); + return 1; + } + if (sb_globals.report_interval > 0) { /* Create a thread for intermediate statistic reports */ @@ -827,36 +868,52 @@ static int run_test(sb_test_t *test) checkpoints_thread_created = 1; } - /* Starting the test threads */ + /* Starting the worker threads */ for(i = 0; i < sb_globals.num_threads; i++) { - if (sb_globals.error) - return 1; if ((err = pthread_create(&(threads[i].thread), &thread_attr, - &runner_thread, (void*)(threads + i))) != 0) + &worker_thread, (void*)(threads + i))) != 0) { log_errno(LOG_FATAL, "pthread_create() for thread #%d failed.", i); return 1; } } - sb_timer_start(&sb_globals.exec_timer); /* Start benchmark timer */ - sb_timer_start(&sb_globals.cumulative_timer1); - sb_timer_start(&sb_globals.cumulative_timer2); +#ifdef HAVE_ALARM + /* Exit with an error if thread initialization timeout expires */ + signal(SIGALRM, sigalrm_thread_init_timeout_handler); + + alarm(THREAD_INIT_TIMEOUT); +#endif + + log_text(LOG_NOTICE, "Initializing worker threads...\n"); + + if (sb_barrier_wait(&thread_start_barrier) < 0) + { + log_text(LOG_FATAL, "Thread initialization failed!"); + return 1; + } #ifdef HAVE_ALARM - /* Set the alarm to force shutdown */ + alarm(0); + if (sb_globals.force_shutdown) + { + /* Set the alarm to force shutdown */ + signal(SIGALRM, sigalrm_forced_shutdown_handler); + alarm(sb_globals.max_time + sb_globals.timeout); + } #endif - - pthread_mutex_unlock(&thread_start_mutex); - - log_text(LOG_NOTICE, "Threads started!\n"); + + log_text(LOG_NOTICE, "Threads started!\n"); + for(i = 0; i < sb_globals.num_threads; i++) { if((err = pthread_join(threads[i].thread, NULL)) != 0) log_errno(LOG_FATAL, "pthread_join() for thread #%d failed.", i); + + sb_globals.num_running--; } sb_timer_stop(&sb_globals.exec_timer); @@ -886,8 +943,6 @@ static int run_test(sb_test_t *test) pthread_mutex_destroy(&sb_globals.exec_mutex); - pthread_mutex_destroy(&thread_start_mutex); - /* finalize test */ if (test->ops.done != NULL) (*(test->ops.done))(); @@ -1213,9 +1268,6 @@ int main(int argc, char *argv[]) /* 'run' command */ current_test = test; -#ifdef HAVE_ALARM - signal(SIGALRM, sigalrm_handler); -#endif if (run_test(test)) exit(1); From 1b5e5619cc84d047ced14f442fc05f4cc4172396 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Fri, 18 Mar 2016 00:17:36 +0300 Subject: [PATCH 2/4] Fix barrier error reporting. --- sysbench/sb_barrier.c | 16 ++++++++++++---- sysbench/sb_barrier.h | 1 + sysbench/scripting/script_lua.c | 2 +- sysbench/sysbench.c | 12 ++++++++---- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/sysbench/sb_barrier.c b/sysbench/sb_barrier.c index eb8088e..893eb13 100644 --- a/sysbench/sb_barrier.c +++ b/sysbench/sb_barrier.c @@ -24,7 +24,9 @@ - it allows defining a callback function which is called right before signaling the participating threads to continue, i.e. as soon as the - required number of threads reach the barrier. + required number of threads reach the barrier. The callback can also signal + an error to sb_barrier_wait() callers by returning a non-zero value. In + which case sb_barrier_wait() returns a negative value to all callers. */ #ifdef HAVE_CONFIG_H @@ -48,6 +50,7 @@ int sb_barrier_init(sb_barrier_t *barrier, unsigned int count, barrier->callback = callback; barrier->arg = arg; barrier->serial = 0; + barrier->error = 0; return 0; } @@ -69,20 +72,25 @@ int sb_barrier_wait(sb_barrier_t *barrier) pthread_cond_broadcast(&barrier->cond); if (barrier->callback != NULL && barrier->callback(barrier->arg) != 0) + { + barrier->error = 1; res = -1; + } pthread_mutex_unlock(&barrier->mutex); - } else { + } + else + { unsigned int serial = barrier->serial; do { pthread_cond_wait(&barrier->cond, &barrier->mutex); } while (serial == barrier->serial); - pthread_mutex_unlock(&barrier->mutex); + res = barrier->error ? -1 : 0; - res = 0; + pthread_mutex_unlock(&barrier->mutex); } return res; diff --git a/sysbench/sb_barrier.h b/sysbench/sb_barrier.h index a8107e6..1e9b09c 100644 --- a/sysbench/sb_barrier.h +++ b/sysbench/sb_barrier.h @@ -45,6 +45,7 @@ typedef struct { pthread_cond_t cond; sb_barrier_cb_t callback; void *arg; + int error; } sb_barrier_t; int sb_barrier_init(sb_barrier_t *barrier, unsigned int count, diff --git a/sysbench/scripting/script_lua.c b/sysbench/scripting/script_lua.c index 31a1aab..410eda8 100644 --- a/sysbench/scripting/script_lua.c +++ b/sysbench/scripting/script_lua.c @@ -40,7 +40,7 @@ #define CALL_ERROR(L, name) \ do { \ const char *err = lua_tostring(L, -1); \ - log_text(LOG_DEBUG, "failed to execute function `%s': %s", \ + log_text(LOG_FATAL, "failed to execute function `%s': %s", \ name, err ? err : "(null)"); \ } while (0) diff --git a/sysbench/sysbench.c b/sysbench/sysbench.c index 46b9fae..7f7ad74 100644 --- a/sysbench/sysbench.c +++ b/sysbench/sysbench.c @@ -502,7 +502,8 @@ static void *worker_thread(void *arg) log_text(LOG_DEBUG, "Worker thread (#%d) started!", thread_id); /* Wait for other threads to initialize */ - sb_barrier_wait(&thread_start_barrier); + if (sb_barrier_wait(&thread_start_barrier) < 0) + return NULL; do { @@ -586,7 +587,8 @@ static void *eventgen_thread_proc(void *arg) log_text(LOG_DEBUG, "Event generating thread started"); /* Wait for other threads to initialize */ - sb_barrier_wait(&thread_start_barrier); + if (sb_barrier_wait(&thread_start_barrier) < 0) + return NULL; curr_ns = sb_timer_value(&sb_globals.exec_timer); /* emulate exponential distribution with Lambda = tx_rate */ @@ -652,7 +654,8 @@ static void *report_thread_proc(void *arg) log_text(LOG_DEBUG, "Reporting thread started"); /* Wait for other threads to initialize */ - sb_barrier_wait(&thread_start_barrier); + if (sb_barrier_wait(&thread_start_barrier) < 0) + return NULL; if (current_test->ops.print_stats == NULL) { @@ -701,7 +704,8 @@ static void *checkpoints_thread_proc(void *arg) log_text(LOG_DEBUG, "Checkpoints report thread started"); /* Wait for other threads to initialize */ - sb_barrier_wait(&thread_start_barrier); + if (sb_barrier_wait(&thread_start_barrier) < 0) + return NULL; if (current_test->ops.print_stats == NULL) { From 57e62669b937b3c4ebaca237af65d69539bfb260 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Fri, 18 Mar 2016 12:50:41 +0300 Subject: [PATCH 3/4] Fixes #25: Include database-related command line options in help Call db_print_help() from print_help() + some cosmetic help changes. --- sysbench/sb_logger.c | 4 +++- sysbench/sb_logger.h | 2 +- sysbench/sysbench.c | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/sysbench/sb_logger.c b/sysbench/sb_logger.c index d2d7df1..59d0af6 100644 --- a/sysbench/sb_logger.c +++ b/sysbench/sb_logger.c @@ -142,12 +142,14 @@ int log_register(void) /* Display command line options for registered log handlers */ -void log_usage(void) +void log_print_help(void) { unsigned int i; sb_list_item_t *pos; log_handler_t *handler; + printf("Log options:\n"); + for (i = 0; i < LOG_MSG_TYPE_MAX; i++) { SB_LIST_FOR_EACH(pos, handlers + i) diff --git a/sysbench/sb_logger.h b/sysbench/sb_logger.h index 6cf267a..eec2ac4 100644 --- a/sysbench/sb_logger.h +++ b/sysbench/sb_logger.h @@ -128,7 +128,7 @@ int log_register(void); /* Display command line options for all register log handlers */ -void log_usage(void); +void log_print_help(void); /* Initialize logger */ diff --git a/sysbench/sysbench.c b/sysbench/sysbench.c index 7f7ad74..0c1e5a7 100644 --- a/sysbench/sysbench.c +++ b/sysbench/sysbench.c @@ -183,7 +183,7 @@ static event_queue_elem_t queue_array[MAX_QUEUE_LEN]; static int queue_is_full; static void print_header(void); -static void print_usage(void); +static void print_help(void); static void print_run_mode(sb_test_t *); #ifdef HAVE_ALARM @@ -289,19 +289,20 @@ void print_header(void) /* Print program usage */ -void print_usage(void) +void print_help(void) { sb_list_item_t *pos; sb_test_t *test; printf("Usage:\n"); - printf(" sysbench [general-options]... --test= " - "[test-options]... command\n\n"); + printf(" sysbench --test= [options]... \n\n"); + printf("Commands: prepare run cleanup help version\n\n"); printf("General options:\n"); sb_print_options(general_args); - printf("Log options:\n"); - log_usage(); + log_print_help(); + + db_print_help(); printf("Compiled-in tests:\n"); SB_LIST_FOR_EACH(pos, &tests) @@ -310,7 +311,6 @@ void print_usage(void) printf(" %s - %s\n", test->sname, test->lname); } printf("\n"); - printf("Commands: prepare run cleanup help version\n\n"); printf("See 'sysbench --test= help' for a list of options for each test.\n\n"); } @@ -1177,7 +1177,7 @@ int main(int argc, char *argv[]) /* Parse command line arguments */ if (parse_arguments(argc,argv)) { - print_usage(); + print_help(); exit(1); } @@ -1190,7 +1190,7 @@ int main(int argc, char *argv[]) if (sb_globals.command == SB_COMMAND_NULL) { fprintf(stderr, "Missing required command argument.\n"); - print_usage(); + print_help(); exit(1); } @@ -1214,7 +1214,7 @@ int main(int argc, char *argv[]) if (sb_globals.command == SB_COMMAND_HELP) { if (test == NULL) - print_usage(); + print_help(); else { if (test->args != NULL) @@ -1234,7 +1234,7 @@ int main(int argc, char *argv[]) if (testname == NULL) { fprintf(stderr, "Missing required argument: --test.\n"); - print_usage(); + print_help(); exit(1); } From 26d5046cc96d6199393a75ccad4451da2f4c69b1 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Tue, 22 Mar 2016 21:09:41 +0300 Subject: [PATCH 4/4] Fixes #29: FATAL: Failed to read file! file: 24 pos: 14516224 errno = 0 (Success) Fail when test files do not exist for `sysbench --test=fileio run`, i.e. when they have not been prepared with `sysbench prepare`. --- sysbench/tests/fileio/sb_fileio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sysbench/tests/fileio/sb_fileio.c b/sysbench/tests/fileio/sb_fileio.c index a7a1a57..7c750d5 100644 --- a/sysbench/tests/fileio/sb_fileio.c +++ b/sysbench/tests/fileio/sb_fileio.c @@ -361,7 +361,7 @@ int file_prepare(void) files[i] = sb_open(file_name); if (!VALID_FILE(files[i])) { - log_errno(LOG_FATAL, "Cannot open file"); + log_errno(LOG_FATAL, "Cannot open file '%s'", file_name); return 1; } } @@ -2057,11 +2057,10 @@ static FILE_DESCRIPTOR sb_open(const char *name) return SB_INVALID_FILE; #ifndef _WIN32 - file = open(name, O_CREAT | O_RDWR | flags, - S_IRUSR | S_IWUSR); + file = open(name, O_RDWR | flags, S_IRUSR | S_IWUSR); #else - file = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_ALWAYS, flags, NULL); + file = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + flags, NULL); #endif #ifdef HAVE_DIRECTIO