]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.1.0/test_and_benchmark/benchmark/src/main.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.1.0 / test_and_benchmark / benchmark / src / main.c
1 /***** includes *****/
2 #include "internal.h"
3
4 /***** structs *****/
5 struct operations_to_perform
6 {
7   char
8     *gnuplot_system_string;
9
10   enum flag
11     benchmark_duration_flag,
12     gnuplot_file_flag,
13     gnuplot_logarithmic_yaxis_flag,
14     gnuplot_png_flag,
15     gnuplot_height_flag,
16     gnuplot_width_flag,
17     run_flag,
18     show_cpu_topology_only_flag,
19     show_error_flag,
20     show_help_flag,
21     show_version_flag,
22     memory_flag;
23
24   lfds710_pal_uint_t
25     memory_in_megabytes,
26     benchmark_duration_in_seconds,
27     gnuplot_height_in_pixels,
28     gnuplot_width_in_pixels;
29 };
30
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 );
35
36
37
38
39
40 /****************************************************************************/
41 int main( int argc, char **argv )
42 {
43   struct operations_to_perform
44     otp;
45
46   assert( argc >= 1 );
47   assert( argv != NULL );
48
49   convert_command_line_args_to_operations_to_perform( argc, argv, &otp );
50
51   perform_operations( &otp );
52
53   return EXIT_SUCCESS;
54 }
55
56
57
58
59
60 /****************************************************************************/
61 static void convert_command_line_args_to_operations_to_perform( int argc, char **argv, struct operations_to_perform *otp )
62 {
63   int
64     rv;
65
66   struct util_cmdline_state
67     cs;
68
69   union util_cmdline_arg_data
70     *arg_data;
71
72   assert( argc >= 1 );
73   assert( argv != NULL );
74   assert( otp != NULL );
75
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;
88
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
93            to initialize it
94   */
95
96   otp->memory_in_megabytes = BENCHMARK_DEFAULT_MEMORY_IN_MEGABYTES;
97
98   util_cmdline_init( &cs );
99
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 );
111
112   rv = util_cmdline_process_args( &cs, argc, argv );
113
114   if( rv == 0 )
115     otp->show_error_flag = RAISED;
116   
117   if( rv == 1 )
118   {
119     util_cmdline_get_arg_data( &cs, 'g', &arg_data );
120     if( arg_data != NULL )
121     {
122       otp->gnuplot_file_flag = RAISED;
123       otp->gnuplot_system_string = arg_data->string.string;
124     }
125
126     util_cmdline_get_arg_data( &cs, 'h', &arg_data );
127     if( arg_data != NULL )
128       otp->show_help_flag = RAISED;
129
130     util_cmdline_get_arg_data( &cs, 'l', &arg_data );
131     if( arg_data != NULL )
132       otp->gnuplot_logarithmic_yaxis_flag = RAISED;
133
134     util_cmdline_get_arg_data( &cs, 'm', &arg_data );
135     if( arg_data != NULL )
136     {
137       if( arg_data->integer.integer < 2 )
138       {
139         puts( "Memory (in megabytes) needs to be 2 or greater." );
140         exit( EXIT_FAILURE );
141       }
142
143       otp->memory_in_megabytes = (lfds710_pal_uint_t) arg_data->integer.integer;
144       otp->memory_flag = RAISED;
145     }
146
147     util_cmdline_get_arg_data( &cs, 'p', &arg_data );
148     if( arg_data != NULL )
149     {
150       otp->gnuplot_png_flag = RAISED;
151
152       // TRD : if -p, -g must be present
153       util_cmdline_get_arg_data( &cs, 'g', &arg_data );
154       if( arg_data == NULL )
155       {
156         puts( "If -p is given, -g must also be given." );
157         exit( EXIT_FAILURE );
158       }
159     }
160
161     util_cmdline_get_arg_data( &cs, 'r', &arg_data );
162     if( arg_data != NULL )
163     {
164       otp->show_help_flag = LOWERED;
165       otp->run_flag = RAISED;
166     }
167
168     util_cmdline_get_arg_data( &cs, 's', &arg_data );
169     if( arg_data != NULL )
170     {
171       if( arg_data->integer.integer < 1 )
172       {
173         puts( "Duration in seconds needs to be 1 or greater." );
174         exit( EXIT_FAILURE );
175       }
176
177       otp->benchmark_duration_in_seconds = (lfds710_pal_uint_t) arg_data->integer.integer;
178       otp->benchmark_duration_flag = RAISED;
179     }
180
181     util_cmdline_get_arg_data( &cs, 't', &arg_data );
182     if( arg_data != NULL )
183     {
184       otp->show_help_flag = LOWERED;
185       otp->show_cpu_topology_only_flag = RAISED;
186     }
187
188     util_cmdline_get_arg_data( &cs, 'v', &arg_data );
189     if( arg_data != NULL )
190     {
191       otp->show_help_flag = LOWERED;
192       otp->show_version_flag = RAISED;
193     }
194
195     util_cmdline_get_arg_data( &cs, 'x', &arg_data );
196     if( arg_data != NULL )
197     {
198       if( arg_data->integer.integer < 1 )
199       {
200         puts( "Gnuplot width in pixels needs to be 1 or greater." );
201         exit( EXIT_FAILURE );
202       }
203
204       otp->gnuplot_width_in_pixels = (lfds710_pal_uint_t) arg_data->integer.integer;
205       otp->gnuplot_width_flag = RAISED;
206     }
207
208     util_cmdline_get_arg_data( &cs, 'y', &arg_data );
209     if( arg_data != NULL )
210     {
211       if( arg_data->integer.integer < 1 )
212       {
213         puts( "Gnuplot height in pixels needs to be 1 or greater." );
214         exit( EXIT_FAILURE );
215       }
216
217       otp->gnuplot_height_in_pixels = (lfds710_pal_uint_t) arg_data->integer.integer;
218       otp->gnuplot_height_flag = RAISED;
219     }
220   }
221
222   util_cmdline_cleanup( &cs );
223
224   return;
225 }
226
227
228
229
230
231 /****************************************************************************/
232 static void perform_operations( struct operations_to_perform *otp )
233 {
234   assert( otp != NULL );
235
236   if( otp->show_error_flag == RAISED )
237   {
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" );
240
241     return;
242   }
243
244   if( otp->show_help_flag == RAISED )
245   {
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 );
262
263     #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_SMP )
264     {
265       printf( "\n"
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"
269               "\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"
276               "\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" );
280     }
281     #endif
282
283     return;
284   }
285
286   if( otp->show_cpu_topology_only_flag == RAISED )
287   {
288     char
289       *topology_string;
290
291     struct libshared_memory_state
292       ms;
293
294     struct libbenchmark_topology_state
295       ts;
296
297     void
298       *store;
299
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 );
308     free( store );
309
310     return;
311   }
312
313   if( otp->run_flag == RAISED )
314   {
315     char
316       diskbuffer[BUFSIZ];
317
318     enum libbenchmark_topology_numa_mode
319       numa_mode = LIBBENCHMARK_TOPOLOGY_NUMA_MODE_SMP;
320
321     FILE
322       *diskfile;
323
324     lfds710_pal_uint_t
325       options_bitmask = NO_FLAGS,
326       size_in_bytes;
327
328     struct lfds710_list_asu_element
329       *lasue = NULL;
330
331     struct lfds710_list_asu_state
332       list_of_gnuplots;
333
334     struct libbenchmark_benchmarkset_gnuplot
335       *bg;
336
337     struct libbenchmark_benchmarksuite_state
338       bss;
339
340     struct libshared_memory_state
341       ms_for_benchmarks,
342       ms_for_rs_and_ts;
343
344     struct libbenchmark_topology_state
345       ts;
346
347     struct libbenchmark_results_state
348       rs;
349
350     void
351       *store;
352
353     // TRD : for the liblfds700 benchmarks
354     lfds700_misc_library_init_valid_on_current_logical_core();
355
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 );
361
362     libshared_memory_init( &ms_for_benchmarks );
363
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 );
369     #endif
370
371     #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_NUMA )
372     {
373       lfds710_pal_uint_t
374         numa_node_id,
375         number_numa_nodes;
376
377       struct libbenchmark_topology_iterate_state
378         tis;
379
380       struct libbenchmark_topology_node_state
381         *tns;
382
383       numa_mode = LIBBENCHMARK_TOPOLOGY_NUMA_MODE_NUMA;
384
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 );
386
387       libbenchmark_topology_iterate_init( &tis, LIBBENCHMARK_TOPOLOGY_NODE_TYPE_NUMA );
388
389       while( libbenchmark_topology_iterate(&ts, &tis, &tns) )
390       {
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 );
395       }
396     }
397     #endif
398
399     if( otp->benchmark_duration_flag == RAISED )
400       options_bitmask |= LIBBENCHMARK_BENCHMARKSUITE_OPTION_DURATION;
401
402     libbenchmark_benchmarksuite_init( &bss, &ts, &ms_for_benchmarks, numa_mode, options_bitmask, otp->benchmark_duration_in_seconds );
403
404     libbenchmark_results_init( &rs, &ms_for_rs_and_ts );
405
406     libbenchmark_benchmarksuite_run( &bss, &rs );
407
408     if( otp->gnuplot_file_flag == RAISED or otp->gnuplot_png_flag == RAISED )
409     {
410       char
411         system_command[1024];
412
413       struct libbenchmark_gnuplot_options
414         gpo;
415
416       LIBBENCHMARK_GNUPLOT_OPTIONS_INIT( gpo );
417
418       if( otp->gnuplot_logarithmic_yaxis_flag == RAISED )
419         LIBBENCHMARK_GNUPLOT_OPTIONS_SET_Y_AXIS_SCALE_TYPE_LOGARITHMIC( gpo );
420
421       if( otp->gnuplot_height_flag == RAISED )
422         LIBBENCHMARK_GNUPLOT_OPTIONS_SET_HEIGHT_IN_PIXELS( gpo, otp->gnuplot_height_in_pixels );
423
424       if( otp->gnuplot_width_flag == RAISED )
425         LIBBENCHMARK_GNUPLOT_OPTIONS_SET_WIDTH_IN_PIXELS( gpo, otp->gnuplot_width_in_pixels );
426
427       libbenchmark_benchmarksuite_get_list_of_gnuplot_strings( &bss, &rs, otp->gnuplot_system_string, &gpo, &list_of_gnuplots );
428
429       // TRD : write the gnuplot strings to disk
430       while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(list_of_gnuplots,lasue) )
431       {
432         bg = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
433
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 );
438         fclose( diskfile );
439
440         if( otp->gnuplot_png_flag == RAISED )
441         {
442           sprintf( system_command, "gnuplot \"%s\"", bg->filename );
443           system( system_command );
444         }
445       }
446     }
447
448     libbenchmark_results_cleanup( &rs );
449
450     libbenchmark_benchmarksuite_cleanup( &bss );
451
452     libshared_memory_cleanup( &ms_for_benchmarks, memory_cleanup_callback );
453
454     libshared_memory_cleanup( &ms_for_rs_and_ts, memory_cleanup_callback );
455
456     lfds700_misc_library_cleanup();
457   }
458
459   if( otp->show_version_flag == RAISED )
460     internal_show_version();
461
462   return;
463 }
464
465
466
467
468
469 /****************************************************************************/
470 #pragma warning( disable : 4100 )
471
472 static void memory_cleanup_callback( enum flag known_numa_node_flag, void *store, lfds710_pal_uint_t size_in_bytes )
473 {
474   assert( store != NULL );
475   // TRD : size_in_bytes can be any value in its range
476
477   #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_SMP )
478     free( store );
479   #endif
480
481   #if( BENCHMARK_PAL_MEMORY_TYPE == BENCHMARK_MEMORY_TYPE_NUMA )
482     benchmark_pal_numa_free( store, size_in_bytes );
483   #endif
484
485   return;
486 }
487
488 #pragma warning( default : 4100 )
489