# Generate an ascii summary from lmbench result files. # Usage: getsummary file file file... # # Hacked into existence by Larry McVoy (lm@sun.com now lm@sgi.com). # Copyright (c) 1994 Larry McVoy. GPLed software. # $Id: getsummary.html,v 1.1 2002/12/19 22:07:59 deadline Exp $ eval 'exec perl -Ssw $0 "$@"' if 0; # Use these constants to same typo-induced bugs later! $M = 1000000.; $K = 1000.; $n = 0; foreach $file (@ARGV) { open(FD, $file) || die "$0: can't open $file"; $file =~ s/\.\d+$//; @_ = split(/\//, $file); push(@host, $_[$#_]); $file = $_[$#_ - 1]; $file =~ s|/|-|; push(@file, $file); $mhz = 0; while () { chop; next if m|scripts/lmbench: /dev/tty|; if (/^\[lmbench/) { push(@uname, $_); if (/lmbench1\./) { $version = 1; } else { $version = 2; } } if (/MHZ/ && !$mhz) { @_ = split; $_[1] =~ s/\]//; push(@misc_mhz, $_[1]); $mhz = 1; } elsif (/Mhz/ && !$mhz) { @_ = split; push(@misc_mhz, $_[0]); $mhz = 1; } if (/^Select on 100 fd/) { @_ = split; push(@lat_select, $_[4]); } if (/^Select on 100 tcp fd/) { @_ = split; push(@lat_tcp_select, $_[5]); } if (/^Simple syscall:/) { @_ = split; push(@lat_syscall, $_[2]); } if (/^Simple read:/) { @_ = split; push(@lat_read, $_[2]); } if (/^Simple write:/) { @_ = split; push(@lat_write, $_[2]); } if (/^Simple stat:/) { @_ = split; push(@lat_stat, $_[2]); } if (/^Simple open.close:/) { @_ = split; push(@lat_openclose, $_[2]); } if (/^Null syscall:/) { # Old format. @_ = split; push(@lat_write, $_[2]); } if (/^Signal handler installation:/) { @_ = split; push(@lat_siginstall, $_[3]); } if (/^Signal handler overhead:/) { @_ = split; push(@lat_sigcatch, $_[3]); } if (/^Protection fault:/) { @_ = split; push(@lat_protfault, $_[2]); } if (/^Pipe latency:/) { @_ = split; push(@lat_pipe, $_[2]); } if (/AF_UNIX sock stream latency:/) { @_ = split; push(@lat_unix, $_[4]); } if (/UDP latency using localhost:/) { @_ = split; push(@lat_udp_local, $_[4]); } if (/TCP latency using localhost/) { @_ = split; push(@lat_tcp_local, $_[4]); } if (/RPC.udp latency using localhost/) { @_ = split; push(@lat_rpc_udp_local, $_[4]); } if (/RPC.tcp latency using localhost/) { @_ = split; push(@lat_rpc_tcp_local, $_[4]); } if (/TCP.IP connection cost to localhost:/) { @_ = split; push(@lat_tcp_connect_local, $_[5]); } if (/^Socket bandwidth using localhost:/) { @_ = split; push(@bw_tcp_local, $_[4]); } if (/^AF_UNIX sock stream bandwidth:/) { @_ = split; push(@bw_unix, $_[4]); } if (/^Process fork.exit/) { @_ = split; push(@lat_nullproc, $_[2]); } if (/^Process fork.execve:/) { @_ = split; push(@lat_simpleproc, $_[2]); } if (/^Process fork..bin.sh/) { @_ = split; push(@lat_shproc, $_[3]); } if (/^Pipe bandwidth/) { @_ = split; push(@bw_pipe, $_[2]); } if (/^File .* write bandwidth/) { @_ = split; $bw = sprintf("%.2f", $_[4] / 1024.); push(@bw_file, $bw); } if (/^Pagefaults on/) { @_ = split; push(@lat_pagefault, $_[3]); } if (/^"mappings/) { $value = &getbiggest("memory mapping timing"); push(@lat_mappings, $value); } if (/^"read bandwidth/) { $value = &getbiggest("reread timing"); push(@bw_reread, $value); } if (/^"Mmap read bandwidth/) { $value = &getbiggest("mmap reread timing"); push(@bw_mmap, $value); } if (/^"libc bcopy unaligned/) { $value = &getbiggest("libc bcopy timing"); push(@bw_bcopy_libc, $value); } if (/^"unrolled bcopy unaligned/) { $value = &getbiggest("unrolled bcopy timing"); push(@bw_bcopy_unrolled, $value); } if (/^Memory read/) { $value = &getbiggest("memory read & sum timing"); push(@bw_mem_rdsum, $value); } if (/^Memory write/) { $value = &getbiggest("memory write timing"); push(@bw_mem_wr, $value); } if (/^"File system latency/) { while () { next if /Id:/; if (/^0k/) { @_ = split; push(@fs_create_0k, $_[2]); push(@fs_delete_0k, $_[3]); } elsif (/^1k/) { @_ = split; push(@fs_create_1k, $_[2]); push(@fs_delete_1k, $_[3]); } elsif (/^4k/) { @_ = split; push(@fs_create_4k, $_[2]); push(@fs_delete_4k, $_[3]); } elsif (/^10k/) { @_ = split; push(@fs_create_10k, $_[2]); push(@fs_delete_10k, $_[3]); } else { last; } } } if (/size=0/) { while () { if (/^2 /) { @_ = split; push(@lat_ctx0_2, $_[1]); } elsif (/^8 /) { @_ = split; push(@lat_ctx0_8, $_[1]); } elsif (/^16 /) { @_ = split; push(@lat_ctx0_16, $_[1]); } last if /^\s*$/ || /^Memory/; } } if (/size=16/) { while () { if (/^2 /) { @_ = split; push(@lat_ctx16_2, $_[1]); } elsif (/^8 /) { @_ = split; push(@lat_ctx16_8, $_[1]); } elsif (/^16 /) { @_ = split; push(@lat_ctx16_16, $_[1]); } last if /^\s*$/; } } if (/size=64/) { while () { if (/^2 /) { @_ = split; push(@lat_ctx64_2, $_[1]); } elsif (/^8 /) { @_ = split; push(@lat_ctx64_8, $_[1]); } elsif (/^16 /) { @_ = split; push(@lat_ctx64_16, $_[1]); } last if /^\s*$/ || /^20/; } } if (/^"stride=128/) { $save = -1; while () { if (/^\s*$/) { last; } @_ = split; $size = $_[0]; $save = $_[1]; if ($size == 0.00098) { push(@lat_l1, $_[1]); } elsif ($size == 0.12500) { push(@lat_l2, $_[1]); } } if ($size < 8.0) { warn "$file: No 8MB memory latency, using $size\n"; } push(@lat_mem, $save); } } @warn = (); foreach $array ( 'bw_bcopy_libc', 'bw_bcopy_unrolled', 'bw_file', 'bw_mem_rdsum', 'bw_mem_wr', 'bw_mmap', 'bw_pipe', 'bw_reread', 'bw_tcp_local', 'bw_unix', 'fs_create_0k', 'fs_create_10k', 'fs_delete_0k', 'fs_delete_10k', 'lat_ctx0_16', 'lat_ctx0_2', 'lat_ctx0_8', 'lat_ctx16_16', 'lat_ctx16_2', 'lat_ctx16_8', 'lat_ctx64_16', 'lat_ctx64_2', 'lat_ctx64_8', 'lat_l1', 'lat_l2', 'lat_mappings', 'lat_mem', 'lat_nullproc', 'lat_openclose', 'lat_pagefault', 'lat_pipe', 'lat_protfault', 'lat_read', 'lat_rpc_tcp_local', 'lat_rpc_udp_local', 'lat_select', 'lat_tcp_select', 'lat_shproc', 'lat_sigcatch', 'lat_siginstall', 'lat_simpleproc', 'lat_stat', 'lat_syscall', 'lat_tcp_connect_local', 'lat_tcp_local', 'lat_udp_local', 'lat_unix', 'lat_write', 'misc_mhz', ) { $last = eval '$#' . $array; if ($last != $n) { #warn "No data for $array in $file\n"; push(@warn, $array); eval 'push(@' . $array . ', -1);'; } } if ($#warn != -1) { warn "Missing data in $file: @warn\n"; } $n++; } print< LMBENCH 2.0 SUMMARY

Basic system parameters

EOF for ($i = 0; $i <= $#uname; $i++) { printf "", $host[$i], &getos($uname[$i]), $file[$i]; printf "
HostOS DescriptionMhz
%-9.9s %13.13s %23.23s%4.4s
", $misc_mhz[$i], 0; } print<Processor, Processes - times in microseconds - smaller is better

EOF @fs_delete_4k = @lat_ctx0_8 = @bw_file = @lat_ctx0_16 = @fs_delete_1k = @fs_create_4k = @fs_create_1k if 0; # lint for ($i = 0; $i <= $#uname; $i++) { # If they have no /dev/zero, use /dev/null, else average them. if ($lat_read[$i] == -1) { $tmp = $lat_write[$i]; } else { $tmp = ($lat_read[$i] + $lat_write[$i]) / 2; } printf "", $host[$i], &getos($uname[$i]); printf "
Host OS Mhz null call null I/O stat open close selct TCP sig inst sig hadl fork proc exec proc sh proc
%-9.9s %13.13s%4.0f %4.4s %4.4s %4.4s %4.4s %5.5s %4.4s %4.4s %4.4s %4.4s %4.4s
", $misc_mhz[$i], &num($lat_syscall[$i], 4), &num($tmp, 4), &num($lat_stat[$i], 4), &num($lat_openclose[$i], 4), &num($lat_tcp_select[$i], 5), &num($lat_siginstall[$i], 4), &num($lat_sigcatch[$i], 4), &num($lat_nullproc[$i], 4), &num($lat_simpleproc[$i], 4), &num($lat_shproc[$i], 4), 0; } print<Context switching - times in microseconds - smaller is better EOF for ($i = 0; $i <= $#uname; $i++) { printf "", $host[$i], &getos($uname[$i]); printf "
Host OS 2p/0K ctxsw 2p/16K ctxsw 2p/64K ctxsw 8p/16K ctxsw 8p/64K ctxsw 16p/16K ctxsw 16p/64K ctxsw
%-9.9s%13.13s%5.5s%6.6s%6.6s%6.6s %6.6s%7.7s%7.7s
", &num($lat_ctx0_2[$i], 5), &num($lat_ctx16_2[$i], 6), &num($lat_ctx64_2[$i], 6), &num($lat_ctx16_8[$i], 6), &num($lat_ctx64_8[$i], 6), &num($lat_ctx16_16[$i], 7), &num($lat_ctx64_16[$i], 7), 0; } print<*Local* Communication latencies in microseconds - smaller is better EOF for ($i = 0; $i <= $#uname; $i++) { printf "", $host[$i], &getos($uname[$i]); printf "
Host OS 2p/0K ctxsw Pipe AF UNIX UDP RPC/UDP TCP RPC/TCP TCP conn
%-9.9s%13.13s%5s%5s%4s%5s%5s%5s%5s%4s
", &num($lat_ctx0_2[$i], 5), &num($lat_pipe[$i], 5), &num($lat_unix[$i], 4), &num($lat_udp_local[$i], 5), &num($lat_rpc_udp_local[$i], 5), &num($lat_tcp_local[$i], 5), &num($lat_rpc_tcp_local[$i], 5), &num($lat_tcp_connect_local[$i], 4), 0; } print<File & VM system latencies in microseconds - smaller is better EOF for ($i = 0; $i <= $#uname; $i++) { printf "", $host[$i], &getos($uname[$i]); $c0k = $fs_create_0k[$i] <= 0 ? -1 : $M / $fs_create_0k[$i]; $c10k = $fs_create_10k[$i] <= 0 ? -1 : $M / $fs_create_10k[$i]; $d0k = $fs_delete_0k[$i] <= 0 ? -1 : $M / $fs_delete_0k[$i]; $d10k = $fs_delete_10k[$i] <= 0 ? -1 : $M / $fs_delete_10k[$i]; printf "
Host OS 0K File
Create/Delete
10K File
Create/Delete
Mmap Latency Prot Fault Page Fault
%-9.9s %13.13s%6.6s / %6.6s%6.6s / %6.6s%8.8s%5.5s%7.7s
", &num($c0k, 6), &num($d0k, 6), &num($c10k, 6), &num($d10k, 6), &num($lat_mappings[$i], 8), &num($lat_protfault[$i], 5), &num($lat_pagefault[$i], 7), 0; } print<*Local* Communication bandwidths in MB/s - bigger is better EOF for ($i = 0; $i <= $#uname; $i++) { printf "
Host OS Pipe AF UNIX TCP File reread Mmap reread Bcopy (libc) Bcopy (hand) Mem read Mem write
%-9.9s%13.13s ", $host[$i], &getos($uname[$i]); printf "%4.4s%4.4s%4.4s%6.6s%6.6s%6.6s%6.6s%4.4s%5.5s
", &num($bw_pipe[$i], 4), &num($bw_unix[$i], 4), &num($bw_tcp_local[$i], 4), &num($bw_reread[$i], 6), &num($bw_mmap[$i], 6), &num($bw_bcopy_libc[$i], 6), &num($bw_bcopy_unrolled[$i], 6), &num($bw_mem_rdsum[$i], 4), &num($bw_mem_wr[$i], 5); } print<Memory latencies in nanoseconds - smaller is better

(WARNING - may not be correct, check graphs)

EOF for ($i = 0; $i <= $#uname; $i++) { printf "", $host[$i], &getos($uname[$i]), $misc_mhz[$i]; $msg = &check_caches; if ($lat_l1[$i] < 0) { printf "", "-", "-", "-", "Bad mhz?"; } else { printf ""; } print "
Host OS Mhz L1 \$ L2 \$ Main mem Guesses
%-9.9s%13.13s%4d%6s %6s %11s%s%5.5s%6.6s%6.6s", &num($lat_l1[$i], 5), &num($lat_l2[$i], 6), &num($lat_mem[$i], 6); print $msg if ($msg =~ /L/); print "
"; } exit 0; # (33, %3d) sub num { local($val, $len) = @_; local($str) = ""; local($i); if ($val <= 0) { $str = ""; for ($i = 0; $i < $len; $i++) { $str .= " "; } return ($str); } if ($val >= 10 * $M) { $nstr = sprintf("%.1f", $val / $M); $fmt = sprintf("%%%d.%ds%%s", $len - 1, $len - 1); $str = sprintf($fmt, $nstr, "M"); } elsif ($val >= 10 * $K) { $nstr = sprintf("%.1f", $val / $K); $fmt = sprintf("%%%d.%ds%%s", $len - 1, $len - 1); $str = sprintf($fmt, $nstr, "K"); } elsif ($val >= 10) { $nstr = sprintf("%.1f", $val); $fmt = sprintf("%%%d.%ds", $len, $len); $str = sprintf($fmt, $nstr); } else { $fmt = sprintf("%%%d.%df", $len, $len - 2); $str = sprintf($fmt, $val); } $str; } # Input looks like # "benchmark name # size value # .... # # # Return the biggest value before the blank line. sub getbiggest { local($msg) = @_; local($line) = 0; undef $save; $value = 0; while () { $line++; #warn "$line $_"; last if /^\s*$/; $save = $_ if /^\d+\./; } if (defined $save) { $_ = $save; @d = split; $value = $d[1]; if (int($d[0]) < 4) { warn "$file: using $d[0] size for $msg\n"; } } else { warn "$file: no data for $msg\n"; } $value; } # Try and create sensible names from uname -a output sub getos { local(@info); @info = split(/\s+/, $_[0]); "$info[3] $info[5]"; } # Return true if the values differe by less than 10% sub same { local($a, $b) = @_; if ($a > $b) { $percent = (($a - $b) / $a) * 100; } else { $percent = (($b - $a) / $b) * 100; } return ($percent <= 20); } sub check_caches { if (!&same($lat_l1[$i], $lat_l2[$i]) && &same($lat_l2[$i], $lat_mem[$i])) { " No L2 cache?"; } elsif (&same($lat_l1[$i], $lat_l2[$i])) { " No L1 cache?"; } }