diff options
Diffstat (limited to 'modules/benchmark.c')
-rw-r--r-- | modules/benchmark.c | 440 |
1 files changed, 208 insertions, 232 deletions
diff --git a/modules/benchmark.c b/modules/benchmark.c index 857904a8..26de9557 100644 --- a/modules/benchmark.c +++ b/modules/benchmark.c @@ -32,48 +32,130 @@ #include "benchmark/bench_results.c" -void scan_fft(gboolean reload); -void scan_raytr(gboolean reload); -void scan_bfsh(gboolean reload); -void scan_cryptohash(gboolean reload); -void scan_fib(gboolean reload); -void scan_nqueens(gboolean reload); -void scan_zlib(gboolean reload); -void scan_gui(gboolean reload); - -gchar *callback_fft(); -gchar *callback_raytr(); -gchar *callback_bfsh(); -gchar *callback_fib(); -gchar *callback_cryptohash(); -gchar *callback_nqueens(); -gchar *callback_zlib(); -gchar *callback_gui(); - -static ModuleEntry entries[] = { - {N_("CPU Blowfish"), "blowfish.png", callback_bfsh, scan_bfsh, MODULE_FLAG_NONE}, - {N_("CPU CryptoHash"), "cryptohash.png", callback_cryptohash, scan_cryptohash, MODULE_FLAG_NONE}, - {N_("CPU Fibonacci"), "nautilus.png", callback_fib, scan_fib, MODULE_FLAG_NONE}, - {N_("CPU N-Queens"), "nqueens.png", callback_nqueens, scan_nqueens, MODULE_FLAG_NONE}, - {N_("CPU Zlib"), "file-roller.png", callback_zlib, scan_zlib, MODULE_FLAG_NONE}, - {N_("FPU FFT"), "fft.png", callback_fft, scan_fft, MODULE_FLAG_NONE}, - {N_("FPU Raytracing"), "raytrace.png", callback_raytr, scan_raytr, MODULE_FLAG_NONE}, -#if !GTK_CHECK_VERSION(3,0,0) - {N_("GPU Drawing"), "module.png", callback_gui, scan_gui, MODULE_FLAG_NO_REMOTE}, -#endif - {NULL} -}; +bench_value bench_results[BENCHMARK_N_ENTRIES]; + +static void do_benchmark(void (*benchmark_function)(void), int entry); +static gchar *benchmark_include_results_reverse(bench_value result, const gchar * benchmark); +static gchar *benchmark_include_results(bench_value result, const gchar * benchmark); + +/* ModuleEntry entries, scan_*(), callback_*(), etc. */ +#include "benchmark/benches.c" static gboolean sending_benchmark_results = FALSE; +char *bench_value_to_str(bench_value r) { + return g_strdup_printf("%lf; %lf; %d", r.result, r.elapsed_time, r.threads_used); +} + +bench_value bench_value_from_str(const char* str) { + bench_value ret = EMPTY_BENCH_VALUE; + double r, e; + int t, c; + if (str) { + c = sscanf(str, "%lf; %lf; %d", &r, &e, &t); + if (c >= 3) { + ret.result = r; + ret.elapsed_time = e; + ret.threads_used = t; + } + } + return ret; +} + typedef struct _ParallelBenchTask ParallelBenchTask; struct _ParallelBenchTask { gint thread_number; guint start, end; gpointer data, callback; + int *stop; }; +static gpointer benchmark_crunch_for_dispatcher(gpointer data) +{ + ParallelBenchTask *pbt = (ParallelBenchTask *)data; + gpointer (*callback)(void *data, gint thread_number); + gpointer return_value = g_malloc(sizeof(int)); + int count = 0; + + if ((callback = pbt->callback)) { + while(!*pbt->stop) { + callback(pbt->data, pbt->thread_number); + /* don't count if didn't finish in time */ + if (!*pbt->stop) + count++; + } + } else { + DEBUG("this is thread %p; callback is NULL and it should't be!", g_thread_self()); + } + + g_free(pbt); + + *(double*)return_value = (double)count; + return return_value; +} + +bench_value benchmark_crunch_for(float seconds, gint n_threads, + gpointer callback, gpointer callback_data) { + int cpu_procs, cpu_cores, cpu_threads, thread_number, stop = 0; + GSList *threads = NULL, *t; + GTimer *timer; + bench_value ret = EMPTY_BENCH_VALUE; + + timer = g_timer_new(); + + cpu_procs_cores_threads(&cpu_procs, &cpu_cores, &cpu_threads); + if (n_threads > 0) + ret.threads_used = n_threads; + else if (n_threads < 0) + ret.threads_used = cpu_cores; + else + ret.threads_used = cpu_threads; + + g_timer_start(timer); + for (thread_number = 0; thread_number < ret.threads_used; thread_number++) { + ParallelBenchTask *pbt = g_new0(ParallelBenchTask, 1); + GThread *thread; + + DEBUG("launching thread %d", thread_number); + + pbt->thread_number = thread_number; + pbt->data = callback_data; + pbt->callback = callback; + pbt->stop = &stop; + + thread = g_thread_new("dispatcher", + (GThreadFunc)benchmark_crunch_for_dispatcher, pbt); + threads = g_slist_prepend(threads, thread); + + DEBUG("thread %d launched as context %p", thread_number, thread); + } + + /* wait for time */ + //while ( g_timer_elapsed(timer, NULL) < seconds ) { } + g_usleep(seconds * 1000000); + + /* signal all threads to stop */ + stop = 1; + g_timer_stop(timer); + + ret.result = 0; + DEBUG("waiting for all threads to finish"); + for (t = threads; t; t = t->next) { + DEBUG("waiting for thread with context %p", t->data); + gpointer *rv = g_thread_join((GThread *)t->data); + ret.result += *(double*)rv; + g_free(rv); + } + + ret.elapsed_time = g_timer_elapsed(timer, NULL); + + g_slist_free(threads); + g_timer_destroy(timer); + + return ret; +} + static gpointer benchmark_parallel_for_dispatcher(gpointer data) { ParallelBenchTask *pbt = (ParallelBenchTask *)data; @@ -94,50 +176,73 @@ static gpointer benchmark_parallel_for_dispatcher(gpointer data) return return_value; } -gdouble benchmark_parallel_for(guint start, guint end, +/* one call for each thread to be used */ +bench_value benchmark_parallel(gint n_threads, gpointer callback, gpointer callback_data) { + int cpu_procs, cpu_cores, cpu_threads; + cpu_procs_cores_threads(&cpu_procs, &cpu_cores, &cpu_threads); + if (n_threads == 0) n_threads = cpu_threads; + else if (n_threads == -1) n_threads = cpu_cores; + return benchmark_parallel_for(n_threads, 0, n_threads, callback, callback_data); +} + +/* Note: + * benchmark_parallel_for(): element [start] included, but [end] is excluded. + * callback(): expected to processes elements [start] through [end] inclusive. + */ +bench_value benchmark_parallel_for(gint n_threads, guint start, guint end, gpointer callback, gpointer callback_data) { gchar *temp; - guint n_cores, iter_per_core, iter, thread_number = 0; - gdouble elapsed_time; + int cpu_procs, cpu_cores, cpu_threads; + guint iter_per_thread, iter, thread_number = 0; GSList *threads = NULL, *t; GTimer *timer; + bench_value ret = EMPTY_BENCH_VALUE; + timer = g_timer_new(); - temp = module_call_method("devices::getProcessorCount"); - n_cores = temp ? atoi(temp) : 1; - g_free(temp); + cpu_procs_cores_threads(&cpu_procs, &cpu_cores, &cpu_threads); - while (n_cores > 0) { - iter_per_core = (end - start) / n_cores; + if (n_threads > 0) + ret.threads_used = n_threads; + else if (n_threads < 0) + ret.threads_used = cpu_cores; + else + ret.threads_used = cpu_threads; - if (iter_per_core == 0) { - DEBUG("not enough items per core; disabling one"); - n_cores--; + while (ret.threads_used > 0) { + iter_per_thread = (end - start) / ret.threads_used; + + if (iter_per_thread == 0) { + DEBUG("not enough items per thread; disabling one thread"); + ret.threads_used--; } else { break; } } - DEBUG("processor has %d cores; processing %d elements (%d per core)", - n_cores, (end - start), iter_per_core); + DEBUG("Using %d threads across %d logical processors; processing %d elements (%d per thread)", + ret.threads_used, cpu_threads, (end - start), iter_per_thread); g_timer_start(timer); - for (iter = start; iter < end; iter += iter_per_core) { + for (iter = start; iter < end; ) { ParallelBenchTask *pbt = g_new0(ParallelBenchTask, 1); GThread *thread; - DEBUG("launching thread %d", 1 + (iter / iter_per_core)); + guint ts = iter, te = iter + iter_per_thread; + /* add the remainder of items/iter_per_thread to the last thread */ + if (end - te < iter_per_thread) + te = end; + iter = te; + + DEBUG("launching thread %d", 1 + thread_number); pbt->thread_number = thread_number++; - pbt->start = iter == 0 ? 0 : iter; - pbt->end = iter + iter_per_core - 1; + pbt->start = ts; + pbt->end = te - 1; pbt->data = callback_data; pbt->callback = callback; - if (pbt->end > end) - pbt->end = end; - thread = g_thread_new("dispatcher", (GThreadFunc)benchmark_parallel_for_dispatcher, pbt); threads = g_slist_prepend(threads, thread); @@ -148,18 +253,23 @@ gdouble benchmark_parallel_for(guint start, guint end, DEBUG("waiting for all threads to finish"); for (t = threads; t; t = t->next) { DEBUG("waiting for thread with context %p", t->data); - g_thread_join((GThread *)t->data); + gpointer *rv = g_thread_join((GThread *)t->data); + if (rv) { + if (ret.result == -1.0) ret.result = 0; + ret.result += *(double*)rv; + } + g_free(rv); } g_timer_stop(timer); - elapsed_time = g_timer_elapsed(timer, NULL); + ret.elapsed_time = g_timer_elapsed(timer, NULL); g_slist_free(threads); g_timer_destroy(timer); - DEBUG("finishing; all threads took %f seconds to finish", elapsed_time); + DEBUG("finishing; all threads took %f seconds to finish", ret.elapsed_time); - return elapsed_time; + return ret; } static gchar *clean_cpuname(gchar *cpuname) @@ -212,7 +322,7 @@ static void br_mi_add(char **results_list, bench_result *b, gboolean select) { *results_list = h_strdup_cprintf("$%s%s$%s=%.2f|%s\n", *results_list, select ? "*" : "", rkey, ckey, - b->result, b->machine->cpu_config); + b->bvalue.result, b->machine->cpu_config); moreinfo_add_with_prefix("BENCH", rkey, bench_result_more_info(b) ); @@ -220,7 +330,7 @@ static void br_mi_add(char **results_list, bench_result *b, gboolean select) { g_free(rkey); } -static gchar *__benchmark_include_results(gdouble result, +static gchar *__benchmark_include_results(bench_value r, const gchar * benchmark, ShellOrderType order_type) { @@ -232,12 +342,8 @@ static gchar *__benchmark_include_results(gdouble result, moreinfo_del_with_prefix("BENCH"); - if (result > 0.0) { - temp = module_call_method("devices::getProcessorCount"); - n_threads = temp ? atoi(temp) : 1; - g_free(temp); temp = NULL; - - b = bench_result_this_machine(benchmark, result, n_threads); + if (r.result > 0.0) { + b = bench_result_this_machine(benchmark, r); br_mi_add(&results, b, 1); temp = bench_result_benchmarkconf_line(b); @@ -292,76 +398,20 @@ static gchar *__benchmark_include_results(gdouble result, return return_value; } - - -static gchar *benchmark_include_results_reverse(gdouble result, - const gchar * benchmark) +static gchar *benchmark_include_results_reverse(bench_value result, const gchar * benchmark) { - return __benchmark_include_results(result, benchmark, - SHELL_ORDER_DESCENDING); + return __benchmark_include_results(result, benchmark, SHELL_ORDER_DESCENDING); } -static gchar *benchmark_include_results(gdouble result, - const gchar * benchmark) +static gchar *benchmark_include_results(bench_value result, const gchar * benchmark) { - return __benchmark_include_results(result, benchmark, - SHELL_ORDER_ASCENDING); -} - -gdouble bench_results[BENCHMARK_N_ENTRIES]; - -gchar *callback_gui() -{ - return benchmark_include_results_reverse(bench_results[BENCHMARK_GUI], - "GPU Drawing"); -} - -gchar *callback_fft() -{ - return benchmark_include_results(bench_results[BENCHMARK_FFT], - "FPU FFT"); -} - -gchar *callback_nqueens() -{ - return benchmark_include_results(bench_results[BENCHMARK_NQUEENS], - "CPU N-Queens"); -} - -gchar *callback_raytr() -{ - return benchmark_include_results(bench_results[BENCHMARK_RAYTRACE], - "FPU Raytracing"); -} - -gchar *callback_bfsh() -{ - return benchmark_include_results(bench_results[BENCHMARK_BLOWFISH], - "CPU Blowfish"); -} - -gchar *callback_cryptohash() -{ - return benchmark_include_results_reverse(bench_results[BENCHMARK_CRYPTOHASH], - "CPU CryptoHash"); -} - -gchar *callback_fib() -{ - return benchmark_include_results(bench_results[BENCHMARK_FIB], - "CPU Fibonacci"); -} - -gchar *callback_zlib() -{ - return benchmark_include_results(bench_results[BENCHMARK_ZLIB], - "CPU Zlib"); + return __benchmark_include_results(result, benchmark, SHELL_ORDER_ASCENDING); } typedef struct _BenchmarkDialog BenchmarkDialog; struct _BenchmarkDialog { GtkWidget *dialog; - double result; + bench_value r; }; static gboolean do_benchmark_handler(GIOChannel *source, @@ -371,25 +421,19 @@ static gboolean do_benchmark_handler(GIOChannel *source, BenchmarkDialog *bench_dialog = (BenchmarkDialog*)data; GIOStatus status; gchar *result; - gchar *buffer; - float float_result; + bench_value r = EMPTY_BENCH_VALUE; status = g_io_channel_read_line(source, &result, NULL, NULL, NULL); if (status != G_IO_STATUS_NORMAL) { DEBUG("error while reading benchmark result"); - - bench_dialog->result = -1.0f; + r.result = -1.0f; + bench_dialog->r = r; gtk_widget_destroy(bench_dialog->dialog); return FALSE; } - float_result = strtof(result, &buffer); - if (buffer == result) { - DEBUG("error while converting floating point value"); - bench_dialog->result = -1.0f; - } else { - bench_dialog->result = float_result; - } + r = bench_value_from_str(result); + bench_dialog->r = r; gtk_widget_destroy(bench_dialog->dialog); g_free(result); @@ -412,6 +456,9 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) GSpawnFlags spawn_flags = G_SPAWN_STDERR_TO_DEV_NULL; gchar *bench_status; + bench_value r = EMPTY_BENCH_VALUE; + bench_results[entry] = r; + bench_status = g_strdup_printf(_("Benchmarking: <b>%s</b>."), entries[entry].name); shell_view_set_enabled(FALSE); @@ -427,7 +474,7 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) GtkWidget *content_area; GtkWidget *hbox; GtkWidget *label; - + bench_dialog = gtk_dialog_new_with_buttons("", NULL, GTK_DIALOG_MODAL, @@ -442,14 +489,13 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) gtk_box_pack_end(GTK_BOX(hbox), label, TRUE, TRUE, 5); gtk_container_add(GTK_CONTAINER (content_area), hbox); gtk_widget_show_all(bench_dialog); -#else +#else bench_dialog = gtk_message_dialog_new(GTK_WINDOW(shell_get_main_shell()->window), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, _("Benchmarking. Please do not move your mouse " \ "or press any keys.")); - g_object_set_data(G_OBJECT(bench_dialog), "result", "0.0"); gtk_dialog_add_buttons(GTK_DIALOG(bench_dialog), _("Cancel"), GTK_RESPONSE_ACCEPT, NULL); gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(bench_dialog), bench_image); @@ -461,7 +507,7 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) benchmark_dialog = g_new0(BenchmarkDialog, 1); benchmark_dialog->dialog = bench_dialog; - benchmark_dialog->result = -1.0f; + benchmark_dialog->r = r; if (!g_path_is_absolute(params.argv0)) { spawn_flags |= G_SPAWN_SEARCH_PATH; @@ -495,7 +541,7 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) kill(bench_pid, SIGINT); } - bench_results[entry] = benchmark_dialog->result; + bench_results[entry] = benchmark_dialog->r; g_io_channel_unref(channel); shell_view_set_enabled(TRUE); @@ -518,94 +564,6 @@ static void do_benchmark(void (*benchmark_function)(void), int entry) setpriority(PRIO_PROCESS, 0, old_priority); } -void scan_gui(gboolean reload) -{ - SCAN_START(); - - if (params.run_benchmark) { - int argc = 0; - - ui_init(&argc, NULL); - } - - if (params.gui_running || params.run_benchmark) { - do_benchmark(benchmark_gui, BENCHMARK_GUI); - } else { - bench_results[BENCHMARK_GUI] = 0.0f; - } - SCAN_END(); -} - -void scan_fft(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_fft, BENCHMARK_FFT); - SCAN_END(); -} - -void scan_nqueens(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_nqueens, BENCHMARK_NQUEENS); - SCAN_END(); -} - -void scan_raytr(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_raytrace, BENCHMARK_RAYTRACE); - SCAN_END(); -} - -void scan_bfsh(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_fish, BENCHMARK_BLOWFISH); - SCAN_END(); -} - -void scan_cryptohash(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_cryptohash, BENCHMARK_CRYPTOHASH); - SCAN_END(); -} - -void scan_fib(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_fib, BENCHMARK_FIB); - SCAN_END(); -} - -void scan_zlib(gboolean reload) -{ - SCAN_START(); - do_benchmark(benchmark_zlib, BENCHMARK_ZLIB); - SCAN_END(); -} - -const gchar *hi_note_func(gint entry) -{ - switch (entry) { - case BENCHMARK_CRYPTOHASH: - return _("Results in MiB/second. Higher is better."); - - case BENCHMARK_ZLIB: - case BENCHMARK_GUI: - return _("Results in HIMarks. Higher is better."); - - case BENCHMARK_FFT: - case BENCHMARK_RAYTRACE: - case BENCHMARK_BLOWFISH: - case BENCHMARK_FIB: - case BENCHMARK_NQUEENS: - return _("Results in seconds. Lower is better."); - } - - return NULL; -} - gchar *hi_module_get_name(void) { return g_strdup(_("Benchmarks")); @@ -658,7 +616,7 @@ static gchar *get_benchmark_results() if (!scan_callback) continue; - if (bench_results[i] < 0.0) { + if (bench_results[i].result < 0.0) { /* benchmark was cancelled */ scan_callback(TRUE); } else { @@ -694,7 +652,24 @@ static gchar *run_benchmark(gchar *name) if ((scan_callback = entries[i].scan_callback)) { scan_callback(FALSE); - return g_strdup_printf("%f", bench_results[i]); +#define CHK_RESULT_FORMAT(F) (params.result_format && strcmp(params.result_format, F) == 0) + + if (params.run_benchmark) { + if (CHK_RESULT_FORMAT("conf") ) { + bench_result *b = bench_result_this_machine(name, bench_results[i]); + char *temp = bench_result_benchmarkconf_line(b); + bench_result_free(b); + return temp; + } else if (CHK_RESULT_FORMAT("shell") ) { + bench_result *b = bench_result_this_machine(name, bench_results[i]); + char *temp = bench_result_more_info_complete(b); + bench_result_free(b); + return temp; + } + /* defaults to "short" which is below*/ + } + + return bench_value_to_str(bench_results[i]); } } } @@ -706,7 +681,7 @@ ShellModuleMethod *hi_exported_methods(void) { static ShellModuleMethod m[] = { {"runBenchmark", run_benchmark}, - {NULL} + {NULL} }; return m; @@ -730,9 +705,10 @@ void hi_module_init(void) sync_manager_add_entry(&se[0]); sync_manager_add_entry(&se[1]); + bench_value er = EMPTY_BENCH_VALUE; int i; for (i = 0; i < G_N_ELEMENTS(entries) - 1; i++) { - bench_results[i] = -1.0f; + bench_results[i] = er; } } |