5 struct operations_to_perform
8 *gnuplot_system_string;
11 benchmark_duration_flag,
13 gnuplot_logarithmic_yaxis_flag,
18 show_cpu_topology_only_flag,
26 benchmark_duration_in_seconds,
27 gnuplot_height_in_pixels,
28 gnuplot_width_in_pixels;
31 /***** prototypes *****/
32 static void convert_command_line_args_to_operations_to_perform( int argc, char **argv, struct operations_to_perform *otp );
33 static void perform_operations( struct operations_to_perform *otp );
34 static void memory_cleanup_callback( enum flag known_numa_node_flag, void *store, lfds710_pal_uint_t size_in_bytes );
40 /****************************************************************************/
41 int main( int argc, char **argv )
43 struct operations_to_perform
47 assert( argv != NULL );
49 convert_command_line_args_to_operations_to_perform( argc, argv, &otp );
51 perform_operations( &otp );
60 /****************************************************************************/
61 static void convert_command_line_args_to_operations_to_perform( int argc, char **argv, struct operations_to_perform *otp )
66 struct util_cmdline_state
69 union util_cmdline_arg_data
73 assert( argv != NULL );
74 assert( otp != NULL );
76 otp->benchmark_duration_flag = LOWERED;
77 otp->gnuplot_file_flag = LOWERED;
78 otp->gnuplot_logarithmic_yaxis_flag = LOWERED;
79 otp->gnuplot_png_flag = LOWERED;
80 otp->gnuplot_height_flag = LOWERED;
81 otp->gnuplot_width_flag = LOWERED;
82 otp->run_flag = LOWERED;
83 otp->show_cpu_topology_only_flag = LOWERED;
84 otp->show_error_flag = LOWERED;
85 otp->show_help_flag = RAISED;
86 otp->show_version_flag = LOWERED;
87 otp->memory_flag = LOWERED;
89 /* TRD : the numeric options are used by libbenchmark
90 if we pass in a bitmark indicating they are set
91 however, we ourselves use otp->memory_in_megabytes
92 when we alloc for printing topology, so we need
96 otp->memory_in_megabytes = BENCHMARK_DEFAULT_MEMORY_IN_MEGABYTES;
98 util_cmdline_init( &cs );
100 util_cmdline_add_arg( &cs, 'g', UTIL_CMDLINE_ARG_TYPE_STRING );
101 util_cmdline_add_arg( &cs, 'h', UTIL_CMDLINE_ARG_TYPE_FLAG );
102 util_cmdline_add_arg( &cs, 'l', UTIL_CMDLINE_ARG_TYPE_FLAG );
103 util_cmdline_add_arg( &cs, 'm', UTIL_CMDLINE_ARG_TYPE_INTEGER );
104 util_cmdline_add_arg( &cs, 'p', UTIL_CMDLINE_ARG_TYPE_FLAG );
105 util_cmdline_add_arg( &cs, 'r', UTIL_CMDLINE_ARG_TYPE_FLAG );
106 util_cmdline_add_arg( &cs, 's', UTIL_CMDLINE_ARG_TYPE_INTEGER );
107 util_cmdline_add_arg( &cs, 't', UTIL_CMDLINE_ARG_TYPE_FLAG );
108 util_cmdline_add_arg( &cs, 'v', UTIL_CMDLINE_ARG_TYPE_FLAG );
109 util_cmdline_add_arg( &cs, 'x', UTIL_CMDLINE_ARG_TYPE_INTEGER );
110 util_cmdline_add_arg( &cs, 'y', UTIL_CMDLINE_ARG_TYPE_INTEGER );
112 rv = util_cmdline_process_args( &cs, argc, argv );
115 otp->show_error_flag = RAISED;
119 util_cmdline_get_arg_data( &cs, 'g', &arg_data );
120 if( arg_data != NULL )
122 otp->gnuplot_file_flag = RAISED;
123 otp->gnuplot_system_string = arg_data->string.string;
126 util_cmdline_get_arg_data( &cs, 'h', &arg_data );
127 if( arg_data != NULL )
128 otp->show_help_flag = RAISED;
130 util_cmdline_get_arg_data( &cs, 'l', &arg_data );
131 if( arg_data != NULL )
132 otp->gnuplot_logarithmic_yaxis_flag = RAISED;
134 util_cmdline_get_arg_data( &cs, 'm', &arg_data );
135 if( arg_data != NULL )
137 if( arg_data->integer.integer < 2 )
139 puts( "Memory (in megabytes) needs to be 2 or greater." );
140 exit( EXIT_FAILURE );
143 otp->memory_in_megabytes = (lfds710_pal_uint_t) arg_data->integer.integer;
144 otp->memory_flag = RAISED;
147 util_cmdline_get_arg_data( &cs, 'p', &arg_data );
148 if( arg_data != NULL )
150 otp->gnuplot_png_flag = RAISED;
152 // TRD : if -p, -g must be present
153 util_cmdline_get_arg_data( &cs, 'g', &arg_data );
154 if( arg_data == NULL )
156 puts( "If -p is given, -g must also be given." );
157 exit( EXIT_FAILURE );
161 util_cmdline_get_arg_data( &cs, 'r', &arg_data );
162 if( arg_data != NULL )
164 otp->show_help_flag = LOWERED;
165 otp->run_flag = RAISED;
168 util_cmdline_get_arg_data( &cs, 's', &arg_data );
169 if( arg_data != NULL )
171 if( arg_data->integer.integer < 1 )
173 puts( "Duration in seconds needs to be 1 or greater." );
174 exit( EXIT_FAILURE );
177 otp->benchmark_duration_in_seconds = (lfds710_pal_uint_t) arg_data->integer.integer;
178 otp->benchmark_duration_flag = RAISED;
181 util_cmdline_get_arg_data( &cs, 't', &arg_data );
182 if( arg_data != NULL )
184 otp->show_help_flag = LOWERED;
185 otp->show_cpu_topology_only_flag = RAISED;
188 util_cmdline_get_arg_data( &cs, 'v', &arg_data );
189 if( arg_data != NULL )
191 otp->show_help_flag = LOWERED;
192 otp->show_version_flag = RAISED;
195 util_cmdline_get_arg_data( &cs, 'x', &arg_data );
196 if( arg_data != NULL )
198 if( arg_data->integer.integer < 1 )
200 puts( "Gnuplot width in pixels needs to be 1 or greater." );
201 exit( EXIT_FAILURE );
204 otp->gnuplot_width_in_pixels = (lfds710_pal_uint_t) arg_data->integer.integer;
205 otp->gnuplot_width_flag = RAISED;
208 util_cmdline_get_arg_data( &cs, 'y', &arg_data );
209 if( arg_data != NULL )
211 if( arg_data->integer.integer < 1 )
213 puts( "Gnuplot height in pixels needs to be 1 or greater." );
214 exit( EXIT_FAILURE );
217 otp->gnuplot_height_in_pixels = (lfds710_pal_uint_t) arg_data->integer.integer;
218 otp->gnuplot_height_flag = RAISED;
222 util_cmdline_cleanup( &cs );
231 /****************************************************************************/
232 static void perform_operations( struct operations_to_perform *otp )
234 assert( otp != NULL );
236 if( otp->show_error_flag == RAISED )
238 printf( "\nInvalid arguments. Sorry - it's a simple parser, so no clues.\n"
239 "-h or run with no args to see the help text.\n" );
244 if( otp->show_help_flag == RAISED )
246 printf( "benchmark -g [s] -h -l -m [n] -p -r -s [n] -t -v -x [n] -y [n]\n"
247 " -g [s] : emit gnuplots, where [s] is an arbitrary string (in quotes if spaces) describing the system\n"
248 " -h : help (this text you're reading now)\n"
249 " -l : logarithmic gnuplot y-axis (normally linear)\n"
250 " -m [n] : alloc [n] mb RAM for benchmarks, default is %u (minimum 2 (two))\n"
251 " (user specifies RAM as libbenchmark performs no allocs - rather it is handed a block of memory\n"
252 " on NUMA systems, each node allocates an equal fraction of the total - benchmark knows about\n"
253 " NUMA and does the right things, including NUMA and non-NUMA versions of the benchmarks)\n"
254 " -p : call gnuplot to emit PNGs (requires -g and gnuplot must be on the path)\n"
255 " -r : run (causes benchmarks to run; present so no args gives help)\n"
256 " -s [n] : individual benchmark duration in integer seconds (min 1, duh)\n"
257 " -t : show CPU topology, uses -m (or its default) for amount of RAM to alloc\n"
258 " -v : build and version info\n"
259 " -x [n] : gnuplot width in pixels (in case the computed values are no good)\n"
260 " -y [n] : gnuplot height in pixels (in case the computed values are no good)\n",
261 (int unsigned) BENCHMARK_DEFAULT_MEMORY_IN_MEGABYTES );
263 #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_SMP )
266 "WARNING : This is the SMP build of benchmark. Do not use it on a NUMA\n"
267 " system as the results will be wrong - and not a bit wrong, but\n"
268 " VERY VERY WRONG.\n"
270 " The benchmarks measure the performance of liblfds, but to do so,\n"
271 " themselves have work to do, which involves what can be many\n"
272 " memory accesses, and so threads running on the primary NUMA node\n"
273 " have no penalty for say twenty memory accesses, whereas threads\n"
274 " off the primary NUMA node are paying the penalty for all of them,\n"
275 " when maybe only five of those accesses are actually by liblfds.\n"
277 " As a result, SMP builds on NUMA systems make off-primary-node\n"
278 " threads look MUCH worse than they actually are, because you think\n"
279 " they're only measuring liblfds, when in fact they're not.\n" );
286 if( otp->show_cpu_topology_only_flag == RAISED )
291 struct libshared_memory_state
294 struct libbenchmark_topology_state
300 libshared_memory_init( &ms );
301 store = malloc( otp->memory_in_megabytes * ONE_MEGABYTE_IN_BYTES );
302 libshared_memory_add_memory( &ms, store, otp->memory_in_megabytes * ONE_MEGABYTE_IN_BYTES );
303 libbenchmark_topology_init( &ts, &ms );
304 topology_string = libbenchmark_topology_generate_string( &ts, &ms, LIBBENCHMARK_TOPOLOGY_STRING_FORMAT_STDOUT );
305 printf( "%s", topology_string );
306 libbenchmark_topology_cleanup( &ts );
307 libshared_memory_cleanup( &ms, NULL );
313 if( otp->run_flag == RAISED )
318 enum libbenchmark_topology_numa_mode
319 numa_mode = LIBBENCHMARK_TOPOLOGY_NUMA_MODE_SMP;
325 options_bitmask = NO_FLAGS,
328 struct lfds710_list_asu_element
331 struct lfds710_list_asu_state
334 struct libbenchmark_benchmarkset_gnuplot
337 struct libbenchmark_benchmarksuite_state
340 struct libshared_memory_state
344 struct libbenchmark_topology_state
347 struct libbenchmark_results_state
353 // TRD : for the liblfds700 benchmarks
354 lfds700_misc_library_init_valid_on_current_logical_core();
356 libshared_memory_init( &ms_for_rs_and_ts );
357 size_in_bytes = (otp->memory_in_megabytes / 2) * ONE_MEGABYTE_IN_BYTES;
358 store = malloc( size_in_bytes );
359 libshared_memory_add_memory( &ms_for_rs_and_ts, store, size_in_bytes );
360 libbenchmark_topology_init( &ts, &ms_for_rs_and_ts );
362 libshared_memory_init( &ms_for_benchmarks );
364 #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_SMP )
365 numa_mode = LIBBENCHMARK_TOPOLOGY_NUMA_MODE_SMP;
366 size_in_bytes = (otp->memory_in_megabytes / 2) * ONE_MEGABYTE_IN_BYTES;
367 store = malloc( size_in_bytes );
368 libshared_memory_add_memory( &ms_for_benchmarks, store, size_in_bytes );
371 #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_NUMA )
377 struct libbenchmark_topology_iterate_state
380 struct libbenchmark_topology_node_state
383 numa_mode = LIBBENCHMARK_TOPOLOGY_NUMA_MODE_NUMA;
385 libbenchmark_topology_query( &ts, LIBBENCHMARK_TOPOLOGY_QUERY_GET_NUMBER_OF_NODE_TYPE, (void *) (lfds710_pal_uint_t) LIBBENCHMARK_TOPOLOGY_NODE_TYPE_NUMA, (void *) &number_numa_nodes );
387 libbenchmark_topology_iterate_init( &tis, LIBBENCHMARK_TOPOLOGY_NODE_TYPE_NUMA );
389 while( libbenchmark_topology_iterate(&ts, &tis, &tns) )
391 numa_node_id = LIBBENCHMARK_TOPOLOGY_NODE_GET_NUMA_ID( *tns );
392 size_in_bytes = ( (otp->memory_in_megabytes / 2) * ONE_MEGABYTE_IN_BYTES ) / number_numa_nodes;
393 store = benchmark_pal_numa_malloc( (int) numa_node_id, size_in_bytes );
394 libshared_memory_add_memory_from_numa_node( &ms_for_benchmarks, numa_node_id, store, size_in_bytes );
399 if( otp->benchmark_duration_flag == RAISED )
400 options_bitmask |= LIBBENCHMARK_BENCHMARKSUITE_OPTION_DURATION;
402 libbenchmark_benchmarksuite_init( &bss, &ts, &ms_for_benchmarks, numa_mode, options_bitmask, otp->benchmark_duration_in_seconds );
404 libbenchmark_results_init( &rs, &ms_for_rs_and_ts );
406 libbenchmark_benchmarksuite_run( &bss, &rs );
408 if( otp->gnuplot_file_flag == RAISED or otp->gnuplot_png_flag == RAISED )
411 system_command[1024];
413 struct libbenchmark_gnuplot_options
416 LIBBENCHMARK_GNUPLOT_OPTIONS_INIT( gpo );
418 if( otp->gnuplot_logarithmic_yaxis_flag == RAISED )
419 LIBBENCHMARK_GNUPLOT_OPTIONS_SET_Y_AXIS_SCALE_TYPE_LOGARITHMIC( gpo );
421 if( otp->gnuplot_height_flag == RAISED )
422 LIBBENCHMARK_GNUPLOT_OPTIONS_SET_HEIGHT_IN_PIXELS( gpo, otp->gnuplot_height_in_pixels );
424 if( otp->gnuplot_width_flag == RAISED )
425 LIBBENCHMARK_GNUPLOT_OPTIONS_SET_WIDTH_IN_PIXELS( gpo, otp->gnuplot_width_in_pixels );
427 libbenchmark_benchmarksuite_get_list_of_gnuplot_strings( &bss, &rs, otp->gnuplot_system_string, &gpo, &list_of_gnuplots );
429 // TRD : write the gnuplot strings to disk
430 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(list_of_gnuplots,lasue) )
432 bg = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
434 diskfile = fopen( bg->filename, "w" );
435 setbuf( diskfile, diskbuffer );
436 // TRD : standard only requires fprintf() to support up to 509 characters of output
437 fwrite( bg->gnuplot_string, libshared_ansi_strlen(bg->gnuplot_string), 1, diskfile );
440 if( otp->gnuplot_png_flag == RAISED )
442 sprintf( system_command, "gnuplot \"%s\"", bg->filename );
443 system( system_command );
448 libbenchmark_results_cleanup( &rs );
450 libbenchmark_benchmarksuite_cleanup( &bss );
452 libshared_memory_cleanup( &ms_for_benchmarks, memory_cleanup_callback );
454 libshared_memory_cleanup( &ms_for_rs_and_ts, memory_cleanup_callback );
456 lfds700_misc_library_cleanup();
459 if( otp->show_version_flag == RAISED )
460 internal_show_version();
469 /****************************************************************************/
470 #pragma warning( disable : 4100 )
472 static void memory_cleanup_callback( enum flag known_numa_node_flag, void *store, lfds710_pal_uint_t size_in_bytes )
474 assert( store != NULL );
475 // TRD : size_in_bytes can be any value in its range
477 #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_SMP )
481 #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_NUMA )
482 benchmark_pal_numa_free( store, size_in_bytes );
488 #pragma warning( default : 4100 )