#! /bin/sh
#
############################################################
# X11perfcompDR version 1.01
#
# Usage: x11perfcompDR  datafile  reference_datafile
#
# X11perfcompDR  --  Creates a Digital Review compatible breakdown of 
# x11perf v1.2 results as described in "Take Your Pick Of Graphics"
# by John Montgomery, Digital Review, May 7th, 1990, Page 44. 
#
# X11perfcompDR was written by Lonnie Mandigo (lonnie@hp-pcd.cv.hp.com).
#
# DISCLAIMER: This shell script is an interpretation of techniques
# for massaging x11perf results as described in the aforementioned
# Digital Review article. This shell script was not written by
# Digital Review nor is it necessarily sanctioned by them. 
############################################################
# CHANGE HISTORY:
#
# 8/30/90  v1.0 program created by Lonnie Mandigo 
# 1/18/91  Modification by  Lonnie Mandigo
#	   Fixed a bug to include UCIRC in data.
# 2/5/91   Modification by  Lonnie Mandigo
#          Now removes sum.tmp file when finished.
# 3/18/91  v1.01 Increased resolution to handle zero ratios.
#          Minor aesethic cleanups and better error handling.
#          Lonnie Mandigo and Jason Levitt (jason@cs.utexas.edu)
#
############################################################
# Copyright (c) 1991 by Hewlett-Packard Company
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both the copyright notice and this permission
# notice appear in supporting documentation, and that the name of
# Hewlett-Packard not be used in advertising or publicity 
# pertaining to distribution of the software without specific, 
# written prior permission.
#
############################################################
# Instructions:
# 
# Usage: x11perfcompDR  datafile  reference_datafile
#
# The x11perf data files, datafile and reference_datafile,
# are created by running x11perf version 1.2  with the "-all" flag:
#
#      x11perf -display grunt:0.0 -all > datafile
#      x11perf -display oxcart:0.0 -all > reference_datafile
#
# x11perfcompDR summarizes the results relative to the data
# contained in reference_datafile. x11perfcompDR writes to
# standard out, so if you want to capture the output in a
# file, use:
# 
#  x11perfcompDR  datafile  reference_datafile > output.comp
#
# The output.comp contains summaries of the x11perf results
# as described in the DR article. X11perfcompDR does not calculate 
# the jackknife value, scaled  residuals, or 95% confidence interval 
# mentioned in DR. 
#
############################################################
# Notes on interpreting standard deviation (STD) and variance:
#
# If you look at one of the test categories and the STD is high
# then that probably means that, for one or more tests that
# went into that catagory, one of the systems had dramatically
# different performance than the other system. Examine the
# DETAILS section for that category and locate the places where
# the ratios seem unusually large. Then compare the raw x11perf
# data that are used to calculate those ratios to determine which 
# tests are throwing off the results. Unusually high isolated
# test results are usually caused by specialized hardware 
# support, tricky software, or possibly a bug. Consult your vendor
# for details.
# 
# If the STD is low for a category, then all tests for one 
# system ran fairly uniformly faster (or slower) than the 
# other system. 
# 
# What constitutes a "high" or "low" STD will vary somewhat depending
# on the software and hardware used, and the testing configuration.
# jason@cs.utexas.edu: "For X terminals circa 1991, I've found that 
# a STD less than one is low and an STD greater than 5 is high. 
# Your mileage may vary. The 4/1/91 issue of Unix Today! compares
# the performance of ten X terminals using x11perfcompDR."
#
# The variance is just the STD squared, and is included mainly
# for compatibility with the DR article.
#
############################################################
############################################################
############################################################
############################################################
# stdform() - Converts the averages to standard form.
#
# $1 - Input file

stdform()
{
    cat > awkfile.$$ <<-'EOS'
	BEGIN {
	    longName["Dot"] = "DOT:1";
	    longName["1x1 rectangle"] = "1RECT:1";
	    longName["10x10 rectangle"] = "RECT:1";
	    longName["100x100 rectangle"] = "RECT:1";
	    longName["500x500 rectangle"] = "5RECT:1";
	    longName["1x1 stippled rectangle"] = "1SRECT:1";
	    longName["10x10 stippled rectangle"] = "SRECT:1";
	    longName["100x100 stippled rectangle"] = "SRECT:1";
	    longName["500x500 stippled rectangle"] = "5SRECT:1";
	    longName["1x1 opaque stippled rectangle"] = "1OSREC:1";
	    longName["10x10 opaque stippled rectangle"] = "OSRECT:1";
	    longName["100x100 opaque stippled rectangle"] = "OSRECT:1";
	    longName["500x500 opaque stippled rectangle"] = "5OSREC:1";
	    longName["1x1 4x4 tiled rectangle"] = "1TREC1:1";
	    longName["10x10 4x4 tiled rectangle"] = "TRECT1:1";
	    longName["100x100 4x4 tiled rectangle"] = "TRECT1:1";
	    longName["500x500 4x4 tiled rectangle"] = "5TREC1:1";
	    longName["1x1 161x145 tiled rectangle"] = "1TREC2:1";
	    longName["10x10 161x145 tiled rectangle"] = "TRECT2:1";
	    longName["100x100 161x145 tiled rectangle"] = "TRECT2:1";
	    longName["500x500 161x145 tiled rectangle"] = "5TREC2:1";
	    longName["1-pixel line segment"] = "1SEG1:1";
	    longName["10-pixel line segment"] = "SEG1:1";
	    longName["100-pixel line segment"] = "SEG1:1";
	    longName["500-pixel line segment"] = "5SEG1:1";
	    longName["100-pixel line segment (1 kid)"] = "SEG2:1";
	    longName["100-pixel line segment (2 kids)"] = "SEG2:1";
	    longName["100-pixel line segment (3 kids)"] = "SEG2:1";
	    longName["10-pixel dashed segment"] = "DSEG:1";
	    longName["100-pixel dashed segment"] = "DSEG:1";
	    longName["100-pixel double-dashed segment"] = "DDSEG:1";
	    longName["1-pixel line"] = "1LINE:1";
	    longName["10-pixel line"] = "LINE:1";
	    longName["100-pixel line"] = "LINE:1";
	    longName["500-pixel line"] = "5LINE:1";
	    longName["10-pixel dashed line"] = "DLINE:1";
	    longName["100-pixel dashed line"] = "DLINE:1";
	    longName["100-pixel double-dashed line"] = "DDLINE:1";
	    longName["10x1 wide line"] = "WLINE:1";
	    longName["100x10 wide line"] = "WLINE:1";
	    longName["500x50 wide line"] = "5WLINE:1";
	    longName["100x10 wide dashed line"] = "WDLINE:1";
	    longName["100x10 wide double-dashed line"] = "WDDLIN:1";
	    longName["1-pixel circle"] = "1CIRC:1";
	    longName["10-pixel circle"] = "CIRCLE:1";
	    longName["100-pixel circle"] = "CIRCLE:1";
	    longName["500-pixel circle"] = "5CIRC:1";
	    longName["100-pixel dashed circle"] = "DCIRC:1";
	    longName["100-pixel double-dashed circle"] = "DDCIRC:1";
	    longName["10-pixel wide circle"] = "WCIRC:1";
	    longName["100-pixel wide circle"] = "WCIRC:1";
	    longName["500-pixel wide circle"] = "5WCIRC:1";
	    longName["100-pixel wide dashed circle"] = "WDCIRC:1";
	    longName["100-pixel wide double-dashed circle"] = "WDDCIR:1";
	    longName["10-pixel partial circle"] = "PARCIR:1";
	    longName["100-pixel partial circle"] = "PARCIR:1";
	    longName["1-pixel solid circle"] = "1SOLCI:1";
	    longName["10-pixel solid circle"] = "SOLCIR:1";
	    longName["100-pixel solid circle"] = "SOLCIR:1";
	    longName["500-pixel solid circle"] = "5SOLCI:1";
	    longName["10-pixel fill chord partial circle"] = "FCPCIR:1";
	    longName["100-pixel fill chord partial circle"] = "FCPCIR:1";
	    longName["10-pixel fill slice partial circle"] = "FSPCIR:1";
	    longName["100-pixel fill slice partial circle"] = "FSPCIR:1";
	    longName["10-pixel ellipse"] = "ELLIPS:1";
	    longName["100-pixel ellipse"] = "ELLIPS:1";
	    longName["500-pixel ellipse"] = "5ELLIP:1";
	    longName["100-pixel dashed ellipse"] = "DELLIP:1";
	    longName["100-pixel double-dashed ellipse"] = "DDELLI:1";
	    longName["10-pixel wide ellipse"] = "WELLIP:1";
	    longName["100-pixel wide ellipse"] = "WELLIP:1";
	    longName["500-pixel wide ellipse"] = "5WELLI:1";
	    longName["100-pixel wide dashed ellipse"] = "WDELLI:1";
	    longName["100-pixel wide double-dashed ellipse"] = "WDDELL:1";
	    longName["10-pixel partial ellipse"] = "PELLIP:1";
	    longName["100-pixel partial ellipse"] = "PELLIP:1";
	    longName["10-pixel filled ellipse"] = "FELLIP:1";
	    longName["100-pixel filled ellipse"] = "FELLIP:1";
	    longName["500-pixel filled ellipse"] = "5FELLI:1";
	    longName["10-pixel fill chord partial ellipse"] = "FCELLI:1";
	    longName["100-pixel fill chord ellipse"] = "FCELLI:1";
	    longName["10-pixel fill slice partial ellipse"] = "FSELLI:1";
	    longName["100-pixel fill slice ellipse"] = "FSELLI:1";
	    longName["Fill 1-pixel/side triangle"] = "1TRIAN:1";
	    longName["Fill 10-pixel/side triangle"] = "TRIANG:1";
	    longName["Fill 100-pixel/side triangle"] = "TRIANG:1";
	    longName["Fill 10x10 trapezoid"] = "TRAP:1";
	    longName["Fill 100x100 trapezoid"] = "TRAP:1";
	    longName["Fill 10x10 stippled trapezoid"] = "STRAP:1";
	    longName["Fill 100x100 stippled trapezoid"] = "STRAP:1";
	    longName["Fill 10x10 opaque stippled trapezoid"] = "OSTRAP:1";
	    longName["Fill 100x100 opaque stippled trapezoid"] = "OSTRAP:1";
	    longName["Fill 10x10 tiled trapezoid"] = "TTRAP:1";
	    longName["Fill 100x100 tiled trapezoid"] = "TTRAP:1";
	    longName["Fill 10-pixel/side complex polygon"] = "CPOLY:1";
	    longName["Fill 100-pixel/side complex polygons"] = "CPOLY:1";
	    longName["Char in 80-char line (6x13)"] = "TEXT1:2";
	    longName["Char in 80-char line (TR 10)"] = "TEXT1:2";
	    longName["Char in 30-char line (TR 24)"] = "TEXT1:2";
	    longName["Char in 20/40/20 line (6x13, TR 10)"] = "TEXT1:2";
	    longName["Char in 80-char image line (6x13)"] = "TEXT2:2";
	    longName["Char in 80-char image line (TR 10)"] = "TEXT2:2";
	    longName["Char in 30-char image line (TR 24)"] = "TEXT2:2";
	    longName["Scroll 10x10 pixels"] = "SCROLL:2";
	    longName["Scroll 100x100 pixels"] = "SCROLL:2";
	    longName["Scroll 500x500 pixels"] = "5SCROL:2";
	    longName["Copy 10x10 from window to window"] = "CPWTOW:3";
	    longName["Copy 100x100 from window to window"] = "CPWTOW:3";
	    longName["Copy 500x500 from window to window"] = "5CPWTW:3";
	    longName["Copy 10x10 from pixmap to window"] = "CPPTOW:3";
	    longName["Copy 100x100 from pixmap to window"] = "CPPTOW:3";
	    longName["Copy 500x500 from pixmap to window"] = "5CPPTW:3";
	    longName["Copy 10x10 from window to pixmap"] = "CPWTOP:3";
	    longName["Copy 100x100 from window to pixmap"] = "CPWTOP:3";
	    longName["Copy 500x500 from window to pixmap"] = "5CPWTP:3";
	    longName["Copy 10x10 from pixmap to pixmap"] = "CPPTOP:3";
	    longName["Copy 100x100 from pixmap to pixmap"] = "CPPTOP:3";
	    longName["Copy 500x500 from pixmap to pixmap"] = "5CPPTP:3";
	    longName["Copy 10x10 1-bit deep plane"] = "CPPLAN:3";
	    longName["Copy 100x100 1-bit deep plane"] = "CPPLAN:3";
	    longName["Copy 500x500 1-bit deep plane"] = "5CPPLA:3";
	    longName["PutImage 10x10 square"] = "PUTIMA:3";
	    longName["PutImage 100x100 square"] = "PUTIMA:3";
	    longName["PutImage 500x500 square"] = "5PUTIM:3";
	    longName["GetImage 10x10 square"] = "GETIMA:3";
	    longName["GetImage 100x100 square"] = "GETIMA:3";
	    longName["GetImage 500x500 square"] = "5GETIM:3";
	    longName["X protocol NoOperation"] = "NOOP:4";
	    longName["GetAtomName"] = "ATOM:4";
	    longName["GetProperty"] = "GETPRO:4";
	    longName["Change graphics context"] = "CGC:4";
	    longName["Create and map subwindows (4 kids)"] = "CMSUB:4";
	    longName["Create and map subwindows (16 kids)"] = "CMSUB:4";
	    longName["Create and map subwindows (25 kids)"] = "CMSUB:4";
	    longName["Create and map subwindows (50 kids)"] = "CMSUB:4";
	    longName["Create and map subwindows (75 kids)"] = "CMSUB:4";
	    longName["Create and map subwindows (100 kids)"] = "CMSUB:4";
	    longName["Create and map subwindows (200 kids)"] = "CMSUB:4";
	    longName["Create unmapped window (4 kids)"] = "CUNMAP:4";
	    longName["Create unmapped window (16 kids)"] = "CUNMAP:4";
	    longName["Create unmapped window (25 kids)"] = "CUNMAP:4";
	    longName["Create unmapped window (50 kids)"] = "CUNMAP:4";
	    longName["Create unmapped window (75 kids)"] = "CUNMAP:4";
	    longName["Create unmapped window (100 kids)"] = "CUNMAP:4";
	    longName["Create unmapped window (200 kids)"] = "CUNMAP:4";
	    longName["Map window via parent (4 kids)"] = "MAP:4";
	    longName["Map window via parent (16 kids)"] = "MAP:4";
	    longName["Map window via parent (25 kids)"] = "MAP:4";
	    longName["Map window via parent (50 kids)"] = "MAP:4";
	    longName["Map window via parent (75 kids)"] = "MAP:4";
	    longName["Map window via parent (100 kids)"] = "MAP:4";
	    longName["Map window via parent (200 kids)"] = "MAP:4";
	    longName["Unmap window via parent (4 kids)"] = "UMAP:4";
	    longName["Unmap window via parent (16 kids)"] = "UMAP:4";
	    longName["Unmap window via parent (25 kids)"] = "UMAP:4";
	    longName["Unmap window via parent (50 kids)"] = "UMAP:4";
	    longName["Unmap window via parent (75 kids)"] = "UMAP:4";
	    longName["Unmap window via parent (100 kids)"] = "UMAP:4";
	    longName["Unmap window via parent (200 kids)"] = "UMAP:4";
	    longName["Destroy window via parent (4 kids)"] = "DESTR:4";
	    longName["Destroy window via parent (16 kids)"] = "DESTR:4";
	    longName["Destroy window via parent (25 kids)"] = "DESTR:4";
	    longName["Destroy window via parent (50 kids)"] = "DESTR:4";
	    longName["Destroy window via parent (75 kids)"] = "DESTR:4";
	    longName["Destroy window via parent (100 kids)"] = "DESTR:4";
	    longName["Destroy window via parent (200 kids)"] = "DESTR:4";
	    longName["Hide/expose window via popup (4 kids)"] = "POPUP:4";
	    longName["Hide/expose window via popup (16 kids)"] = "POPUP:4";
	    longName["Hide/expose window via popup (25 kids)"] = "POPUP:4";
	    longName["Hide/expose window via popup (50 kids)"] = "POPUP:4";
	    longName["Hide/expose window via popup (75 kids)"] = "POPUP:4";
	    longName["Hide/expose window via popup (100 kids)"] = "POPUP:4";
	    longName["Hide/expose window via popup (200 kids)"] = "POPUP:4";
	    longName["Move window (4 kids)"] = "MOVE:4";
	    longName["Move window (16 kids)"] = "MOVE:4";
	    longName["Move window (25 kids)"] = "MOVE:4";
	    longName["Move window (50 kids)"] = "MOVE:4";
	    longName["Move window (75 kids)"] = "MOVE:4";
	    longName["Move window (100 kids)"] = "MOVE:4";
	    longName["Move window (200 kids)"] = "MOVE:4";
	    longName["Moved unmapped window (4 kids)"] = "UMOVE:4";
	    longName["Moved unmapped window (16 kids)"] = "UMOVE:4";
	    longName["Moved unmapped window (25 kids)"] = "UMOVE:4";
	    longName["Moved unmapped window (50 kids)"] = "UMOVE:4";
	    longName["Moved unmapped window (75 kids)"] = "UMOVE:4";
	    longName["Moved unmapped window (100 kids)"] = "UMOVE:4";
	    longName["Moved unmapped window (200 kids)"] = "UMOVE:4";
	    longName["Move window via parent (4 kids)"] = "MOVPAR:4";
	    longName["Move window via parent (16 kids)"] = "MOVPAR:4";
	    longName["Move window via parent (25 kids)"] = "MOVPAR:4";
	    longName["Move window via parent (50 kids)"] = "MOVPAR:4";
	    longName["Move window via parent (75 kids)"] = "MOVPAR:4";
	    longName["Move window via parent (100 kids)"] = "MOVPAR:4";
	    longName["Move window via parent (200 kids)"] = "MOVPAR:4";
	    longName["Resize window (4 kids)"] = "RESIZ:4";
	    longName["Resize window (16 kids)"] = "RESIZ:4";
	    longName["Resize window (25 kids)"] = "RESIZ:4";
	    longName["Resize window (50 kids)"] = "RESIZ:4";
	    longName["Resize window (75 kids)"] = "RESIZ:4";
	    longName["Resize window (100 kids)"] = "RESIZ:4";
	    longName["Resize window (200 kids)"] = "RESIZ:4";
	    longName["Resize unmapped window (4 kids)"] = "URESIZ:4";
	    longName["Resize unmapped window (16 kids)"] = "URESIZ:4";
	    longName["Resize unmapped window (25 kids)"] = "URESIZ:4";
	    longName["Resize unmapped window (50 kids)"] = "URESIZ:4";
	    longName["Resize unmapped window (75 kids)"] = "URESIZ:4";
	    longName["Resize unmapped window (100 kids)"] = "URESIZ:4";
	    longName["Resize unmapped window (200 kids)"] = "URESIZ:4";
	    longName["Circulate window (4 kids)"] = "CIRC:4";
	    longName["Circulate window (16 kids)"] = "CIRC:4";
	    longName["Circulate window (25 kids)"] = "CIRC:4";
	    longName["Circulate window (50 kids)"] = "CIRC:4";
	    longName["Circulate window (75 kids)"] = "CIRC:4";
	    longName["Circulate window (100 kids)"] = "CIRC:4";
	    longName["Circulate window (200 kids)"] = "CIRC:4";
	    longName["Circulate Unmapped window (4 kids)"] = "UCIRC:4";
	    longName["Circulate Unmapped window (16 kids)"] = "UCIRC:4";
	    longName["Circulate Unmapped window (25 kids)"] = "UCIRC:4";
	    longName["Circulate Unmapped window (50 kids)"] = "UCIRC:4";
	    longName["Circulate Unmapped window (75 kids)"] = "UCIRC:4";
	    longName["Circulate Unmapped window (100 kids)"] = "UCIRC:4";
	    longName["Circulate Unmapped window (200 kids)"] = "UCIRC:4";
	}
	{
	    reps = $1;				# get repetitions
	    time = $4;				# get time / operation
	    split($0,parts,":");		# get name
	    name = parts[2];
	    while (substr(name,1,1) == " ") {	# remove leading spaces
		name = substr(name,2,length(name));
	    }

	    printf("%s:%d:",longName[name],NR);	# output in new format
	    printf("%d:",reps);
	    printf("%8.4f\n",time);
	}
EOS
    awk -f awkfile.$$ $1
    rm -f awkfile.$$				# cleanup
}						# stdform()

############################################################
# get500s() - Extracts the 500 pixel operations
#
# $1 - Input file

get500s() 
{
    awk -F: '					# extract the lines
	{
	    name = $1;
	    category = $2;
	    ord = $3;
	    reps = $4;
	    time = $5;

	    if (substr(name,1,1) == "5") {
		printf("%s:",name);
		printf("%d:",category);
	 	printf("%d:",ord);
		printf("%d:",reps);
		printf("%.8g\n",1000/time);
	    }
	}' $1	
}						# get500s()

############################################################
# get1s() - Extracts the 1 pixel operations
#
# $1 - Input file

get1s() 
{
    awk -F: '					# extract the lines
	{
	    name = $1;
	    category = $2;
	    ord = $3;
	    reps = $4;
	    time = $5;

	    if (substr(name,1,1) == "1") {
		printf("%s:",name);
		printf("%d:",category);
	 	printf("%d:",ord);
		printf("%d:",reps);
		printf("%.8g\n",1000/time);
	    }
	}' $1	
}						# get1s()

############################################################
# getKernel() - Gets the kernel measurements.
#
# $1 - Input file

getKernel()
{
    awk -F: '
	{
	    name = $1;

	    if ((substr(name,1,1) != "1") && (substr(name,1,1) != "5"))
		print $0;
	} ' $1 |
    awk -F: '
	BEGIN {
	    prevName = "***";
	    logsum = 0;
	    cnt = 0;
	}
	{
	    name = $1;				# get fields
	    category = $2;
	    ord = $3;
	    reps = $4;
	    time = $5;

	    if (name != prevName && prevName != "***") {
		printf("%s:",prevName);
		printf("%d:",c);
	 	printf("%d:",o);
		printf("%d:",r);
		printf("%10.1f\n",  exp(logsum / cnt));

		logsum = 0;
		cnt = 0;
	    }

	    logsum += log( 1000 / time );	# generate log sum
	    cnt++;
	    prevName = name;
	    c = category;
	    r = reps;
	    o = ord;
	}
	END {
	    printf("%s:",prevName);
	    printf("%d:",c);
	    printf("%d:",o);
	    printf("%d:",r);
	    printf("%10.1f\n",  exp(logsum / cnt));
	}
	' -
}						# getKernel()


############################################################
# doRatios() - Calculates the ratios for each of the entries
#
# $1 - datafile
# $2 - reference datafile
#

doRatios() 
{
    sort +0 -1 -t: $1		> DR.JUNK1
    sort +0 -1 -t: $2		> DR.JUNK2
    join -j1 1 -j2 1 -t: DR.JUNK1 DR.JUNK2  |	# join the together
    awk -F: '
	{
	    name = $1;				# get fields
	    cat = $2;
	    ord = $3;
	    count = $4;
	    speed = $5;
	    refcat = $6;
	    reford = $7;
	    refcount = $8;
	    refspeed = $9;


	    printf("%s:",name);
	    printf("%d:",cat);
	    printf("%d:",ord);
	    printf("%s:",speed);
	    printf("%s:",refspeed);
	    printf("%6.16f\n",speed/refspeed);		# print ratio
	} ' -
    rm -f DR.JUNK1 DR.JUNK2				# cleanup
}							# doRatios()

############################################################
# breakout() - Breaks out the data into each of the 
# necessary categories.
#
# $1 - datafile
# $2 - suffix
#

breakout()
{
    DF=$1
    SFX=$2

    grep trep $DF		|		# extract the averages
    stdform -			> avgs.$SFX	# convert to standard form
    get500s avgs.$SFX		> 500s.$SFX	# extract 500 pixel operations
    get1s avgs.$SFX		> 1s.$SFX	# get 1 pixel operations
    getKernel avgs.$SFX		> kernel.$SFX	# extract kernal measurements
    rm -f avgs.$SFX				# cleanup
}						# breakout()

############################################################
# summarize() - Calculates a summary for the specific file
#
# $1 - input file

summarize()
{
    awk -F: '
	BEGIN {
	    cn[1] = "GENERAL GRAPHICS";
	    cn[2] = "TERMINAL EMULATION";
	    cn[3] = "WINDOW MANAGEMENT";
	    cn[4] = "X-SPECIFIC OPERATIONS";
	    sumname = "OVERALL";
	    cnt = 0;
	}
	{
	    name = $1				# get fields
	    cat = $2;
	    ord = $3;
	    speed = $4;
	    refspeed = $5;
	    ratio = $6;

	    if (substr(name,1,1) == "1") {	# its a 1 file
		sumname = "1 OVERALL";
	    }
	    if (substr(name,1,1) == "5") {	# its a 500 file
		sumname = "500 OVERALL";
	    }

	    lsum[cat] += log( speed );		# accumulate sums
	    rlsum[cat] += log( refspeed );
	    ratlsum[cat] += log(ratio);
	    ratl2sum[cat] += ratio * ratio;
	    ratsum[cat] += ratio;
	    ccnt[cat]++;
	    tsum += log( speed );
	    rtsum += log (refspeed);
	    rattsum += log(ratio);
	    ratt2sum += ratio * ratio;
	    ratsumt += ratio;
	    cnt++;
	}
	END {
	    printf("%s:",sumname);
	    printf("%10.2f:",exp(tsum/cnt));
	    printf("%10.2f:",exp(rtsum/cnt));
	    printf("%10.2f:",exp(rattsum/cnt));
	    printf("%10.4f",sqrt((cnt * ratt2sum - (ratsumt * ratsumt)) / (cnt * (cnt - 1))));
	    printf("\n");
	    for (i=1; i<=4; i++) {
		if (ccnt[i] != 0) {
		    printf("%s:",cn[i]);
		    printf("%10.2f:",exp( lsum[i] / ccnt[i]));
		    printf("%10.2f:",exp( rlsum[i] / ccnt[i]));
		    printf("%10.2f:",exp( ratlsum[i] / ccnt[i]));
		    if (ccnt[i] > 1) {
			sum2 = ratsum[i] * ratsum[i];
		    	printf("%10.4f",sqrt( (ccnt[i] * ratl2sum[i] - sum2) / (ccnt[i] * (ccnt[i] - 1))));
		    }
		    else
			printf("%10.4f",0);
		    printf("\n");
		}
	    }
	}
    ' $1
}						# summarize

############################################################
# printout() - Printout the calculated data
#

printout()
{
    echo "x11perf 1.2 Breakdown ala Digital Review"
    echo "----------------------------------------"
    echo "REFERENCE=$REF"
    echo "DATA=$DATA"
    echo
    echo "*** SUMMARY ***"
    sed -n -e '1p' 1s.sum > sum.tmp
    sed -n -e '1p' 500s.sum >> sum.tmp
    cat kernel.sum sum.tmp |
    awk -F: '
	BEGIN {
	    printf("                              Geometric Mean                  of Ratios\n");
	    printf("                      /--------------^---------------\\/----------^---------\\\n");
	    printf("       Test            Reference    Data        Ratio    Variance  Standard\n");
	    printf("       Category        (Ops/sec)  (Ops/Sec)                        Deviation\n");
	    printf("----------------------------------------------------------------------------\n");
	}
	{
	    name = $1;				# get fields
	    datamean = $2;
	    refmean = $3;
	    ratmean = $4;
	    ratstd = $5;

	    printf("%21s ",name);
	    printf("%10.2f ",refmean);
	    printf("%10.2f ",datamean);
	    printf("%10.2f ",ratmean);
	    printf("%10.4f ",ratstd * ratstd);
	    printf("%10.4f ",ratstd);
	    printf("\n");
	}
    ' -

    echo

    cat kernel.sum sum.tmp |		# prints the graph
    awk -F: '
	BEGIN {
	    max = 1;
	    cnt = 0;
	}
	{
	    name[cnt] = $1;
	    ratmean[cnt] = $4;

	    if (max < ratmean[cnt]) max = ratmean[cnt];
	    cnt++;	    
	}
	END {
	    step = max / 55;			# calculate increment
	    for (i=0; i<cnt; i++) {		# step thru categories
		printf("%21s|",name[i]);	# print category name
		for (j=1; j<=55 ; j++) {	# up to and including 55
		    if (j == int((1 / step)))	# the reference value
			printf("|");
		    else if (j>(ratmean[i] / step)) # greater than data value
			printf(" ");
		    else			# less than data value
		        printf("=");
		}
		printf("\n");
	    }
	}
    ' -

    echo
    echo "*** DETAILS ***"
    for i in kernel.detail 1s.detail 500s.detail ; do
        echo
    	sort -t: -n +2 $i	|		# sort to original order
        awk -F: '
    	    BEGIN {
    	    	cn[1] = "GENERAL GRAPHICS";
    	    	cn[2] = "TERMINAL EMULATION";
    	    	cn[3] = "WINDOW MANAGEMENT";
    	    	cn[4] = "X-SPECIFIC OPERATIONS";

		first = 1;
    		
    	    	prevcat = 0;

	    	printf("  Op    Reference    Data        Ratio\n");
	    	printf(" Name   (Ops/Sec)  (Ops/Sec)\n");
	    }
	    {
	    	name = $1;			# get fields
	    	cat = $2;
	    	ord = $3;
	    	speed = $4;
	    	refspeed = $5;
	    	ratio = $6;

		if (first) {
		    first = 0;
		    if (substr(name,1,1) == "1")
			paren = "(1 PIXEL)"
		    else if (substr(name,1,1) == "5")
			paren = "(500 PIXEL)"
		    else
			paren = "";
		}

	    	if (cat != prevcat) {
		    printf("----------------------------------------\n");
		    printf("%s %s\n",cn[cat],paren);
		    printf("----------------------------------------\n");
		    prevcat = cat;
	    	}

	        printf("%6s ",name);			# print data
	        printf("%10.2f ",refspeed);
	        printf("%10.2f ",speed);
	        printf("%10.2f ",ratio);
	        printf("\n");
	   }
    	' - 
    done
    rm sum.tmp						# remove temp file
}							# printout()

############################################################
# deletetmp() - Deletes temporary files. Called by trap.
#
# 
deletetmp()
{
   rm -f kernel.* 500s.* 1s.* avgs.* awkfile* sum.tmp DR.JUNK* 
}

############################################################
# MAIN PROGRAM
############################################################
# Don't print the OVERALL number. It's pretty bogus.
DO_OVERALL=false

# Cleanup on interrupt
trap \
"echo Interrupt: removing temporary files. >& 2 ;deletetmp; exit 1"  1 2 15

# Must have two files specified
if [ "$#" -ne 2 ]
then
	echo "Usage: $0 datafile reference_datafile" >& 2
	exit 1
fi

# Must be ordinary files
if [ ! -f "$1" -o ! -f "$2" ]
then
	echo "Error: data files do not exist or are not ordinary." >& 2
	exit 1
fi

# Should have the same number of results unless something failed.
LC1=`grep trep "$1" | wc -l`
LC2=`grep trep "$2" | wc -l`

if [ "$LC1" -ne "$LC2" ]
then
   	echo "Error: files do not have the same number of results. Check for errors." >& 2
 	exit 1
fi
if [ "$LC1" -ne 222 ]
then
	echo "Warning: $LC1 does not contain 222 results, summaries may be misleading." >& 2
fi
if [ "$LC2" -ne 222 ]
then
	echo "Warning: $LC2 does not contain 222 results, summaries may be misleading." >& 2
fi
 
DATA=$1
REF=$2

breakout $DATA "DR"
breakout $REF "ref"
doRatios kernel.DR kernel.ref		> kernel.detail
doRatios 500s.DR 500s.ref		> 500s.detail
doRatios 1s.DR 1s.ref			> 1s.detail
if $DO_OVERALL 
then
    summarize kernel.detail		> kernel.sum
else
    summarize kernel.detail		|
    grep -v OVERALL 			> kernel.sum
fi
summarize 500s.detail			> 500s.sum
summarize 1s.detail			> 1s.sum
printout
deletetmp

exit 0

