]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.1.0/test_and_benchmark/libbenchmark/src/libbenchmark_benchmarkset/libbenchmark_benchmarkset_gnuplot.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.1.0 / test_and_benchmark / libbenchmark / src / libbenchmark_benchmarkset / libbenchmark_benchmarkset_gnuplot.c
1 /***** includes *****/
2 #include "libbenchmark_benchmarkset_internal.h"
3
4
5
6
7
8 /****************************************************************************/
9 void libbenchmark_benchmarkset_gnuplot_emit( struct libbenchmark_benchmarkset_state *bsets,
10                                              struct libbenchmark_results_state *rs,
11                                              char *gnuplot_system_string,
12                                              enum libbenchmark_topology_numa_mode numa_mode,
13                                              struct libbenchmark_gnuplot_options *gpo,
14                                              struct libbenchmark_benchmarkset_gnuplot *bg )
15 {
16   char
17     png_filename[512],
18     temp_string[64],
19     *topology_string;
20
21   char const
22     *libbenchmark_version_and_build_string,
23     *liblfds_version_and_build_string,
24     *libshared_version_and_build_string;
25
26   enum flag
27     found_flag;
28
29   int
30     rv;
31
32   lfds710_pal_uint_t
33     count,
34     greatest_digit = 0,
35     greatest_result = 0,
36     length,
37     loop,
38     longest_line_length = 0,
39     result,
40     second_greatest_digit,
41     temp_greatest_result,
42     title_line_lengths[5],
43     y_max = 0, // TRD : to remove compiler warning
44     number_logical_cores,
45     number_benchmarks,
46     number_lp_sets,
47     topology_string_length,
48     one_block_xticks,
49     one_block_plot,
50     one_block_titles,
51     one_block_numeric_data,
52     one_inner_block,
53     one_outer_block,
54     one_block,
55     total_length_in_bytes;
56
57   struct libbenchmark_benchmarkinstance_state
58     *bs;
59
60   struct lfds710_btree_au_element
61     *baue,
62     *baue_inner,
63     *baue_temp;
64
65   struct lfds710_list_asu_element
66     *lasue_benchmarks,
67     *lasue_benchmarks_outer,
68     *lasue_lpset,
69     *lasue_temp;
70
71   struct lfds710_list_aso_element
72     *lasoe,
73     *lasoe_inner;
74
75   struct lfds710_list_aso_state
76     *logical_processor_set;
77
78   struct libbenchmark_topology_node_state
79     *tns,
80     *tns_results,
81     *tns_inner = NULL; // TRD : to remove compiler warning
82
83   LFDS710_PAL_ASSERT( bsets != NULL );
84   LFDS710_PAL_ASSERT( rs != NULL );
85   LFDS710_PAL_ASSERT( gnuplot_system_string != NULL );
86   // TRD : numa_mode can be any value in its range
87   LFDS710_PAL_ASSERT( gpo != NULL );
88   LFDS710_PAL_ASSERT( bg != NULL );
89
90   bg->datastructure_id = bsets->datastructure_id;
91   bg->benchmark_id = bsets->benchmark_id;
92
93   /* TRD : so, first, we're producing a string
94            so we need to figure out how much store to allocate
95
96            roughly, length is;
97
98            topology string length
99            fixed = 4096
100            one_block_xticks = 64 + 6 * number logical cores
101            one_block_plot = 16 + 40 * number_benchmarks
102            one_block_titles = 32 * number_benchmarks
103            one_block_numeric_data = (16 + number_benchmarks) * number_benchmarks * number logical cores
104            one_inner_block = one_block_titles + one_block_numeric_data + 2
105            one_outer_block = one_block_xticks + one_block_plot
106            one_block = one_inner_block * number_benchmarks + one_outer_block
107
108            (plus one on number_lp_sets for the blank key-only chart)
109            total = topology_string_length + fixed + one_block * (number_lp_sets+1)
110   */
111
112   topology_string = libbenchmark_topology_generate_string( bsets->ts, bsets->ms, LIBBENCHMARK_TOPOLOGY_STRING_FORMAT_GNUPLOT );
113
114   libbenchmark_topology_query( bsets->ts, LIBBENCHMARK_TOPOLOGY_QUERY_GET_NUMBER_OF_NODE_TYPE, (void *) (lfds710_pal_uint_t) LIBBENCHMARK_TOPOLOGY_NODE_TYPE_LOGICAL_PROCESSOR, &number_logical_cores );
115   lfds710_list_asu_query( &bsets->benchmarks, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_benchmarks );
116   lfds710_list_asu_query( bsets->logical_processor_sets, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_lp_sets );
117
118   topology_string_length = libshared_ansi_strlen( topology_string );
119   one_block_xticks = 64 + 6 * number_logical_cores;
120   one_block_plot = 16 + 40 * number_benchmarks;
121   one_block_titles = 32 * number_benchmarks;
122   one_block_numeric_data = (16 + number_benchmarks) * number_benchmarks * number_logical_cores;
123   one_inner_block = one_block_titles + one_block_numeric_data + 2;
124   one_outer_block = one_block_xticks + one_block_plot;
125   one_block = one_inner_block * number_benchmarks + one_outer_block;
126   total_length_in_bytes = topology_string_length + 4096 + one_block * (number_lp_sets+1);
127
128   bg->gnuplot_string = libshared_memory_alloc_from_most_free_space_node( bsets->ms, total_length_in_bytes, sizeof(char) );
129
130   lfds710_misc_query( LFDS710_MISC_QUERY_GET_BUILD_AND_VERSION_STRING, NULL, (void **) &liblfds_version_and_build_string );
131   libbenchmark_misc_query( LIBBENCHMARK_MISC_QUERY_GET_BUILD_AND_VERSION_STRING, NULL, (void **) &libbenchmark_version_and_build_string );
132   libshared_misc_query( LIBSHARED_MISC_QUERY_GET_BUILD_AND_VERSION_STRING, NULL, (void **) &libshared_version_and_build_string );
133
134   libshared_ansi_strcpy( bg->filename, "liblfds" );
135   libshared_ansi_strcat_number( bg->filename, (lfds710_pal_uint_t) LFDS710_MISC_VERSION_INTEGER );
136   libshared_ansi_strcat( bg->filename, "_" );
137   libshared_ansi_strcat( bg->filename, libbenchmark_globals_datastructure_names[bsets->datastructure_id] );
138   libshared_ansi_strcat( bg->filename, "_" );
139   libshared_ansi_strcat( bg->filename, libbenchmark_globals_benchmark_names[bsets->benchmark_id] );
140   libshared_ansi_strcat( bg->filename, "_" );
141   libshared_ansi_strcat( bg->filename, libbenchmark_globals_numa_mode_names[numa_mode] );
142   libshared_ansi_strcat( bg->filename, "_" );
143   libshared_ansi_strcat( bg->filename, gnuplot_system_string );
144   libshared_ansi_strcat( bg->filename, ".gnuplot" );
145
146   libshared_ansi_strcpy( png_filename, "liblfds" );
147   libshared_ansi_strcat_number( png_filename, (lfds710_pal_uint_t) LFDS710_MISC_VERSION_INTEGER );
148   libshared_ansi_strcat( png_filename, "_" );
149   libshared_ansi_strcat( png_filename, libbenchmark_globals_datastructure_names[bsets->datastructure_id] );
150   libshared_ansi_strcat( png_filename, "_" );
151   libshared_ansi_strcat( png_filename, libbenchmark_globals_benchmark_names[bsets->benchmark_id] );
152   libshared_ansi_strcat( png_filename, "_" );
153   libshared_ansi_strcat( png_filename, libbenchmark_globals_numa_mode_names[numa_mode] );
154   libshared_ansi_strcat( png_filename, "_" );
155   libshared_ansi_strcat( png_filename, gnuplot_system_string );
156   libshared_ansi_strcat( png_filename, ".png" );
157
158   // TRD : now for main gnuplot header
159   libshared_ansi_strcpy( bg->gnuplot_string, "set output \"" );
160   libshared_ansi_strcat( bg->gnuplot_string, png_filename );
161   libshared_ansi_strcat( bg->gnuplot_string, "\"\n" );
162
163   libshared_ansi_strcat( bg->gnuplot_string, "set terminal pngcairo enhanced font \"Courier New,14\" size " );
164
165   if( gpo->width_in_pixels_set_flag == RAISED )
166     libshared_ansi_strcat_number( bg->gnuplot_string, gpo->width_in_pixels );
167
168   // TRD : 300px wide per logical core
169   if( gpo->width_in_pixels_set_flag == LOWERED )
170     libshared_ansi_strcat_number( bg->gnuplot_string, number_logical_cores * 300 );
171
172   libshared_ansi_strcat( bg->gnuplot_string, "," );
173
174   // TRD : height is 300 pixels per chart, plus 300 for the title, plus 300 for the key
175   if( gpo->height_in_pixels_set_flag == RAISED )
176     libshared_ansi_strcat_number( bg->gnuplot_string, gpo->height_in_pixels );
177
178   if( gpo->height_in_pixels_set_flag == LOWERED )
179     libshared_ansi_strcat_number( bg->gnuplot_string, (number_lp_sets+2) * 300 );
180
181   libshared_ansi_strcat( bg->gnuplot_string, "\n" );
182   libshared_ansi_strcat( bg->gnuplot_string, "set multiplot title \"" );
183
184   // TRD : compute longest line in first header part so we can know how many spaces needed for right padding on each line
185   title_line_lengths[0] = libshared_ansi_strlen( "data structure : " ) + libshared_ansi_strlen( libbenchmark_globals_datastructure_names[bsets->datastructure_id] );
186   title_line_lengths[1] = libshared_ansi_strlen( "benchmark      : " ) + libshared_ansi_strlen( libbenchmark_globals_benchmark_names[bsets->benchmark_id] );
187   title_line_lengths[2] = libshared_ansi_strlen( "numa mode      : " ) + libshared_ansi_strlen( libbenchmark_globals_numa_mode_names[numa_mode] );
188   temp_string[0] = '\0';
189   libshared_ansi_strcat_number( temp_string, libbenchmark_globals_benchmark_duration_in_seconds );
190   title_line_lengths[3] = libshared_ansi_strlen( "duration       :  seconds(s)" ) + libshared_ansi_strlen( temp_string );
191   title_line_lengths[4] = libshared_ansi_strlen( "system         : " ) + libshared_ansi_strlen( gnuplot_system_string );
192
193   for( loop = 0 ; loop < 5 ; loop++ )
194     if( title_line_lengths[loop] > longest_line_length )
195       longest_line_length = title_line_lengths[loop];
196
197   // TRD : now emit
198   libshared_ansi_strcat( bg->gnuplot_string, "data structure : " );
199   libshared_ansi_strcat( bg->gnuplot_string, libbenchmark_globals_datastructure_names[bsets->datastructure_id] );
200   for( loop = 0 ; loop < longest_line_length - title_line_lengths[0] ; loop++ )
201     libshared_ansi_strcat( bg->gnuplot_string, " " );
202   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
203
204   libshared_ansi_strcat( bg->gnuplot_string, "benchmark      : " );
205   libshared_ansi_strcat( bg->gnuplot_string, libbenchmark_globals_benchmark_names[bsets->benchmark_id] );
206   for( loop = 0 ; loop < longest_line_length - title_line_lengths[1] ; loop++ )
207     libshared_ansi_strcat( bg->gnuplot_string, " " );
208   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
209
210   libshared_ansi_strcat( bg->gnuplot_string, "numa mode      : " );
211   libshared_ansi_strcat( bg->gnuplot_string, libbenchmark_globals_numa_mode_names[numa_mode] );
212   for( loop = 0 ; loop < longest_line_length - title_line_lengths[2] ; loop++ )
213     libshared_ansi_strcat( bg->gnuplot_string, " " );
214   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
215
216   libshared_ansi_strcat( bg->gnuplot_string, "duration       : " );
217   temp_string[0] = '\0';
218   libshared_ansi_strcat_number( bg->gnuplot_string, libbenchmark_globals_benchmark_duration_in_seconds );
219   libshared_ansi_strcat( bg->gnuplot_string, " seconds(s)" );
220   for( loop = 0 ; loop < longest_line_length - title_line_lengths[3] ; loop++ )
221     libshared_ansi_strcat( bg->gnuplot_string, " " );
222   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
223
224   libshared_ansi_strcat( bg->gnuplot_string, "system         : " );
225   libshared_ansi_strcat( bg->gnuplot_string, gnuplot_system_string );
226   for( loop = 0 ; loop < longest_line_length - title_line_lengths[4] ; loop++ )
227     libshared_ansi_strcat( bg->gnuplot_string, " " );
228   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
229
230   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
231   libshared_ansi_strcat( bg->gnuplot_string, topology_string );
232   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
233
234   libshared_ansi_strcat( bg->gnuplot_string, "Y axis = ops/sec, X axis = logical cores in use\\n\\\n" );
235   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
236   libshared_ansi_strcat( bg->gnuplot_string, (char *) liblfds_version_and_build_string );
237   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
238   libshared_ansi_strcat( bg->gnuplot_string, (char *) libshared_version_and_build_string );
239   libshared_ansi_strcat( bg->gnuplot_string, "\\n\\\n" );
240   libshared_ansi_strcat( bg->gnuplot_string, (char *) libbenchmark_version_and_build_string );
241
242   libshared_ansi_strcat( bg->gnuplot_string, "\" layout " );
243   // TRD : +1 for key-only chart
244   libshared_ansi_strcat_number( bg->gnuplot_string, number_lp_sets+1 );
245   libshared_ansi_strcat( bg->gnuplot_string, ",1 rowsfirst noenhanced\n"
246                                                 "set format y \"%.0f\"\n"
247                                                 "set boxwidth 1 absolute\n"
248                                                 "set style data histograms\n"
249                                                 "set style histogram cluster\n"
250                                                 "set style histogram gap 4\n"
251                                                 "set style fill solid border -1\n"
252                                                 "set key autotitle columnheader center top\n"
253                                                 "set noxtics\n"
254                                                 "set noytics\n"
255                                                 "set noborder\n"
256                                                 "set noxlabel\n"
257                                                 "set noylabel\n" );
258
259   /* TRD : we're drawing the plot for benchmarks in one set (i.e. a single logical benchmark, but all the different lock type variants of it)
260            over all of its logical processor sets
261            so we have one chart per logical processor set
262   */
263
264   /* TRD : first, we need to compute the y range
265            this itself requires us to iterate over the result for every core in every test :-)
266   */
267
268   // TRD : loop over every logical processor set
269   lasue_lpset = NULL;
270
271   while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*bsets->logical_processor_sets,lasue_lpset) )
272   {
273     logical_processor_set = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_lpset );
274
275     // TRD : now loop over every benchmark
276     lasue_benchmarks = NULL;
277
278     while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
279     {
280       bs = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_benchmarks );
281
282       // TRD : now for this processor set, loop over every logical core
283       lasoe = NULL;
284
285       while( LFDS710_LIST_ASO_GET_START_AND_THEN_NEXT(*logical_processor_set, lasoe) )
286       {
287         tns_results = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasoe );
288
289         // TRD : now, finally, let's go shopping
290         libbenchmark_results_get_result( rs, 
291                                          bsets->datastructure_id,
292                                          bsets->benchmark_id,
293                                          bs->lock_id,
294                                          numa_mode,
295                                          logical_processor_set,
296                                          tns_results,
297                                          &result );
298
299         if( result > greatest_result )
300           greatest_result = result;
301       }
302     }
303   }
304
305   if( gpo->y_axis_scale_type == LIBBENCHMARK_GNUPLOT_Y_AXIS_SCALE_TYPE_LINEAR )
306     libshared_ansi_strcat( bg->gnuplot_string, "set yrange [0:" );
307
308   if( gpo->y_axis_scale_type == LIBBENCHMARK_GNUPLOT_Y_AXIS_SCALE_TYPE_LOGARITHMIC )
309     libshared_ansi_strcat( bg->gnuplot_string, "set logscale y\n"
310                                                "set yrange [1:" );
311
312   /* TRD : for y-range max, we look at the second greatest digit in greatest_result
313            i.e. for 3429111 the second greatest digit is 4
314            if that digit is 0 to 4, inclusive, the y-max value is that digit converted to 5, and everything to the right (smaller values to 0)
315            if that digit is 5 to 9, inclusive, the y-max value is that digit and everything to the right converted to 0, and the greatest digit increased by 1
316            I am assuming I will not exceed a 32-bit unsigned max :-)
317            if the greatest_result is a single digit, we set second_greatest_digit to greatest_digit and greatest_digit to 0, and it works properly
318   */
319
320   temp_greatest_result = greatest_result / libbenchmark_globals_benchmark_duration_in_seconds;
321   length = 0;
322
323   do
324   {
325     second_greatest_digit = greatest_digit;
326     greatest_digit = temp_greatest_result % 10;
327     length++;
328     temp_greatest_result -= greatest_digit;
329     temp_greatest_result /= 10;
330   }
331   while( temp_greatest_result > 0 );
332
333   if( length == 1 )
334   {
335     second_greatest_digit = greatest_digit;
336     greatest_digit = 0;
337   }
338
339   if( second_greatest_digit < 5 )
340     y_max = greatest_digit * 10 + 5;
341
342   if( second_greatest_digit >= 5 )
343     y_max = (greatest_digit+1) * 10;
344
345   if( length >= 2 )
346     for( loop = 0 ; loop < length-2 ; loop++ )
347       y_max *= 10;
348
349   libshared_ansi_strcat_number( bg->gnuplot_string, y_max );
350   libshared_ansi_strcat( bg->gnuplot_string, "]\n" );
351
352   // TRD : now print one empty chart which is just for the key
353
354   libshared_ansi_strcat( bg->gnuplot_string, "plot " );
355
356   lasue_benchmarks = NULL;
357   count = 1;
358
359   while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
360   {
361     lasue_temp = lasue_benchmarks;
362     lasue_temp = LFDS710_LIST_ASU_GET_NEXT( *lasue_temp );
363
364     libshared_ansi_strcat( bg->gnuplot_string, "     '-' using " );
365     libshared_ansi_strcat_number( bg->gnuplot_string, count++ );
366     libshared_ansi_strcat( bg->gnuplot_string, lasue_temp != NULL ? ", \\\n" : "\n" );
367   }
368
369   /* TRD : simpler output for the key-only chart
370            for each benchmark
371              print the title (name of all benchmarks)
372              for number of lp sets
373                print "0 " for number of benchmarks
374              print "e"
375
376            print;
377             set key off
378             set border
379             set ytics mirror
380   */
381
382   lasue_benchmarks_outer = NULL;
383
384   while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks_outer) )
385   {
386     // TRD : now loop over every benchmark and print its lock name, in quotes
387     lasue_benchmarks = NULL;
388
389     while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
390     {
391       bs = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_benchmarks );
392
393       libshared_ansi_strcat( bg->gnuplot_string, "\"" );
394       libshared_ansi_strcat( bg->gnuplot_string, libbenchmark_globals_lock_names[bs->lock_id] );
395       libshared_ansi_strcat( bg->gnuplot_string, "\" " );
396     }
397
398     libshared_ansi_strcat( bg->gnuplot_string, "\n" );
399
400     // TRD : loop over every logical processor set
401     lasue_lpset = NULL;
402
403     while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*bsets->logical_processor_sets,lasue_lpset) )
404     {
405       logical_processor_set = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_lpset );
406
407       // TRD : now loop over every benchmark and print its lock name, in quotes
408       lasue_benchmarks = NULL;
409
410       while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
411         libshared_ansi_strcat( bg->gnuplot_string, "0 " );
412
413       libshared_ansi_strcat( bg->gnuplot_string, "\n" );
414     }
415
416     libshared_ansi_strcat( bg->gnuplot_string, "e\n" );
417   }
418
419   libshared_ansi_strcat( bg->gnuplot_string, "set key off\n"
420                                              "set border\n"
421                                              "set ytics mirror\n" );
422
423   // TRD : now repeat, this time emitting actual charts
424
425   // TRD : loop over every logical processor set
426   lasue_lpset = NULL;
427
428   while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*bsets->logical_processor_sets,lasue_lpset) )
429   {
430     logical_processor_set = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_lpset );
431
432     /* TRD : emit the chart header; xtics and plot
433              to get the display order right
434              we need to loop over every logical processor in the topology set
435              we then check each of each LP to see if they're in the lpset
436              if so, we print the LP number, otherwise a "-"
437     */
438
439     libshared_ansi_strcat( bg->gnuplot_string, "set xtics 1 out nomirror ( " );
440
441     baue = NULL;
442     count = 0;
443
444     while( lfds710_btree_au_get_by_absolute_position_and_then_by_relative_position(&bsets->ts->topology_tree, &baue, LFDS710_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE, LFDS710_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE) )
445     {
446       tns = LFDS710_BTREE_AU_GET_KEY_FROM_ELEMENT( *baue );
447
448       if( tns->type == LIBBENCHMARK_TOPOLOGY_NODE_TYPE_LOGICAL_PROCESSOR )
449       {
450         /* TRD : now for this processor set, loop over every logical core and see if lp is in this set
451                  if in set, and processor_group is not set, print the processor number, or "-"
452                  if in set, and processor_group is set, print "processor number/group number", or "-"
453         */
454
455         lasoe_inner = NULL;
456         found_flag = LOWERED;
457
458         while( found_flag == LOWERED and LFDS710_LIST_ASO_GET_START_AND_THEN_NEXT(*logical_processor_set, lasoe_inner) )
459         {
460           tns_inner = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasoe_inner );
461
462           if( 0 == libbenchmark_topology_node_compare_nodes_function(tns, tns_inner) )
463             found_flag = RAISED;
464         }
465
466         /* TRD : check to see if we're the last element - if so, no trailing comman
467                  the final LP is always the smallest element in the tree, so it's always the final element in the tree
468         */
469         baue_temp = baue;
470         lfds710_btree_au_get_by_relative_position( &baue_temp, LFDS710_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE );
471         libshared_ansi_strcat( bg->gnuplot_string, "\"" );
472
473         if( found_flag == RAISED )
474         {
475           libshared_ansi_strcat_number( bg->gnuplot_string, LIBBENCHMARK_TOPOLOGY_NODE_GET_LOGICAL_PROCESSOR_NUMBER(*tns_inner) );
476
477           if( LIBBENCHMARK_TOPOLOGY_NODE_IS_WINDOWS_GROUP_NUMBER(*tns_inner) )
478           {
479             libshared_ansi_strcat( bg->gnuplot_string, "/" );
480             libshared_ansi_strcat_number( bg->gnuplot_string, LIBBENCHMARK_TOPOLOGY_NODE_GET_WINDOWS_GROUP_NUMBER(*tns_inner) );
481           }
482         }
483
484         if( found_flag == LOWERED )
485           libshared_ansi_strcat( bg->gnuplot_string, "-" );
486
487         libshared_ansi_strcat( bg->gnuplot_string, "\" " );
488         libshared_ansi_strcat_number( bg->gnuplot_string, count++ );
489         libshared_ansi_strcat( bg->gnuplot_string, baue_temp != NULL ? ", " : " " );
490       }
491     }
492
493     libshared_ansi_strcat( bg->gnuplot_string, " )\n" );
494
495     /* TRD : now the plot command
496
497              christ, I need an API for this, to build up the plot in memory and then dump it out
498              this hardcoded in-line output is insane
499
500              we print one line per lock type (i.e. one per benchmark)
501     */
502
503     libshared_ansi_strcat( bg->gnuplot_string, "plot " );
504
505     // TRD : now loop over every benchmark
506     lasue_benchmarks = NULL;
507     count = 1;
508
509     while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
510     {
511       lasue_temp = lasue_benchmarks;
512       lasue_temp = LFDS710_LIST_ASU_GET_NEXT( *lasue_temp );
513
514       libshared_ansi_strcat( bg->gnuplot_string, "     '-' using " );
515       libshared_ansi_strcat_number( bg->gnuplot_string, count++ );
516       libshared_ansi_strcat( bg->gnuplot_string, lasue_temp != NULL ? ", \\\n" : "\n" );
517     }
518
519     /* TRD : now for the results
520              we need to print 0s for the LPs not in the set
521              and only the topology shows the LPs we do not have
522              so iterate over the LPs in topology
523              for each LP in topology
524              we can search the result set for it, because if it's not there, we'll print a 0
525
526              we need to print these all once per benchmark/lock
527     */
528
529     lasue_benchmarks_outer = NULL;
530
531     while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks_outer) )
532     {
533       baue = NULL;
534
535       // TRD : now loop over every benchmark and print its lock name, in quotes
536       lasue_benchmarks = NULL;
537
538       while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
539       {
540         bs = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_benchmarks );
541
542         libshared_ansi_strcat( bg->gnuplot_string, "\"" );
543         libshared_ansi_strcat( bg->gnuplot_string, libbenchmark_globals_lock_names[bs->lock_id] );
544         libshared_ansi_strcat( bg->gnuplot_string, "\" " );
545       }
546
547       libshared_ansi_strcat( bg->gnuplot_string, "\n" );
548
549       baue_inner = NULL;
550
551       while( lfds710_btree_au_get_by_absolute_position_and_then_by_relative_position(&bsets->ts->topology_tree, &baue_inner, LFDS710_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE, LFDS710_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE) )
552       {
553         tns = LFDS710_BTREE_AU_GET_KEY_FROM_ELEMENT( *baue_inner );
554
555         if( tns->type == LIBBENCHMARK_TOPOLOGY_NODE_TYPE_LOGICAL_PROCESSOR )
556         {
557           // TRD : so we have an LP - now loop over every benchmark, and print 0 if not found, result if found
558           lasue_benchmarks = NULL;
559
560           while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(bsets->benchmarks,lasue_benchmarks) )
561           {
562             bs = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue_benchmarks );
563
564             // TRD : now, finally, let's go shopping
565             rv = libbenchmark_results_get_result( rs, 
566                                                   bsets->datastructure_id,
567                                                   bsets->benchmark_id,
568                                                   bs->lock_id,
569                                                   numa_mode,
570                                                   logical_processor_set,
571                                                   tns,
572                                                   &result );
573
574             if( rv == 0 )
575               libshared_ansi_strcat( bg->gnuplot_string, "0 " );
576
577             if( rv == 1 )
578             {
579               libshared_ansi_strcat_number( bg->gnuplot_string, result / libbenchmark_globals_benchmark_duration_in_seconds);
580               libshared_ansi_strcat( bg->gnuplot_string, " " );
581             }
582           }
583
584           libshared_ansi_strcat( bg->gnuplot_string, "\n" );
585         }
586       }
587
588       libshared_ansi_strcat( bg->gnuplot_string, "e\n" );
589     }
590   }
591
592   return;
593 }
594