1
2# Generate an ascii summary from lmbench result files BY HOSTNAME
3# instead of architecture.  Sorry, I think of these tools as being
4# used to measure and prototype particular named systems, not as
5# being useful to measure once and for all "i686-linux" systems,
6# which might well have different motherboards, chipsets, memory
7# clocks, CPU's (anything from PPro through to PIII so far) and
8# so forth.  Linux systems are far to heterogeneous to be categorized
9# with two or three descriptors, so might as well just use hostname
10# for shorthand...
11#
12# Usage: statsummary file file file...
13#
14# Hacked into existence by Larry McVoy (lm@sun.com now lm@sgi.com).
15# Copyright (c) 1994 Larry McVoy.  GPLed software.
16#
17# $Id: statsummary,v 1.5 2000/07/08 21:06:49 rgb Exp $
18#
19#
20# Edit History.  I'm starting out with Larry's getsummary.  Then I'm
21# going to splice in a very simple set of stats routines that are
22# passed an array in his standard form and return a structure containing
23# max, min, mean, median, unbiased standard deviation and we'll go from
24# there.  However I'll likely print out only mean and SD and will try
25# to preserve Larry's general layout at that.  Oh, and I'm going to add
26# COMMENTS to the script.  Drives me nuts to work on something without
27# comments.  7/6/00
28
29eval 'exec perl -Ssw $0 "$@"'
30  if 0;
31
32#
33# This segment loops through all the output files and pushes the
34# specific field values it needs into suitably named arrays.  It
35# counts while it does so so it can check to be sure that all
36# the input files are complete.
37$n = 0;
38@hosts = ();
39foreach $file (@ARGV) {
40  open(FD, $file) || die "$0: can't open $file";
41  # I just want @file to contain the hostname, not the path or architecture.
42  # However, we have reason to need the associated filename (no path) to
43  # to help with debugging.
44  # Strip off the path
45  $file =~ s/(.*)\///;
46  # Split the filename from the number.  This will probably break if the
47  # hostname contains more "."'s.  However, I'm too lazy to figure out
48  # how to make this work totally robustly.  It would be easy if the
49  # the host datafiles were all created according to the "hostname.count"
50  # format, because then a simple regexp would pull off just the hostname
51  # or the count.  Not so easy when a hostname/count might contain no "."'s
52  # at all...
53  $filecount = "";
54  ($file,$filecount) = split(/\./,$file);
55  # fix silly bug caused by starting numbering at blank.
56  if(! $filecount){
57    $filecount = 0;
58  }
59  # Debugging...
60  # print STDERR "Found file $file with count $filecount\n";
61  push(@file, $file);
62  push(@filecount, $filecount);
63
64  # This should just push UNIQUE new hosts onto @hosts.
65  $numhosts = @hosts;
66  if($numhosts){
67    $lasthost = $hosts[$numhosts-1];
68  } else {
69    $lasthost = "";
70  }
71  if($lasthost !~ /$file/){
72    push(@hosts, $file);
73  }
74
75  $mhz = 0;
76  while (<FD>) {
77    chop;
78    next if m|scripts/lmbench: /dev/tty|;
79    if (/^\[lmbench/) {
80      push(@uname, $_);
81      if (/lmbench1\./) {
82        $version = 1;
83      } else {
84        $version = 2;
85      }
86    }
87    if (/MHZ/ && !$mhz) {
88      @_ = split;
89      $_[1] =~ s/\]//;
90      push(@misc_mhz, $_[1]);
91      $mhz = 1;
92    } elsif (/Mhz/ && !$mhz) {
93      @_ = split;
94      push(@misc_mhz, $_[0]);
95      $mhz = 1;
96    }
97    if (/^Select on 100 fd/) {
98      @_ = split;
99      push(@lat_select, $_[4]);
100      $tmp = $lat_select[0];	# Just to shut up the error parser
101    }
102    if (/^Simple syscall:/) {
103      @_ = split;
104      push(@lat_syscall, $_[2]);
105      $tmp = $lat_syscall[0];	# Just to shut up the error parser
106    }
107    if (/^Simple read:/) {
108      @_ = split;
109      push(@lat_read, $_[2]);
110      $tmp = $lat_read[0];	# Just to shut up the error parser
111    }
112    if (/^Simple write:/) {
113      @_ = split;
114      push(@lat_write, $_[2]);
115      $tmp = $lat_write[0];	# Just to shut up the error parser
116    }
117    if (/^Simple stat:/) {
118      @_ = split;
119      push(@lat_stat, $_[2]);
120      $tmp = $lat_stat[0];	# Just to shut up the error parser
121    }
122    if (/^Simple open.close:/) {
123      @_ = split;
124      push(@lat_openclose, $_[2]);
125      $tmp = $lat_openclose[0];	# Just to shut up the error parser
126    }
127    if (/^Null syscall:/) {  # Old format.
128      @_ = split;
129      push(@lat_write, $_[2]);
130      $tmp = $lat_write[0];	# Just to shut up the error parser
131    }
132    if (/^Signal handler installation:/) {
133      @_ = split;
134      push(@lat_siginstall, $_[3]);
135      $tmp = $lat_siginstall[0];	# Just to shut up the error parser
136    }
137    if (/^Signal handler overhead:/) {
138      @_ = split;
139      push(@lat_sigcatch, $_[3]);
140      $tmp = $lat_sigcatch[0];	# Just to shut up the error parser
141    }
142    if (/^Protection fault:/) {
143      @_ = split;
144      push(@lat_protfault, $_[2]);
145      $tmp = $lat_protfault[0];	# Just to shut up the error parser
146    }
147    if (/^Pipe latency:/) {
148      @_ = split;
149      push(@lat_pipe, $_[2]);
150      $tmp = $lat_pipe[0];	# Just to shut up the error parser
151    }
152    if (/AF_UNIX sock stream latency:/) {
153      @_ = split;
154      push(@lat_unix, $_[4]);
155      $tmp = $lat_unix[0];	# Just to shut up the error parser
156    }
157    if (/^UDP latency using /) {
158      if(/localhost:/) {
159        @_ = split;
160        push(@lat_udp_local, $_[4]);
161        $tmp = $lat_udp_local[0];	# Just to shut up the error parser
162      } else {
163        @_ = split;
164        push(@lat_udp_net, $_[4]);
165        $tmp = $lat_udp_net[0];	# Just to shut up the error parser
166      }
167    }
168    if (/^TCP latency using /) {
169      if(/localhost:/) {
170        @_ = split;
171        push(@lat_tcp_local, $_[4]);
172        $tmp = $lat_tcp_local[0];	# Just to shut up the error parser
173      } else {
174        @_ = split;
175        push(@lat_tcp_net, $_[4]);
176        $tmp = $lat_tcp_net[0];	# Just to shut up the error parser
177      }
178    }
179    if (/^RPC\/udp latency using /) {
180      if(/localhost:/) {
181        @_ = split;
182        push(@lat_rpc_udp_local, $_[4]);
183        $tmp = $lat_rpc_udp_local[0];	# Just to shut up the error parser
184      } else {
185        @_ = split;
186        push(@lat_rpc_udp_net, $_[4]);
187        $tmp = $lat_rpc_udp_net[0];	# Just to shut up the error parser
188      }
189    }
190    if (/^RPC\/tcp latency using /) {
191      if(/localhost:/) {
192        @_ = split;
193        push(@lat_rpc_tcp_local, $_[4]);
194        $tmp = $lat_rpc_tcp_local[0];	# Just to shut up the error parser
195      } else {
196        @_ = split;
197        push(@lat_rpc_tcp_net, $_[4]);
198        $tmp = $lat_rpc_tcp_net[0];	# Just to shut up the error parser
199      }
200    }
201    if (/^TCP\/IP connection cost to /) {
202      if(/localhost:/) {
203        @_ = split;
204        push(@lat_tcp_connect_local, $_[5]);
205        $tmp = $lat_tcp_connect_local[0];	# Just to shut up the error parser
206      } else {
207        @_ = split;
208        push(@lat_tcp_connect_net, $_[5]);
209        $tmp = $lat_tcp_connect_net[0];	# Just to shut up the error parser
210      }
211    }
212    if (/^Socket bandwidth using /) {
213      if(/localhost:/) {
214        @_ = split;
215        push(@bw_tcp_local, $_[4]);
216        $tmp = $bw_tcp_local[0];	# Just to shut up the error parser
217      } else {
218        @_ = split;
219        push(@bw_tcp_net, $_[4]);
220        $tmp = $bw_tcp_net[0];	# Just to shut up the error parser
221      }
222    }
223    if (/^AF_UNIX sock stream bandwidth:/) {
224      @_ = split;
225      push(@bw_unix, $_[4]);
226      $tmp = $bw_unix[0];	# Just to shut up the error parser
227    }
228    if (/^Process fork.exit/) {
229      @_ = split;
230      push(@lat_nullproc, $_[2]);
231      $tmp = $lat_nullproc[0];	# Just to shut up the error parser
232    }
233    if (/^Process fork.execve:/) {
234      @_ = split;
235      push(@lat_simpleproc, $_[2]);
236      $tmp = $lat_simpleproc[0];	# Just to shut up the error parser
237    }
238    if (/^Process fork..bin.sh/) {
239      @_ = split;
240      push(@lat_shproc, $_[3]);
241      $tmp = $lat_shproc[0];	# Just to shut up the error parser
242    }
243    if (/^Pipe bandwidth/) {
244      @_ = split;
245      push(@bw_pipe, $_[2]);
246      $tmp = $bw_pipe[0];	# Just to shut up the error parser
247    }
248    if (/^File .* write bandwidth/) {
249      @_ = split;
250      $bw = sprintf("%.2f", $_[4] / 1024.);
251      push(@bw_file, $bw);
252      $tmp = $bw_file[0];	# Just to shut up the error parser
253    }
254    if (/^Pagefaults on/) {
255      @_ = split;
256      push(@lat_pagefault, $_[3]);
257      $tmp = $lat_pagefault[0];	# Just to shut up the error parser
258    }
259    if (/^"mappings/) {
260      $value = &getbiggest("memory mapping timing");
261      push(@lat_mappings, $value);
262      $tmp = $lat_mappings[0];	# Just to shut up the error parser
263    }
264    if (/^"read bandwidth/) {
265      $value = &getbiggest("reread timing");
266      push(@bw_reread, $value);
267      $tmp = $bw_reread[0];	# Just to shut up the error parser
268    }
269    if (/^"Mmap read bandwidth/) {
270      $value = &getbiggest("mmap reread timing");
271      push(@bw_mmap, $value);
272      $tmp = $bw_mmap[0];	# Just to shut up the error parser
273    }
274    if (/^"libc bcopy unaligned/) {
275      $value = &getbiggest("libc bcopy timing");
276      push(@bw_bcopy_libc, $value);
277      $tmp = $bw_bcopy_libc[0];	# Just to shut up the error parser
278    }
279    if (/^"unrolled bcopy unaligned/) {
280      $value = &getbiggest("unrolled bcopy timing");
281      push(@bw_bcopy_unrolled, $value);
282      $tmp = $bw_bcopy_unrolled[0];	# Just to shut up the error parser
283    }
284    if (/^Memory read/) {
285      $value = &getbiggest("memory read & sum timing");
286      push(@bw_mem_rdsum, $value);
287      $tmp = $bw_mem_rdsum[0];	# Just to shut up the error parser
288    }
289    if (/^Memory write/) {
290      $value = &getbiggest("memory write timing");
291      push(@bw_mem_wr, $value);
292      $tmp = $bw_mem_wr[0];	# Just to shut up the error parser
293    }
294    if (/^"File system latency/) {
295      while (<FD>) {
296        next if /Id:/;
297        if (/^0k/) {
298          @_ = split;
299          push(@fs_create_0k, $_[2]);
300          push(@fs_delete_0k, $_[3]);
301          $tmp = $fs_create_0k[0];	# Just to shut up the error parser
302          $tmp = $fs_delete_0k[0];	# Just to shut up the error parser
303        } elsif (/^1k/) {
304          @_ = split;
305          push(@fs_create_1k, $_[2]);
306          push(@fs_delete_1k, $_[3]);
307          $tmp = $fs_create_1k[0];	# Just to shut up the error parser
308          $tmp = $fs_delete_1k[0];	# Just to shut up the error parser
309        } elsif (/^4k/) {
310          @_ = split;
311          push(@fs_create_4k, $_[2]);
312          push(@fs_delete_4k, $_[3]);
313          $tmp = $fs_create_4k[0];	# Just to shut up the error parser
314          $tmp = $fs_delete_4k[0];	# Just to shut up the error parser
315        } elsif (/^10k/) {
316          @_ = split;
317          push(@fs_create_10k, $_[2]);
318          push(@fs_delete_10k, $_[3]);
319          $tmp = $fs_create_10k[0];	# Just to shut up the error parser
320          $tmp = $fs_delete_10k[0];	# Just to shut up the error parser
321        } else {
322          last;
323        }
324      }
325    }
326    if (/size=0/) {
327      while (<FD>) {
328        if (/^2 /) {
329          @_ = split; push(@lat_ctx0_2, $_[1]);
330          $tmp = $lat_ctx0_2[0];	# Just to shut up the error parser
331        } elsif (/^8 /) {
332          @_ = split; push(@lat_ctx0_8, $_[1]);
333          $tmp = $lat_ctx0_8[0];	# Just to shut up the error parser
334        } elsif (/^16 /) {
335          @_ = split; push(@lat_ctx0_16, $_[1]);
336          $tmp = $lat_ctx0_16[0];	# Just to shut up the error parser
337        }
338            last if /^\s*$/ || /^Memory/;
339      }
340    }
341    if (/size=16/) {
342      while (<FD>) {
343        if (/^2 /) {
344          @_ = split; push(@lat_ctx16_2, $_[1]);
345          $tmp = $lat_ctx16_2[0];	# Just to shut up the error parser
346        } elsif (/^8 /) {
347          @_ = split; push(@lat_ctx16_8, $_[1]);
348          $tmp = $lat_ctx16_8[0];	# Just to shut up the error parser
349        } elsif (/^16 /) {
350          @_ = split; push(@lat_ctx16_16, $_[1]);
351          $tmp = $lat_ctx16_16[0];	# Just to shut up the error parser
352        }
353            last if /^\s*$/;
354      }
355    }
356    if (/size=64/) {
357      while (<FD>) {
358        if (/^2 /) {
359          @_ = split; push(@lat_ctx64_2, $_[1]);
360          $tmp = $lat_ctx64_2[0];	# Just to shut up the error parser
361        } elsif (/^8 /) {
362          @_ = split; push(@lat_ctx64_8, $_[1]);
363          $tmp = $lat_ctx64_8[0];	# Just to shut up the error parser
364        } elsif (/^16 /) {
365          @_ = split; push(@lat_ctx64_16, $_[1]);
366          $tmp = $lat_ctx64_16[0];	# Just to shut up the error parser
367        }
368            last if /^\s*$/ || /^20/;
369      }
370    }
371    if (/^"stride=128/) {
372      $save = -1;
373      while (<FD>) {
374        if (/^0.00098\s/) {
375          @_ = split;
376          push(@lat_l1, $_[1]);
377          $tmp = $lat_l1[0];	# Just to shut up the error parser
378        } elsif (/^0.12500\s/) {
379          @_ = split;
380          push(@lat_l2, $_[1]);
381          $tmp = $lat_l2[0];	# Just to shut up the error parser
382        } elsif (/^[45678].00000\s/) {
383          @_ = split;
384          $size = $_[0];
385          $save = $_[1];
386          last if /^8.00000\s/;
387        } elsif (/^\s*$/) {
388          last;
389        }
390      }
391      if (!/^8/) {
392        warn "$file: No 8MB memory latency, using $size\n";
393      }
394      push(@lat_mem, $save);
395    }
396  }
397  @warn = ();
398  foreach $array (
399    'bw_bcopy_libc', 'bw_bcopy_unrolled', 'bw_file',
400    'bw_mem_rdsum', 'bw_mem_wr', 'bw_mmap', 'bw_pipe',
401    'bw_reread', 'bw_tcp_local', 'bw_unix',
402    'fs_create_0k','fs_delete_0k',
403    'fs_create_1k','fs_delete_1k',
404    'fs_create_4k','fs_delete_4k',
405    'fs_create_10k','fs_delete_10k',
406    'lat_ctx0_16', 'lat_ctx0_2', 'lat_ctx0_8',
407    'lat_ctx16_16', 'lat_ctx16_2', 'lat_ctx16_8',
408    'lat_ctx64_16', 'lat_ctx64_2', 'lat_ctx64_8', 'lat_l1',
409    'lat_l2', 'lat_mappings', 'lat_mem', 'lat_nullproc',
410    'lat_openclose', 'lat_pagefault', 'lat_pipe',
411    'lat_protfault', 'lat_read',
412    'lat_rpc_tcp_local','lat_rpc_udp_local',
413    'lat_tcp_connect_local', 'lat_tcp_local', 'lat_udp_local',
414    'lat_rpc_tcp_net','lat_rpc_udp_net',
415    'lat_tcp_connect_net', 'lat_tcp_net', 'lat_udp_net',
416    'lat_select', 'lat_shproc', 'lat_sigcatch',
417    'lat_siginstall', 'lat_simpleproc', 'lat_stat',
418    'lat_syscall', 'lat_unix', 'lat_write', 'misc_mhz',
419  ) {
420    $last = eval '$#' . $array;
421    if ($last != $n) {
422      #warn "No data for $array in $file\n";
423      push(@warn, $array);
424      eval 'push(@' . $array . ', -1);';
425    }
426  }
427  if ($#warn != -1) {
428    warn "Missing data in $file: @warn\n";
429  }
430  $n++;
431}
432
433#
434# OK, now all those arrays are packed.  Because everything is keyed
435# on raw hostname, we can do all the stats evaluations using a combination
436# of @file and the array -- we march through @file and create a stats
437# object (a % hash) with its name and do the obvious sums and so forth.
438# should be very simple.
439#
440# However, to be fair to Larry, we do want to preserve the general flavor
441# of the summary.  However, the summary is now going to be output BY HOST
442# and so we need a separate host-description section for each host.
443#
444# First we have to evaluate the stats, though.
445#
446
447#
448# Let's test this with just one small set of values...
449foreach $array (
450    'bw_bcopy_libc', 'bw_bcopy_unrolled', 'bw_file',
451    'bw_mem_rdsum', 'bw_mem_wr', 'bw_mmap', 'bw_pipe',
452    'bw_reread', 'bw_tcp_local', 'bw_unix',
453    'fs_create_0k','fs_delete_0k',
454    'fs_create_1k','fs_delete_1k',
455    'fs_create_4k','fs_delete_4k',
456    'fs_create_10k','fs_delete_10k',
457    'lat_l1',
458    'lat_l2', 'lat_mappings', 'lat_mem', 'lat_nullproc',
459    'lat_openclose', 'lat_pagefault', 'lat_pipe',
460    'lat_protfault', 'lat_read',
461    'lat_rpc_tcp_local','lat_rpc_udp_local',
462    'lat_tcp_connect_local', 'lat_tcp_local', 'lat_udp_local',
463    'lat_rpc_tcp_net','lat_rpc_udp_net',
464    'lat_tcp_connect_net', 'lat_tcp_net', 'lat_udp_net',
465    'lat_select', 'lat_shproc', 'lat_sigcatch',
466    'lat_siginstall', 'lat_simpleproc', 'lat_stat',
467    'lat_syscall', 'lat_unix', 'lat_write', 'misc_mhz',
468  ) { }	# Empty just to save the full list someplace handy.
469
470#
471# Oops.  For some unfathomable reason lat_fs returns something other than
472# an (average) time in nanoseconds.  Why, I cannot imagine -- one could
473# trivially invert so that it did so.  One CANNOT DO STATS on inverse
474# quantities, so we invert here and convert to nanoseconds
475# so we can correctly do stats below.
476foreach $array (
477    'fs_create_0k','fs_delete_0k','fs_create_1k','fs_delete_1k',
478    'fs_create_4k','fs_delete_4k','fs_create_10k','fs_delete_10k',
479    ) {
480  $cnt = 0;
481  foreach $entry (@$array){
482    $$array[$cnt++] = 1.0e+9/$entry;
483  }
484
485}
486
487# Working copy.  Let's just add things as they turn out to be
488# appropriate.  In fact, we'll add them in presentation order!
489foreach $array (
490    'lat_syscall','lat_read', 'lat_write', 'lat_syscall', 'lat_stat',
491    'lat_openclose','lat_select','lat_siginstall','lat_sigcatch',
492    'lat_nullproc','lat_simpleproc','lat_shproc',
493    'lat_ctx0_2','lat_ctx0_16','lat_ctx0_8',
494    'lat_ctx16_16','lat_ctx16_2','lat_ctx16_8',
495    'lat_ctx64_16','lat_ctx64_2','lat_ctx64_8',
496    'lat_pipe','lat_unix',
497    'lat_udp_local','lat_tcp_local',lat_tcp_connect_local,
498    'lat_rpc_udp_local','lat_rpc_tcp_local',
499    'lat_udp_net','lat_tcp_net',lat_tcp_connect_net,
500    'lat_rpc_udp_net','lat_rpc_tcp_net',
501    'fs_create_0k','fs_delete_0k',
502    'fs_create_1k','fs_delete_1k',
503    'fs_create_4k','fs_delete_4k',
504    'fs_create_10k','fs_delete_10k',
505    'lat_mappings','lat_protfault','lat_pagefault',
506    'bw_pipe','bw_unix',
507    'bw_tcp_local',	# Note we need bw_udp_local as soon as it exists...
508    'bw_reread','bw_mmap','bw_bcopy_libc','bw_bcopy_unrolled',
509    'bw_mem_rdsum','bw_mem_wr',
510    'bw_tcp_net',
511    'lat_l1','lat_l2','lat_mem',
512    ) {
513
514  #
515  # This should do it all, by name and collapsed by hostname
516  #
517  makestats($array);
518
519}
520
521#
522# Fine, that seems to work.  Now we break up the summary, BY HOST.
523# For each host we print just ONE TIME key values that don't really
524# vary (like its architecture information and clock).  Then we print
525# out a modified version of Larry's old summary.
526#
527
528#
529# First the header
530#
531print<<EOF;
532========================================================================
533
534                 L M B E N C H  3 . 0   S U M M A R Y
535                 ------------------------------------
536
537========================================================================
538
539EOF
540
541#
542# Now a host loop.  Notice that @hosts is a list of hosts
543#
544$numhosts = @hosts;
545for($i=0;$i<$numhosts;$i++){
546  $host = $hosts[$i];
547  # Obviously we need a better way to fill in this information.
548  # Linux provides /proc/cpuinfo, which is just perfect and trivial
549  # to parse.  However, we should probably read this in from e.g.
550  # config/$host.conf, which can be created either automagically or
551  # by hand.  This file should also be used to control the running
552  # of the benchmark suite, which in turn should be done by means of
553  # a script call, not a make target.  I'm getting there...
554  #
555  # Oh, one last note.  It would be VERY CONVENIENT to have the config
556  # information stored in perl.  So convenient that the following should
557  # BE the format of the config file... (up to the next comment)
558  $CPU = "Celeron(Mendocino)";
559  $CPUFAMILY = "i686";
560  $MHz = 400;
561  $L1CODE = 16;
562  $L1DATA = 16;
563  $L2SIZE = 128;
564  $memsize = 128;
565  $memspeed = "PC100";
566  $memtype = "SDRAM";
567  @DISKS = ("/dev/hda","/dev/hdb","/dev/hdc");
568  @DISKTYPE = ("IBM-DJNA-371350, ATA DISK drive", "Disk 2", "Disk etc.");
569  @NETWORKS = ("ethernet-100","SneakerNet @ 3 meters/second");
570  @NICTYPE = ("Lite-On 82c168 PNIC rev 32","Nike Sports (etc.)");
571  @NETHUB = ("Netgear FS108 Fast Ethernet Switch","The Floor");
572  #
573  # OK, given this wealth of detail (which can be sourced directly into
574  # the perl script from the host config file if we are clever) we now
575  # print it into the report/summary.
576  #
577  printf("HOST:\t\t$host\n");
578  printf("CPU:\t\t$CPU\n");
579  printf("CPU Family:\t$CPUFAMILY\n");
580  printf("MHz:\t\t$MHz\n");
581  printf("L1 Cache Size:\t$L1CODE KB (code)/$L1DATA KB (data)\n");
582  printf("L2 Cache Size:\t$L2SIZE KB\n");
583  printf("Memory:\t\t$memsize MB of $memspeed $memtype\n");
584  printf("OS Kernel:\t%13s\n",&getos($uname[0]));
585  printf("Disk(s):\n");
586  $numdisks = @DISKS;
587  for($j=0;$j<$numdisks;$j++){
588    printf("\t\t%d) %s: %s\n",$j+1,$DISKS[$j],$DISKTYPE[$j]);
589  }
590  printf("Network(s):\n");
591  $numnets = @NETWORKS;
592  for($j=0;$j<$numnets;$j++){
593    printf("\t\t%d) %s: %s\n",$j+1,$NETWORKS[$j],$NICTYPE[$j]);
594    printf("\t\t   Switch/Hub: %s\n",$NETHUB[$j]);
595  }
596  print<<EOF;
597
598
599------------------------------------------------------------------------
600Processor, Processes - average times in microseconds - smaller is better
601------------------------------------------------------------------------
602 null           null                         open/
603 call  Error    I/O   Error    stat  Error   close  Error
604------ ------  ------ ------  ------ ------  ------ ------
605EOF
606
607#
608# In all the output below, averaged arrays are accessed by the hash:
609#  $stats{$host}{$array}{mean or stddev} (or whatever)
610
611  @fs_delete_4k = @lat_ctx0_8 = @bw_file = @lat_ctx0_16 = @fs_delete_1k =
612  @fs_create_4k = @fs_create_1k
613    if 0;  # lint
614
615  # If they have no /dev/zero, use /dev/null, else average them.
616  if ($stats{$host}{lat_read}{mean} == -1) {
617    $lat_rw_mean = $stats{$host}{lat_write}{mean};
618    $lat_rw_stddev = $stats{$host}{lat_write}{stddev};
619  } else {
620    $lat_rw_mean = ($stats{$host}{lat_read}{mean} + $stats{$host}{lat_write}{mean})/2;
621    $lat_rw_stddev = ($stats{$host}{lat_read}{stddev} + $stats{$host}{lat_write}{stddev})/2;
622  }
623  # We have to pick a format adequate for these numbers.  We'll shoot for
624  # %5.2f and see how it goes.
625  printf("%6.3f %6.3f  ",$stats{$host}{lat_syscall}{mean},$stats{$host}{lat_syscall}{stddev});
626  printf("%6.3f %6.3f  ",$lat_rw_mean,$lat_rw_stddev);
627  printf("%6.3f %6.3f  ",$stats{$host}{lat_stat}{mean},$stats{$host}{lat_stat}{stddev});
628  printf("%6.3f %6.3f  ",$stats{$host}{lat_openclose}{mean},$stats{$host}{lat_openclose}{stddev});
629  # End with this to complete the line...
630  printf("\n");
631  print<<EOF;
632........................................................................
633               signal         signal
634select Error   instll Error   catch  Error
635------ ------  ------ ------  ------ ------
636EOF
637  printf("%6.1f %6.2f  ",$stats{$host}{lat_select}{mean},$stats{$host}{lat_select}{stddev});
638  printf("%6.3f %6.3f  ",$stats{$host}{lat_siginstall}{mean},$stats{$host}{lat_siginstall}{stddev});
639  printf("%6.3f %6.3f  ",$stats{$host}{lat_sigcatch}{mean},$stats{$host}{lat_sigcatch}{stddev});
640  # End with this to complete the line...
641  printf("\n");
642  print<<EOF;
643........................................................................
644 fork             exec             shell
645 proc    Error    proc    Error    proc    Error
646------- -------  ------- -------  ------- -------
647EOF
648  printf("%7.1f %7.2f  ",
649         $stats{$host}{lat_nullproc}{mean},$stats{$host}{lat_nullproc}{stddev});
650  printf("%7.1f %7.2f  ",
651         $stats{$host}{lat_simpleproc}{mean},$stats{$host}{lat_simpleproc}{stddev});
652  printf("%7.1f %7.2f  ",
653         $stats{$host}{lat_shproc}{mean},$stats{$host}{lat_shproc}{stddev});
654  # End with this to complete the line...
655  printf("\n");
656  print<<EOF;
657
658
659------------------------------------------------------------------------
660Context switching - times in microseconds - smaller is better
661------------------------------------------------------------------------
6622p/0K          2p/16K         2p/64K
663       Error          Error          Error
664------ ------  ------ ------  ------ ------
665EOF
666  printf("%6.2f %6.3f  ",
667         $stats{$host}{lat_ctx0_2}{mean},$stats{$host}{lat_ctx0_2}{stddev});
668  printf("%6.2f %6.3f  ",
669         $stats{$host}{lat_ctx16_2}{mean},$stats{$host}{lat_ctx16_2}{stddev});
670  printf("%6.2f %6.3f  ",
671         $stats{$host}{lat_ctx64_2}{mean},$stats{$host}{lat_ctx64_2}{stddev});
672  # End with this to complete the line...
673  printf("\n");
674  print<<EOF;
675........................................................................
6768p/0K          8p/16K         8p/64K
677       Error          Error          Error
678------ ------  ------ ------  ------ ------
679EOF
680  printf("%6.2f %6.3f  ",
681         $stats{$host}{lat_ctx0_8}{mean},$stats{$host}{lat_ctx16_8}{stddev});
682  printf("%6.2f %6.3f  ",
683         $stats{$host}{lat_ctx16_8}{mean},$stats{$host}{lat_ctx16_8}{stddev});
684  printf("%6.2f %6.3f  ",
685         $stats{$host}{lat_ctx64_8}{mean},$stats{$host}{lat_ctx64_8}{stddev});
686  # End with this to complete the line...
687  printf("\n");
688  print<<EOF;
689........................................................................
69016p/0K        16p/16K        16p/64K
691       Error          Error          Error
692------ ------  ------ ------  ------ ------
693EOF
694  printf("%6.2f %6.3f  ",
695         $stats{$host}{lat_ctx0_16}{mean},$stats{$host}{lat_ctx0_16}{stddev});
696  printf("%6.2f %6.3f  ",
697         $stats{$host}{lat_ctx16_16}{mean},$stats{$host}{lat_ctx16_16}{stddev});
698  printf("%6.2f %6.3f  ",
699         $stats{$host}{lat_ctx64_16}{mean},$stats{$host}{lat_ctx64_16}{stddev});
700  # End with this to complete the line...
701  printf("\n");
702  print<<EOF;
703
704------------------------------------------------------------------------
705*Local* Communication latencies in microseconds - smaller is better
706------------------------------------------------------------------------
707 Pipe            AF
708       Error    UNIX  Error
709------ ------  ------ ------
710EOF
711  printf("%6.2f %6.3f  ",
712         $stats{$host}{lat_pipe}{mean},$stats{$host}{lat_pipe}{stddev});
713  printf("%6.2f %6.3f  ",
714         $stats{$host}{lat_unix}{mean},$stats{$host}{lat_unix}{stddev});
715  printf("\n");
716  print<<EOF;
717........................................................................
718 UDP            TCP            TCP
719       Error          Error  Connect Error
720------ ------  ------ ------  ------ ------
721EOF
722  printf("%6.2f %6.3f  ",
723         $stats{$host}{lat_udp_local}{mean},$stats{$host}{lat_udp_local}{stddev});
724  printf("%6.2f %6.3f  ",
725         $stats{$host}{lat_tcp_local}{mean},$stats{$host}{lat_tcp_local}{stddev});
726  printf("%6.2f %6.3f  ",
727         $stats{$host}{lat_tcp_connect_local}{mean},$stats{$host}{lat_tcp_connect_local}{stddev});
728  printf("\n");
729  print<<EOF;
730........................................................................
731 RPC            RPC
732 UDP   Error    TCP Error
733------ ------  ------ ------
734EOF
735  printf("%6.2f %6.3f  ",
736         $stats{$host}{lat_rpc_udp_local}{mean},$stats{$host}{lat_rpc_udp_local}{stddev});
737  printf("%6.2f %6.3f  ",
738         $stats{$host}{lat_rpc_tcp_local}{mean},$stats{$host}{lat_rpc_tcp_local}{stddev});
739  printf("\n");
740  print<<EOF;
741
742------------------------------------------------------------------------
743*Network* Communication latencies in microseconds - smaller is better
744------------------------------------------------------------------------
745 UDP            TCP            TCP
746       Error          Error  Connect Error
747------ ------  ------ ------  ------ ------
748EOF
749  printf("%6.2f %6.3f  ",
750         $stats{$host}{lat_udp_net}{mean},$stats{$host}{lat_udp_net}{stddev});
751  printf("%6.2f %6.3f  ",
752         $stats{$host}{lat_tcp_net}{mean},$stats{$host}{lat_tcp_net}{stddev});
753  printf("%6.2f %6.3f  ",
754         $stats{$host}{lat_tcp_connect_net}{mean},$stats{$host}{lat_tcp_connect_net}{stddev});
755  printf("\n");
756  print<<EOF;
757........................................................................
758 RPC            RPC
759 UDP   Error    TCP Error
760------ ------  ------ ------
761EOF
762  printf("%6.2f %6.3f  ",
763         $stats{$host}{lat_rpc_udp_net}{mean},$stats{$host}{lat_rpc_udp_net}{stddev});
764  printf("%6.2f %6.3f  ",
765         $stats{$host}{lat_rpc_tcp_net}{mean},$stats{$host}{lat_rpc_tcp_net}{stddev});
766  printf("\n");
767  print<<EOF;
768
769------------------------------------------------------------------------
770File & VM system latencies in microseconds - smaller is better
771------------------------------------------------------------------------
772             0k File                           1K File
773Create   Error   Delete   Error   Create   Error   Delete   Error
774------- -------  ------- -------  ------- -------  ------- -------
775EOF
776  $c0k =    $stats{$host}{fs_create_0k}{mean} <= 0 ? -1 : $stats{$host}{fs_create_0k}{mean}/1000;
777  $c0kerr = $stats{$host}{fs_create_0k}{stddev} <= 0 ? -1 : $stats{$host}{fs_create_0k}{stddev}/1000;
778  $d0k =    $stats{$host}{fs_delete_0k}{mean} <= 0 ? -1 : $stats{$host}{fs_delete_0k}{mean}/1000;
779  $d0kerr = $stats{$host}{fs_delete_0k}{stddev} <= 0 ? -1 : $stats{$host}{fs_delete_0k}{stddev}/1000;
780  $c1k =    $stats{$host}{fs_create_1k}{mean} <= 0 ? -1 : $stats{$host}{fs_create_1k}{mean}/1000;
781  $c1kerr = $stats{$host}{fs_create_1k}{stddev} <= 0 ? -1 : $stats{$host}{fs_create_1k}{stddev}/1000;
782  $d1k =    $stats{$host}{fs_delete_1k}{mean} <= 0 ? -1 : $stats{$host}{fs_delete_1k}{mean}/1000;
783  $d1kerr = $stats{$host}{fs_delete_1k}{stddev} <= 0 ? -1 : $stats{$host}{fs_delete_1k}{stddev}/1000;
784  printf("%7.2f %7.3f  ",
785         $c0k,$c0kerr);
786  printf("%7.2f %7.3f  ",
787         $d0k,$d0kerr);
788  printf("%7.2f %7.3f  ",
789         $c1k,$c1kerr);
790  printf("%7.2f %7.3f  ",
791         $d1k,$d1kerr);
792  printf("\n");
793  print<<EOF;
794........................................................................
795             4k File                          10K File
796Create   Error   Delete   Error   Create   Error   Delete   Error
797------- -------  ------- -------  ------- -------  ------- -------
798EOF
799  $c4k =    $stats{$host}{fs_create_4k}{mean} <= 0 ? -1 : $stats{$host}{fs_create_4k}{mean}/1000;
800  $c4kerr = $stats{$host}{fs_create_4k}{stddev} <= 0 ? -1 : $stats{$host}{fs_create_4k}{stddev}/1000;
801  $d4k =    $stats{$host}{fs_delete_4k}{mean} <= 0 ? -1 : $stats{$host}{fs_delete_4k}{mean}/1000;
802  $d4kerr = $stats{$host}{fs_delete_4k}{stddev} <= 0 ? -1 : $stats{$host}{fs_delete_4k}{stddev}/1000;
803  $c10k =    $stats{$host}{fs_create_10k}{mean} <= 0 ? -1 : $stats{$host}{fs_create_10k}{mean}/1000;
804  $c10kerr = $stats{$host}{fs_create_10k}{stddev} <= 0 ? -1 : $stats{$host}{fs_create_10k}{stddev}/1000;
805  $d10k =    $stats{$host}{fs_delete_10k}{mean} <= 0 ? -1 : $stats{$host}{fs_delete_10k}{mean}/1000;
806  $d10kerr = $stats{$host}{fs_delete_10k}{stddev} <= 0 ? -1 : $stats{$host}{fs_delete_10k}{stddev}/1000;
807  printf("%7.2f %7.3f  ",
808         $c4k,$c4kerr);
809  printf("%7.2f %7.3f  ",
810         $d4k,$d4kerr);
811  printf("%7.2f %7.3f  ",
812         $c10k,$c10kerr);
813  printf("%7.2f %7.3f  ",
814         $d10k,$d10kerr);
815  printf("\n");
816  print<<EOF;
817........................................................................
818  Mmap              Prot              Page
819Latency   Error     Fault   Error     Fault   Error
820-------- --------  ------- -------  -------- --------
821EOF
822  printf("%8.2f %8.3f  ",
823         $stats{$host}{lat_mappings}{mean},$stats{$host}{lat_mappings}{stddev});
824  printf("%7.2f %7.3f  ",
825         $stats{$host}{lat_protfault}{mean},$stats{$host}{lat_protfault}{stddev});
826  printf("%8.2f %8.3f  ",
827         $stats{$host}{lat_pagefault}{mean},$stats{$host}{lat_pagefault}{stddev});
828  printf("\n");
829  print<<EOF;
830
831------------------------------------------------------------------------
832*Local* Communication bandwidths in MB/s - bigger is better
833------------------------------------------------------------------------
834 Pipe            AF
835       Error    UNIX  Error
836------ ------  ------ ------
837EOF
838  printf("%6.2f %6.3f  ",
839         $stats{$host}{bw_pipe}{mean},$stats{$host}{bw_pipe}{stddev});
840  printf("%6.2f %6.3f  ",
841         $stats{$host}{bw_unix}{mean},$stats{$host}{bw_unix}{stddev});
842  printf("\n");
843  print<<EOF;
844........................................................................
845 UDP            TCP
846       Error          Error
847------ ------  ------ ------
848EOF
849  printf("%6.2f %6.3f  ",
850         -1,-1);
851  printf("%6.2f %6.3f  ",
852         $stats{$host}{bw_tcp_local}{mean},$stats{$host}{bw_tcp_local}{stddev});
853  printf("\n");
854  print<<EOF;
855........................................................................
856 File           Mmap          Bcopy          Bcopy
857reread Error   reread Error   (libc) Error   (hand) Error
858------ ------  ------ ------  ------ ------  ------ ------
859EOF
860  printf("%6.2f %6.3f  ",
861         $stats{$host}{bw_reread}{mean},$stats{$host}{bw_reread}{stddev});
862  printf("%6.2f %6.3f  ",
863         $stats{$host}{bw_mmap}{mean},$stats{$host}{bw_mmap}{stddev});
864  printf("%6.2f %6.3f  ",
865         $stats{$host}{bw_bcopy_libc}{mean},$stats{$host}{bw_bcopy_libc}{stddev});
866  printf("%6.2f %6.3f  ",
867         $stats{$host}{bw_bcopy_unrolled}{mean},$stats{$host}{bw_bcopy_unrolled}{stddev});
868  printf("\n");
869  print<<EOF;
870........................................................................
871 Mem            Mem
872 read  Error   write  Error
873------ ------  ------ ------
874EOF
875  printf("%6.2f %6.3f  ",
876         $stats{$host}{bw_mem_rdsum}{mean},$stats{$host}{bw_mem_rdsum}{stddev});
877  printf("%6.2f %6.3f  ",
878         $stats{$host}{bw_mem_wr}{mean},$stats{$host}{bw_mem_wr}{stddev});
879  printf("\n");
880  print<<EOF;
881
882------------------------------------------------------------------------
883*Net* Communication bandwidths in MB/s - bigger is better
884------------------------------------------------------------------------
885 UDP            TCP
886       Error          Error
887------ ------  ------ ------
888EOF
889  printf("%6.2f %6.3f  ",
890         -1,-1);
891  printf("%6.2f %6.3f  ",
892         $stats{$host}{bw_tcp_net}{mean},$stats{$host}{bw_tcp_net}{stddev});
893  printf("\n");
894  print<<EOF;
895
896------------------------------------------------------------------------
897Memory latencies in nanoseconds - smaller is better
898  (WARNING - may not be correct, check graphs)
899------------------------------------------------------------------------
900  L1             L2            Main
901Cache  Error    Cache Error    mem   Error   Guesses
902------ ------  ------ ------  ------ ------  -------
903EOF
904  $msg = &check_caches;
905  if ($stats{$host}{lat_l1}{mean} < 0) {
906    printf("%6s %6s  ",
907         "------","------");
908    printf("%6s %6s  ",
909         "------","------");
910    printf("%6s %6s  ",
911         "------","------");
912    printf("%6s","Bad mhz?");
913  } else {
914    printf("%6.2f %6.3f  ",
915         $stats{$host}{lat_l1}{mean},$stats{$host}{lat_l1}{stddev});
916    printf("%6.2f %6.3f  ",
917         $stats{$host}{lat_l2}{mean},$stats{$host}{lat_l2}{stddev});
918    printf("%6.2f %6.3f  ",
919         $stats{$host}{lat_mem}{mean},$stats{$host}{lat_mem}{stddev});
920    print $msg if ($msg =~ /L/);
921  }
922  printf("\n");
923
924
925
926# This ends the host section...
927  print<<EOF;
928
929========================================================================
930EOF
931
932}
933
934exit 0;
935
936
937# (33, %3d)
938sub num
939{
940  local($val, $fmt) = @_;
941  local($str) = "";
942  local($i);
943
944  if ($val <= 0) {
945    $fmt =~ s/^.//;
946    while (length($fmt) > 1) { chop($fmt); }
947    for ($i = 0; $i < $fmt; $i++) {
948      $str .= " ";
949    }
950    return ($str);
951  }
952  $str = sprintf($fmt, $val);
953  $str;
954}
955
956# Input looks like
957# "benchmark name
958# size value
959# ....
960# <blank line>
961#
962# Return the biggest value before the blank line.
963sub getbiggest
964{
965  local($msg) = @_;
966  local($line) = 0;
967
968  undef $save;
969  $value = 0;
970  while (<FD>) {
971    $line++;
972    #warn "$line $_";
973    last if /^\s*$/;
974    $save = $_ if /^\d+\./;
975  }
976  if (defined $save) {
977    $_ = $save;
978    @d = split;
979    $value = $d[1];
980    if (int($d[0]) < 4) {
981      warn "$file: using $d[0] size for $msg\n";
982    }
983  } else {
984    warn "$file: no data for $msg\n";
985  }
986  $value;
987}
988
989
990# Try and create sensible names from uname -a output
991sub getos
992{
993        local(@info);
994
995        @info = split(/\s+/, $_[0]);
996        "$info[3] $info[5]";
997}
998
999# Return true if the values differe by less than 10%
1000sub same
1001{
1002  local($a, $b) = @_;
1003
1004  if ($a > $b) {
1005    $percent = (($a - $b) / $a) * 100;
1006  } else {
1007    $percent = (($b - $a) / $b) * 100;
1008  }
1009  return ($percent <= 20);
1010}
1011
1012sub check_caches
1013{
1014  if (!&same($lat_l1[$i], $lat_l2[$i]) &&
1015      &same($lat_l2[$i], $lat_mem[$i])) {
1016    "    No L2 cache?";
1017  } elsif (&same($lat_l1[$i], $lat_l2[$i])) {
1018    "    No L1 cache?";
1019  }
1020}
1021
1022sub makestats
1023{
1024
1025 my $cnt=0;
1026 my $host;
1027 # Debugging
1028 # print STDERR "Ready to make stats for array $array\n";
1029 # Zero the counters
1030 $numhosts = @hosts;
1031 for($i=0;$i<$numhosts;$i++){
1032   $host = $hosts[$i];
1033   $stats{$host}{$array}{mean} = 0.0;
1034   $stats{$host}{$array}{stddev} = 0.0;
1035   $stats{$host}{$array}{count} = 0;
1036 }
1037 # Loop through ALL DATA.  We use the hash to direct results to
1038 # to the appropriate counters.
1039 foreach $value (@$array){
1040   $host = $file[$cnt];
1041   if($$array[0] == -1){
1042     $stats{$host}{$array}{mean} = -1;
1043     $stats{$host}{$array}{stddev} = -1;
1044     # Debugging (and curiosity)
1045     print STDERR "Oops.  $array is empty.\n";
1046     return;
1047   }
1048   # Debugging
1049   # print STDERR "$host/$array ($cnt): value is $value\n";
1050   $stats{$host}{$array}{mean} += $value;
1051   $stats{$host}{$array}{stddev} += $value*$value;
1052   $stats{$host}{$array}{count}++;
1053   $cnt++;
1054 }
1055 for($i=0;$i<$numhosts;$i++){
1056   $host = $hosts[$i];
1057   $cnt = $stats{$host}{$array}{count};
1058   # Debugging Only
1059   # print STDERR "Evaluating final mean/stddev of $cnt objects in $host/$array\n";
1060   if($cnt>1) {
1061     $stats{$host}{$array}{mean} = $stats{$host}{$array}{mean} / $cnt;
1062     $stats{$host}{$array}{stddev} = sqrt(($stats{$host}{$array}{stddev} / $cnt
1063          - $stats{$host}{$array}{mean}*$stats{$host}{$array}{mean})/($cnt-1));
1064   } elsif($cnt == 1) {
1065     # Wish one could assign "infinity".  This probably breaks somewhere.
1066     $stats{$host}{$array}{stddev} = 1.0e+1000;
1067   } else {
1068     # print STDERR "Error:  Cannot average 0 $array results on $host\n";
1069   }
1070
1071   # Debugging Only.
1072   # print STDERR "$host/$array (average): $stats{$host}{$array}{mean} +/- $stats{$host}{$array}{stddev}\n";
1073 }
1074
1075}
1076