/* s3 virge trace file parser * Copyright (c) Brien Oberstein, 1996 * brien@leland.stanford.edu * */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include #include #include #include #include "vertex.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #define BUFSIZE 4096 /* a line in the trace file may be no longer */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* globals */ const char _dude_[] = "\n\n\n\n The code you're lookin at" " is (c) Copyright Brien Oberstein, Brad Johanson and Stanford University" " 1996\n\n\n\n"; const char *gpsztrace = NULL; FILE *gftrace = NULL; uint gmaxlines = -1; uint gstartframe = 0; uint gendframe = -1; char gfquiet = 0; int gfHtml = 0; /* graph generation toggles */ int makeAreaHistogram = 0; int makeAspectHistogram = 0; int makeHorizHistogram = 0; int makeVertHistogram =0; int makeWRatioHistogram = 0; int makeTriTexHistogram = 0; int makePixelTexHistogram = 0; int makeTexLocalityHistogram = 0; int makeTriFrameHistogram = 0; int makeFrameDepthComplexityHistogram =0; int makeTexChangeFrameHistogram = 0; int makeAreaDotStatistics = 0; int makeWRatioDotStatistics = 0; int makeAverageWDotStatistics = 0; int makeAspectRatioDotStatistics = 0; int makeVerticalExtentDotStatistics = 0; int makeHorizontalExtentDotStatistics = 0; int makeTextureUsedDotStatistics = 0; int makeTriangleTypeDotStatistics = 0; /* statistics */ #define MAXAREA 310000 #define MAXASPECT 1000 #define MAXFRAMES 1000 #define MAXWRATIO 100000 #define MAXTEXTURES 1000 #define MAXVERT 485 #define MAXHORIZ 645 /* untextured/textured triangle stats */ int gctriangles[2]; /* total triangle count */ double gtotalarea[2]; /* total area count */ double gtotalaspect[2]; /* for average aspect ratio */ double gtotalhoriz[2]; /* for average horizontal */ double gtotalvert[2]; /* for total vertical */ double gtotalwratio; /* for average w-ratio */ int gtotaltexchanges; /* total times textures change */ int gcwratio[MAXWRATIO]; /* w-ratio histogram */ int gcarea[MAXAREA][2]; /* tri area histogram */ int gcaspect[MAXASPECT][2]; /* aspect ratio histogram */ int gchoriz[MAXHORIZ][2]; /* horizontal extent histogram */ int gcvert[MAXVERT][2]; /* vertical extent histogram */ double gfarea[MAXFRAMES][2]; /* tri area per frame */ int gftexchange[MAXFRAMES]; /* texture changes per frame */ int gftris[MAXFRAMES][2]; /* triangles per frame */ uint gctexdata[MAXTEXTURES][4]; /* all per tex stats 0=texture ID 1=# of triangles 2=# of pixels 3=# of times tex is selected */ uint gcframes=0; /* total frames */ uint gcrelframes=0; /* frames since stat collection start */ uint gccurrenttex=0; /* index of current texture in tex data array */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int areabucketize(double area) { assert(area >= 0 && area < MAXAREA); return (int)(area+0.5); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void TakeStats(const vertex v[3], int fTexTriangle, int framenumber, int line, FILE *areaDotStat, FILE *wRDotStat, FILE *wAvgDotStat, FILE *aspDotStat, FILE *vertDotStat, FILE *horizDotStat, FILE *texDotStat, FILE *triDotStat) { double a, r, w, h, vert, wAve; /* take stats */ assert(fTexTriangle == 0 || fTexTriangle == 1); ++gctriangles[fTexTriangle]; ++gftris[framenumber][fTexTriangle]; /* area */ a = vtx_area(v); if(makeAreaDotStatistics) fprintf(areaDotStat,"%12.2f\n",a); gtotalarea[fTexTriangle] += a; gfarea[framenumber][fTexTriangle] += a; ++gcarea[areabucketize(a)][fTexTriangle]; /* aspect ration of bounding box */ r = vtx_bbaspect(v); if (!(r >= 0 && r < MAXASPECT)) { fprintf(stderr, "ignoring huge aspect line %-7d r=%f\n", line, r); } else { gtotalaspect[fTexTriangle]+=r; ++gcaspect[(int)r][fTexTriangle]; } /* hoizontal of bounding box */ h = vtx_bbhoriz(v); if (!(h >= 0 && h < MAXHORIZ)) { fprintf(stderr, "ignoring huge horizontal line %-7d r=%f\n", line, h); } else { gtotalhoriz[fTexTriangle]+=h; ++gchoriz[(int)h][fTexTriangle]; } /* vertical of bounding box */ vert = vtx_bbvert(v); if (!(vert >= 0 && vert < MAXVERT)) { fprintf(stderr, "ignoring huge vertical line %-7d r=%f\n", line, vert); } else { gtotalvert[fTexTriangle]+=vert; ++gcvert[(int)vert][fTexTriangle]; } /* w-ratios */ if(fTexTriangle) { w = vtx_wratio(v); wAve = vtx_wave(v); if (!(w >= 0 && w < MAXWRATIO/1000)) { fprintf(stderr, "ignoring huge w-ratio line %-7d r=%f\n", line, w); } else { gtotalwratio+=w; ++gcwratio[(int)(w*1000)]; } } /* texture stuff */ if(fTexTriangle) { ++gctexdata[gccurrenttex][1]; gctexdata[gccurrenttex][2] += a; } /* do dot statistics stuff */ if(fTexTriangle) { if(makeWRatioDotStatistics) fprintf(wRDotStat,"%12.2f\n",w); if(makeAverageWDotStatistics) fprintf(wAvgDotStat,"%12.2f\n",wAve); if(makeTextureUsedDotStatistics) fprintf(texDotStat,"%d\n",gccurrenttex); } if(makeAspectRatioDotStatistics) fprintf(aspDotStat,"%12.2f\n",r); if(makeVerticalExtentDotStatistics) fprintf(vertDotStat,"%12.2f\n",vert); if(makeHorizontalExtentDotStatistics) fprintf(horizDotStat,"%12.2f\n",h); if(makeTriangleTypeDotStatistics) fprintf(triDotStat,"%d\n",fTexTriangle); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Parse the trace file */ static int parse(void) { char buf[BUFSIZE], *p; uint line = 0; FILE *areaDotStat; FILE *wRDotStat; FILE *wAvgDotStat; FILE *aspDotStat; FILE *vertDotStat; FILE *horizDotStat; FILE *texDotStat; FILE *triDotStat; /* s3 state variables */ int fTexTriangle = 0; /* open dot stat files */ if(makeAreaDotStatistics) { areaDotStat=fopen("tri_area.dot","w"); fprintf(areaDotStat,"#Triangle Area\n"); } if(makeWRatioDotStatistics) { wRDotStat=fopen("w_ratio.dot","w"); fprintf(wRDotStat,"#W Ratio\n"); } if(makeAverageWDotStatistics) { wAvgDotStat=fopen("w_average.dot","w"); fprintf(wAvgDotStat,"#Average W\n"); } if(makeAspectRatioDotStatistics) { aspDotStat=fopen("asp_ratio.dot","w"); fprintf(aspDotStat,"#Aspect Ratio\n"); } if(makeVerticalExtentDotStatistics) { vertDotStat=fopen("vertical.dot","w"); fprintf(vertDotStat,"#Vertical Extent\n"); } if(makeHorizontalExtentDotStatistics) { horizDotStat=fopen("horizontal.dot","w"); fprintf(horizDotStat,"#Horizontal Extent\n"); } if(makeTextureUsedDotStatistics) { texDotStat=fopen("tex_used.dot","w"); fprintf(texDotStat,"#Texture Used\n"); } if(makeTriangleTypeDotStatistics) { triDotStat=fopen("tri_type.dot","w"); fprintf(triDotStat,"#Tri Type (0=gouraud, 1=Texture)\n"); } /* quick hack to check for long lines */ buf[BUFSIZE-1] = 'b'; while ((line < gmaxlines) && (gcframes <= gendframe) && fgets(buf, sizeof(buf), gftrace)) { ++line; p = buf; if (!buf[BUFSIZE-1]) { fprintf(stderr, "error: line %d too long. increase BUFSIZE!\n", line); return 0; } /* check for directive */ if (*p == '.') { p++; /* arrange in order of likeliness for speed */ if (!strncmp(p, "frame", 5)) { /* .frame */ p += 5; /* end of frame */ ++gcframes; if(gcframes >= gstartframe) { gcrelframes++; } } else if (gcframes < gstartframe) { if (!strncmp(p, "3DTR", 4)) { ++line, fgets(buf, sizeof(buf), gftrace); ++line, fgets(buf, sizeof(buf), gftrace); } continue; } else if (!strncmp(p, "3DTR", 4)) { /* .3DTR 492.000000 411.000000 1.000000 150 0 0 0 491.000000 69.000000 1.000000 150 0 0 0 492.000000 69.000000 1.000000 150 0 0 0 .3DTR 298.891541 245.557922 1.000000 150 255 255 255 \ 64.000000 63.968750 0.000000 0.000000 297.796875 245.845932 1.000000 150 255 255 255 \ 32.000000 63.968750 0.000000 0.000000 298.892853 203.390656 1.000000 150 255 255 255 \ 64.000000 0.000000 0.000000 0.000000 */ vertex v[3]; p += 4; if (!vtx_sscan(p, &v[0], fTexTriangle) || !(++line, fgets(buf, sizeof(buf), gftrace)) || !vtx_sscan(p, &v[1], fTexTriangle) || !(++line, fgets(buf, sizeof(buf), gftrace)) || !vtx_sscan(p, &v[2], fTexTriangle)) goto argerr; /* update statistics */ TakeStats(v, fTexTriangle, gcrelframes, line, areaDotStat, wRDotStat, wAvgDotStat, aspDotStat, vertDotStat, horizDotStat, texDotStat, triDotStat); } else if (!strncmp(p, "3DOP", 4)) { /* .3DOP b2ALP_BLD_SRC .3DOP b3TEX_FILT_MODE_4TPP .3DOP b2ALP_BLD_TEX .3DOP triTypeArg gouraud .3DOP triTypeArg litTexture .3DOP triTypeArg unlitTexture .3DOP triTypeArg litPerspective .3DOP triTypeArg unlitPerspctive */ p += 5; if (!strncmp(p, "triTypeArg", 10)) { p += 11; if (!strncmp(p, "gouraud", 7)) { fTexTriangle = 0; } else if (!strncmp(p, "litTexture", 10)) { fTexTriangle = 1; } else if (!strncmp(p, "unlitTexture", 12)) { fTexTriangle = 1; } else if (!strncmp(p, "litPerspective", 14)) { fTexTriangle = 1; } else if (!strncmp(p, "unlitPerspctive", 15)) { fTexTriangle = 1; } else { goto argerr; } } else if (!strncmp(p, "b2ALP_BLD_SRC", 13)) { /* ... */ } else if (!strncmp(p, "b2ALP_BLD_TEX", 13)) { /* ... */ } else if (!strncmp(p, "b3TEX_FILT_MODE_4TPP", 20)) { /* ... */ } else { goto argunk; } } else if (!strncmp(p, "newtex", 6)) { /* .newtex 0xXXXXXXX */ uint texaddr = 0; int i; p += 6; if (sscanf(p+3, "%x", &texaddr) != 1) goto argerr; for(i=0;i(a)) ? (b) : (a)) static void stats(void) { const char *szsfmt[] = { "\nstatistics for %s\n", "\n\n", "\nTOTALS UNTEXTURED TEXTURED OVERALL\n\n", "\n\n\n", "frames %28d to %d\n", "\n", "number of triangles %12d %12d %12d\n", "\n", "area %12.2f %12.2f %12.2f\n\n", "\n\n", "average number triangles / frame %12.2f %12.2f %12.2f\n\n", "\n\n", "average area / triangle %12.2f %12.2f %12.2f\n", "\n", "median triangle area %12d", "", " %12d", "", " %12d\n\n", "\n\n", "average aspect ratio %12.2f %12.2f %12.2f\n", "\n", "median aspect ratio %12d", "\n\n", "average horizontal extent %12.2f %12.2f %12.2f\n", "\n", "median horizontal extent %12d", "\n\n", "average vertical extent %12.2f %12.2f %12.2f\n", "\n", "median vertical extent %12d", "\n\n", "average depth complexity %12.2f %12.2f %12.2f\n\n", "\n\n", "average W-Ratio %12.2f\n", "\n", "median w-ratio %12.2f\n\n", "\n\n", "total texture changes %35d\n", "\n", "average tex changes/frame %38.2f\n\n", "\n\n", "total unique textures %35d\n", "\n", "average triangles/texture/frame %38.2f\n", "\n", "average pixels/texture/frame %38.2f\n", "\n", "average consecutive hits to a texture %38.2f\n\n", "\n\n", "\n", "
statistics for %s
TOTALSUNTEXTUREDTEXTUREDOVERALL
frames%d to %d
number of triangles%d%d%d
area%.2f%.2f%.2f
average number triangles / frame%.2f%.2f%.2f
average area / triangle%.2f%.2f%.2f
median triangle area%d%d%d
average aspect ratio%.2f%.2f%.2f
median aspect ratio%d", " %12d", "%d", " %12d\n\n", "%d
average horizontal extent%.2f%.2f%.2f
median horizontal extent%d", " %12d", "%d", " %12d\n\n", "%d
average vertical extent%.2f%.2f%.2f
median vertical extent%d", " %12d", "%d", " %12d\n\n", "%d
average depth complexity%.2f%.2f%.2f
average W-Ratio%.2f
median w-ratio%.2f
total texture changes%d
average tex changes/frame%.2f
total unique textures%d
average triangles/texture/frame%.2f
average pixels/texture/frame%.2f
average consecutive hits to a texture%.2f
\n" }; int nmed, median; int i,c, n; FILE *fOut; #define sfmt(n) (szsfmt[2*(n)+gfHtml]) assert(gfHtml == 0 || gfHtml == 1); n = 0; if(gcrelframes==0) gcrelframes=1; printf(sfmt(n++), gpsztrace); printf(sfmt(n++)); printf(sfmt(n++), gstartframe, min(gendframe,gcframes)); printf(sfmt(n++), gctriangles[0], gctriangles[1], gctriangles[0]+gctriangles[1]); printf(sfmt(n++), gtotalarea[0], gtotalarea[1], gtotalarea[0]+gtotalarea[1]); printf(sfmt(n++), (double)gctriangles[0]/(double)gcrelframes, (double)gctriangles[1]/(double)gcrelframes, (double)(gctriangles[0]+gctriangles[1])/(double)gcrelframes); printf(sfmt(n++), gtotalarea[0]/(gctriangles[0]==0 ? 1 : gctriangles[0]), gtotalarea[1]/(gctriangles[1]==0 ? 1 : gctriangles[1]), (gtotalarea[0]+gtotalarea[1])/(gctriangles[0]+gctriangles[1])); /* get median triangle sizes */ nmed = gctriangles[0] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = gctriangles[1] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = (gctriangles[0]+gctriangles[1]) / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); /* print average aspect ratio */ printf(sfmt(n++), gtotalaspect[0]/(gctriangles[0]==0 ? 1 : gctriangles[0]), gtotalaspect[1]/(gctriangles[1]==0 ? 1 : gctriangles[1]), (gtotalaspect[0]+gtotalaspect[1])/(gctriangles[0]+gctriangles[1])); /* get median aspect ratios */ nmed = gctriangles[0] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = gctriangles[1] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = (gctriangles[0]+gctriangles[1]) / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); printf(sfmt(n++), gtotalhoriz[0]/(gctriangles[0]==0 ? 1 : gctriangles[0]), gtotalhoriz[1]/(gctriangles[1]==0 ? 1 : gctriangles[1]), (gtotalhoriz[0]+gtotalhoriz[1])/(gctriangles[0]+gctriangles[1])); /* get median horizontal extent */ nmed = gctriangles[0] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = gctriangles[1] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = (gctriangles[0]+gctriangles[1]) / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); printf(sfmt(n++), gtotalvert[0]/(gctriangles[0]==0 ? 1 : gctriangles[0]), gtotalvert[1]/(gctriangles[1]==0 ? 1 : gctriangles[1]), (gtotalvert[0]+gtotalvert[1])/(gctriangles[0]+gctriangles[1])); /* get median vertical extent */ nmed = gctriangles[0] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = gctriangles[1] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); nmed = (gctriangles[0]+gctriangles[1]) / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), median); printf(sfmt(n++), gtotalarea[0]/((double)gcrelframes*307200.0), gtotalarea[1]/((double)gcrelframes*307200.0), (gtotalarea[0]+gtotalarea[1])/((double)gcrelframes*307200.0)); printf(sfmt(n++), gtotalwratio/(gctriangles[1]==0 ? 1 : gctriangles[1])); /* get median w-ratio */ nmed = gctriangles[1] / 2; for (i=0, c=0; i= nmed) { median = i; break; } } printf(sfmt(n++), (double)median/1000.0); printf(sfmt(n++), gtotaltexchanges); printf(sfmt(n++), (double)gtotaltexchanges/(double)gcrelframes); /* count the number of unique textures */ for(i=0;i\n", argv[0]); return 0; } /* open the trace file as stdin */ if (!(gftrace = fopen(argv[i], "r"))) { fprintf(stderr, "error: could not open trace file %s\n", argv[i]); return 0; } gpsztrace = argv[i]; return 1; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int main(int argc, char *argv[]) { /* parse the command line */ if (!cline(argc, argv)) return 1; /* parse the trace file */ parse(); /* show statistics */ stats(); return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */