1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)gprof.c	5.1 (Berkeley) 6/4/85";
  15: #endif not lint
  16: 
  17: #include "gprof.h"
  18: 
  19: char    *whoami = "gprof";
  20: 
  21:     /*
  22:      *	things which get -E excluded by default.
  23:      */
  24: char    *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
  25: 
  26: main(argc, argv)
  27:     int argc;
  28:     char **argv;
  29: {
  30:     char    **sp;
  31:     nltype  **timesortnlp;
  32: 
  33:     --argc;
  34:     argv++;
  35:     debug = 0;
  36:     bflag = TRUE;
  37:     while ( *argv != 0 && **argv == '-' ) {
  38:     (*argv)++;
  39:     switch ( **argv ) {
  40:     case 'a':
  41:         aflag = TRUE;
  42:         break;
  43:     case 'b':
  44:         bflag = FALSE;
  45:         break;
  46:     case 'c':
  47:         cflag = TRUE;
  48:         break;
  49:     case 'd':
  50:         dflag = TRUE;
  51:         (*argv)++;
  52:         debug |= atoi( *argv );
  53:         debug |= ANYDEBUG;
  54: #	    ifdef DEBUG
  55:         printf("[main] debug = %d\n", debug);
  56: #	    else not DEBUG
  57:         printf("%s: -d ignored\n", whoami);
  58: #	    endif DEBUG
  59:         break;
  60:     case 'E':
  61:         ++argv;
  62:         addlist( Elist , *argv );
  63:         Eflag = TRUE;
  64:         addlist( elist , *argv );
  65:         eflag = TRUE;
  66:         break;
  67:     case 'e':
  68:         addlist( elist , *++argv );
  69:         eflag = TRUE;
  70:         break;
  71:     case 'F':
  72:         ++argv;
  73:         addlist( Flist , *argv );
  74:         Fflag = TRUE;
  75:         addlist( flist , *argv );
  76:         fflag = TRUE;
  77:         break;
  78:     case 'f':
  79:         addlist( flist , *++argv );
  80:         fflag = TRUE;
  81:         break;
  82:     case 's':
  83:         sflag = TRUE;
  84:         break;
  85:     case 'z':
  86:         zflag = TRUE;
  87:         break;
  88:     }
  89:     argv++;
  90:     }
  91:     if ( *argv != 0 ) {
  92:     a_outname  = *argv;
  93:     argv++;
  94:     } else {
  95:     a_outname  = A_OUTNAME;
  96:     }
  97:     if ( *argv != 0 ) {
  98:     gmonname = *argv;
  99:     argv++;
 100:     } else {
 101:     gmonname = GMONNAME;
 102:     }
 103:     /*
 104: 	 *	turn off default functions
 105: 	 */
 106:     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
 107:     Eflag = TRUE;
 108:     addlist( Elist , *sp );
 109:     eflag = TRUE;
 110:     addlist( elist , *sp );
 111:     }
 112:     /*
 113: 	 *	how many ticks per second?
 114: 	 *	if we can't tell, report time in ticks.
 115: 	 */
 116:     hz = hertz();
 117:     if (hz == 0) {
 118:     hz = 1;
 119:     fprintf(stderr, "time is in ticks, not seconds\n");
 120:     }
 121:     /*
 122: 	 *	get information about a.out file.
 123: 	 */
 124:     getnfile();
 125:     /*
 126: 	 *	get information about mon.out file(s).
 127: 	 */
 128:     do  {
 129:     getpfile( gmonname );
 130:     if ( *argv != 0 ) {
 131:         gmonname = *argv;
 132:     }
 133:     } while ( *argv++ != 0 );
 134:     /*
 135: 	 *	dump out a gmon.sum file if requested
 136: 	 */
 137:     if ( sflag ) {
 138:     dumpsum( GMONSUM );
 139:     }
 140:     /*
 141: 	 *	assign samples to procedures
 142: 	 */
 143:     asgnsamples();
 144:     /*
 145: 	 *	assemble the dynamic profile
 146: 	 */
 147:     timesortnlp = doarcs();
 148:     /*
 149: 	 *	print the dynamic profile
 150: 	 */
 151:     printgprof( timesortnlp );
 152:     /*
 153: 	 *	print the flat profile
 154: 	 */
 155:     printprof();
 156:     /*
 157: 	 *	print the index
 158: 	 */
 159:     printindex();
 160:     done();
 161: }
 162: 
 163:     /*
 164:      * Set up string and symbol tables from a.out.
 165:      *	and optionally the text space.
 166:      * On return symbol table is sorted by value.
 167:      */
 168: getnfile()
 169: {
 170:     FILE    *nfile;
 171: 
 172:     nfile = fopen( a_outname ,"r");
 173:     if (nfile == NULL) {
 174:     perror( a_outname );
 175:     done();
 176:     }
 177:     fread(&xbuf, 1, sizeof(xbuf), nfile);
 178:     if (N_BADMAG(xbuf)) {
 179:     fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
 180:     done();
 181:     }
 182:     getstrtab(nfile);
 183:     getsymtab(nfile);
 184:     gettextspace( nfile );
 185:     qsort(nl, nname, sizeof(nltype), valcmp);
 186:     fclose(nfile);
 187: #   ifdef DEBUG
 188:     if ( debug & AOUTDEBUG ) {
 189:         register int j;
 190: 
 191:         for (j = 0; j < nname; j++){
 192:         printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
 193:         }
 194:     }
 195: #   endif DEBUG
 196: }
 197: 
 198: getstrtab(nfile)
 199:     FILE    *nfile;
 200: {
 201: 
 202:     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
 203:     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
 204:     fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
 205:         whoami , a_outname );
 206:     done();
 207:     }
 208:     strtab = (char *)calloc(ssiz, 1);
 209:     if (strtab == NULL) {
 210:     fprintf(stderr, "%s: %s: no room for %d bytes of string table",
 211:         whoami , a_outname , ssiz);
 212:     done();
 213:     }
 214:     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
 215:     fprintf(stderr, "%s: %s: error reading string table\n",
 216:         whoami , a_outname );
 217:     done();
 218:     }
 219: }
 220: 
 221:     /*
 222:      * Read in symbol table
 223:      */
 224: getsymtab(nfile)
 225:     FILE    *nfile;
 226: {
 227:     register long   i;
 228:     int         askfor;
 229:     struct nlist    nbuf;
 230: 
 231:     /* pass1 - count symbols */
 232:     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
 233:     nname = 0;
 234:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
 235:     fread(&nbuf, sizeof(nbuf), 1, nfile);
 236:     if ( ! funcsymbol( &nbuf ) ) {
 237:         continue;
 238:     }
 239:     nname++;
 240:     }
 241:     if (nname == 0) {
 242:     fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
 243:     done();
 244:     }
 245:     askfor = nname + 1;
 246:     nl = (nltype *) calloc( askfor , sizeof(nltype) );
 247:     if (nl == 0) {
 248:     fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
 249:         whoami, askfor * sizeof(nltype) );
 250:     done();
 251:     }
 252: 
 253:     /* pass2 - read symbols */
 254:     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
 255:     npe = nl;
 256:     nname = 0;
 257:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
 258:     fread(&nbuf, sizeof(nbuf), 1, nfile);
 259:     if ( ! funcsymbol( &nbuf ) ) {
 260: #	    ifdef DEBUG
 261:         if ( debug & AOUTDEBUG ) {
 262:             printf( "[getsymtab] rejecting: 0x%x %s\n" ,
 263:                 nbuf.n_type , strtab + nbuf.n_un.n_strx );
 264:         }
 265: #	    endif DEBUG
 266:         continue;
 267:     }
 268:     npe->value = nbuf.n_value;
 269:     npe->name = strtab+nbuf.n_un.n_strx;
 270: #	ifdef DEBUG
 271:         if ( debug & AOUTDEBUG ) {
 272:         printf( "[getsymtab] %d %s 0x%08x\n" ,
 273:             nname , npe -> name , npe -> value );
 274:         }
 275: #	endif DEBUG
 276:     npe++;
 277:     nname++;
 278:     }
 279:     npe->value = -1;
 280: }
 281: 
 282:     /*
 283:      *	read in the text space of an a.out file
 284:      */
 285: gettextspace( nfile )
 286:     FILE    *nfile;
 287: {
 288:     unsigned char   *malloc();
 289: 
 290:     if ( cflag == 0 ) {
 291:     return;
 292:     }
 293:     textspace = malloc( xbuf.a_text );
 294:     if ( textspace == 0 ) {
 295:     fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
 296:             whoami , xbuf.a_text );
 297:     fprintf( stderr , "can't do -c\n" );
 298:     return;
 299:     }
 300:     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
 301:     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
 302:     fprintf( stderr , "%s: couldn't read text space:  " , whoami );
 303:     fprintf( stderr , "can't do -c\n" );
 304:     free( textspace );
 305:     textspace = 0;
 306:     return;
 307:     }
 308: }
 309:     /*
 310:      *	information from a gmon.out file is in two parts:
 311:      *	an array of sampling hits within pc ranges,
 312:      *	and the arcs.
 313:      */
 314: getpfile(filename)
 315:     char *filename;
 316: {
 317:     FILE        *pfile;
 318:     FILE        *openpfile();
 319:     struct rawarc   arc;
 320: 
 321:     pfile = openpfile(filename);
 322:     readsamples(pfile);
 323:     /*
 324: 	 *	the rest of the file consists of
 325: 	 *	a bunch of <from,self,count> tuples.
 326: 	 */
 327:     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
 328: #	ifdef DEBUG
 329:         if ( debug & SAMPLEDEBUG ) {
 330:         printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
 331:             arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
 332:         }
 333: #	endif DEBUG
 334:         /*
 335: 	     *	add this arc
 336: 	     */
 337:     tally( &arc );
 338:     }
 339:     fclose(pfile);
 340: }
 341: 
 342: FILE *
 343: openpfile(filename)
 344:     char *filename;
 345: {
 346:     struct hdr  tmp;
 347:     FILE    *pfile;
 348: 
 349:     if((pfile = fopen(filename, "r")) == NULL) {
 350:     perror(filename);
 351:     done();
 352:     }
 353:     fread(&tmp, sizeof(struct hdr), 1, pfile);
 354:     if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
 355:      tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
 356:     fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
 357:     done();
 358:     }
 359:     h = tmp;
 360:     s_lowpc = (unsigned long) h.lowpc;
 361:     s_highpc = (unsigned long) h.highpc;
 362:     lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
 363:     highpc = (unsigned long)h.highpc / sizeof(UNIT);
 364:     sampbytes = h.ncnt - sizeof(struct hdr);
 365:     nsamples = sampbytes / sizeof (unsigned UNIT);
 366: #   ifdef DEBUG
 367:     if ( debug & SAMPLEDEBUG ) {
 368:         printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
 369:         h.lowpc , h.highpc , h.ncnt );
 370:         printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
 371:         s_lowpc , s_highpc );
 372:         printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
 373:         lowpc , highpc );
 374:         printf( "[openpfile] sampbytes %d nsamples %d\n" ,
 375:         sampbytes , nsamples );
 376:     }
 377: #   endif DEBUG
 378:     return(pfile);
 379: }
 380: 
 381: tally( rawp )
 382:     struct rawarc   *rawp;
 383: {
 384:     nltype      *parentp;
 385:     nltype      *childp;
 386: 
 387:     parentp = nllookup( rawp -> raw_frompc );
 388:     childp = nllookup( rawp -> raw_selfpc );
 389:     childp -> ncall += rawp -> raw_count;
 390: #   ifdef DEBUG
 391:     if ( debug & TALLYDEBUG ) {
 392:         printf( "[tally] arc from %s to %s traversed %d times\n" ,
 393:             parentp -> name , childp -> name , rawp -> raw_count );
 394:     }
 395: #   endif DEBUG
 396:     addarc( parentp , childp , rawp -> raw_count );
 397: }
 398: 
 399: /*
 400:  * dump out the gmon.sum file
 401:  */
 402: dumpsum( sumfile )
 403:     char *sumfile;
 404: {
 405:     register nltype *nlp;
 406:     register arctype *arcp;
 407:     struct rawarc arc;
 408:     FILE *sfile;
 409: 
 410:     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
 411:     perror( sumfile );
 412:     done();
 413:     }
 414:     /*
 415:      * dump the header; use the last header read in
 416:      */
 417:     if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
 418:     perror( sumfile );
 419:     done();
 420:     }
 421:     /*
 422:      * dump the samples
 423:      */
 424:     if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
 425:     perror( sumfile );
 426:     done();
 427:     }
 428:     /*
 429:      * dump the normalized raw arc information
 430:      */
 431:     for ( nlp = nl ; nlp < npe ; nlp++ ) {
 432:     for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
 433:         arc.raw_frompc = arcp -> arc_parentp -> value;
 434:         arc.raw_selfpc = arcp -> arc_childp -> value;
 435:         arc.raw_count = arcp -> arc_count;
 436:         if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
 437:         perror( sumfile );
 438:         done();
 439:         }
 440: #	    ifdef DEBUG
 441:         if ( debug & SAMPLEDEBUG ) {
 442:             printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
 443:                 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
 444:         }
 445: #	    endif DEBUG
 446:     }
 447:     }
 448:     fclose( sfile );
 449: }
 450: 
 451: valcmp(p1, p2)
 452:     nltype *p1, *p2;
 453: {
 454:     if ( p1 -> value < p2 -> value ) {
 455:     return LESSTHAN;
 456:     }
 457:     if ( p1 -> value > p2 -> value ) {
 458:     return GREATERTHAN;
 459:     }
 460:     return EQUALTO;
 461: }
 462: 
 463: readsamples(pfile)
 464:     FILE    *pfile;
 465: {
 466:     register i;
 467:     unsigned UNIT   sample;
 468: 
 469:     if (samples == 0) {
 470:     samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
 471:     if (samples == 0) {
 472:         fprintf( stderr , "%s: No room for %d sample pc's\n",
 473:         whoami , sampbytes / sizeof (unsigned UNIT));
 474:         done();
 475:     }
 476:     }
 477:     for (i = 0; i < nsamples; i++) {
 478:     fread(&sample, sizeof (unsigned UNIT), 1, pfile);
 479:     if (feof(pfile))
 480:         break;
 481:     samples[i] += sample;
 482:     }
 483:     if (i != nsamples) {
 484:     fprintf(stderr,
 485:         "%s: unexpected EOF after reading %d/%d samples\n",
 486:         whoami , --i , nsamples );
 487:     done();
 488:     }
 489: }
 490: 
 491: /*
 492:  *	Assign samples to the procedures to which they belong.
 493:  *
 494:  *	There are three cases as to where pcl and pch can be
 495:  *	with respect to the routine entry addresses svalue0 and svalue1
 496:  *	as shown in the following diagram.  overlap computes the
 497:  *	distance between the arrows, the fraction of the sample
 498:  *	that is to be credited to the routine which starts at svalue0.
 499:  *
 500:  *	    svalue0                                         svalue1
 501:  *	       |                                               |
 502:  *	       v                                               v
 503:  *
 504:  *	       +-----------------------------------------------+
 505:  *	       |					       |
 506:  *	  |  ->|    |<-		->|         |<-		->|    |<-  |
 507:  *	  |         |		  |         |		  |         |
 508:  *	  +---------+		  +---------+		  +---------+
 509:  *
 510:  *	  ^         ^		  ^         ^		  ^         ^
 511:  *	  |         |		  |         |		  |         |
 512:  *	 pcl       pch		 pcl       pch		 pcl       pch
 513:  *
 514:  *	For the vax we assert that samples will never fall in the first
 515:  *	two bytes of any routine, since that is the entry mask,
 516:  *	thus we give call alignentries() to adjust the entry points if
 517:  *	the entry mask falls in one bucket but the code for the routine
 518:  *	doesn't start until the next bucket.  In conjunction with the
 519:  *	alignment of routine addresses, this should allow us to have
 520:  *	only one sample for every four bytes of text space and never
 521:  *	have any overlap (the two end cases, above).
 522:  */
 523: asgnsamples()
 524: {
 525:     register int    j;
 526:     unsigned UNIT   ccnt;
 527:     double      time;
 528:     unsigned long   pcl, pch;
 529:     register int    i;
 530:     unsigned long   overlap;
 531:     unsigned long   svalue0, svalue1;
 532: 
 533:     /* read samples and assign to namelist symbols */
 534:     scale = highpc - lowpc;
 535:     scale /= nsamples;
 536:     alignentries();
 537:     for (i = 0, j = 1; i < nsamples; i++) {
 538:     ccnt = samples[i];
 539:     if (ccnt == 0)
 540:         continue;
 541:     pcl = lowpc + scale * i;
 542:     pch = lowpc + scale * (i + 1);
 543:     time = ccnt;
 544: #	ifdef DEBUG
 545:         if ( debug & SAMPLEDEBUG ) {
 546:         printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
 547:             pcl , pch , ccnt );
 548:         }
 549: #	endif DEBUG
 550:     totime += time;
 551:     for (j = j - 1; j < nname; j++) {
 552:         svalue0 = nl[j].svalue;
 553:         svalue1 = nl[j+1].svalue;
 554:         /*
 555: 		 *	if high end of tick is below entry address,
 556: 		 *	go for next tick.
 557: 		 */
 558:         if (pch < svalue0)
 559:             break;
 560:         /*
 561: 		 *	if low end of tick into next routine,
 562: 		 *	go for next routine.
 563: 		 */
 564:         if (pcl >= svalue1)
 565:             continue;
 566:         overlap = min(pch, svalue1) - max(pcl, svalue0);
 567:         if (overlap > 0) {
 568: #		ifdef DEBUG
 569:             if (debug & SAMPLEDEBUG) {
 570:             printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
 571:                 nl[j].value/sizeof(UNIT), svalue0, svalue1,
 572:                 nl[j].name,
 573:                 overlap * time / scale, overlap);
 574:             }
 575: #		endif DEBUG
 576:         nl[j].time += overlap * time / scale;
 577:         }
 578:     }
 579:     }
 580: #   ifdef DEBUG
 581:     if (debug & SAMPLEDEBUG) {
 582:         printf("[asgnsamples] totime %f\n", totime);
 583:     }
 584: #   endif DEBUG
 585: }
 586: 
 587: 
 588: unsigned long
 589: min(a, b)
 590:     unsigned long a,b;
 591: {
 592:     if (a<b)
 593:     return(a);
 594:     return(b);
 595: }
 596: 
 597: unsigned long
 598: max(a, b)
 599:     unsigned long a,b;
 600: {
 601:     if (a>b)
 602:     return(a);
 603:     return(b);
 604: }
 605: 
 606:     /*
 607:      *	calculate scaled entry point addresses (to save time in asgnsamples),
 608:      *	and possibly push the scaled entry points over the entry mask,
 609:      *	if it turns out that the entry point is in one bucket and the code
 610:      *	for a routine is in the next bucket.
 611:      */
 612: alignentries()
 613: {
 614:     register struct nl  *nlp;
 615:     unsigned long   bucket_of_entry;
 616:     unsigned long   bucket_of_code;
 617: 
 618:     for (nlp = nl; nlp < npe; nlp++) {
 619:     nlp -> svalue = nlp -> value / sizeof(UNIT);
 620:     bucket_of_entry = (nlp->svalue - lowpc) / scale;
 621:     bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
 622:     if (bucket_of_entry < bucket_of_code) {
 623: #	    ifdef DEBUG
 624:         if (debug & SAMPLEDEBUG) {
 625:             printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
 626:                 nlp->svalue, nlp->svalue + UNITS_TO_CODE);
 627:         }
 628: #	    endif DEBUG
 629:         nlp->svalue += UNITS_TO_CODE;
 630:     }
 631:     }
 632: }
 633: 
 634: bool
 635: funcsymbol( nlistp )
 636:     struct nlist    *nlistp;
 637: {
 638:     extern char *strtab;    /* string table from a.out */
 639:     extern int  aflag;      /* if static functions aren't desired */
 640:     char    *name;
 641: 
 642:     /*
 643: 	 *	must be a text symbol,
 644: 	 *	and static text symbols don't qualify if aflag set.
 645: 	 */
 646:     if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
 647:        || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
 648:     return FALSE;
 649:     }
 650:     /*
 651: 	 *	can't have any `funny' characters in name,
 652: 	 *	where `funny' includes	`.', .o file names
 653: 	 *			and	`$', pascal labels.
 654: 	 */
 655:     for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
 656:     if ( *name == '.' || *name == '$' ) {
 657:         return FALSE;
 658:     }
 659:     }
 660:     return TRUE;
 661: }
 662: 
 663: done()
 664: {
 665: 
 666:     exit(0);
 667: }

Defined functions

alignentries defined in line 612; used 1 times
asgnsamples defined in line 523; used 2 times
done defined in line 663; used 19 times
dumpsum defined in line 402; used 1 times
funcsymbol defined in line 634; used 3 times
getnfile defined in line 168; used 2 times
getpfile defined in line 314; used 2 times
getstrtab defined in line 198; used 2 times
getsymtab defined in line 224; used 2 times
gettextspace defined in line 285; used 2 times
main defined in line 26; used 1 times
max defined in line 597; used 2 times
min defined in line 588; used 2 times
openpfile defined in line 342; used 3 times
readsamples defined in line 463; used 2 times
tally defined in line 381; used 2 times
valcmp defined in line 451; used 2 times

Defined variables

copyright defined in line 8; never used
defaultEs defined in line 24; used 1 times
sccsid defined in line 14; never used
whoami defined in line 19; used 11 times
Last modified: 1985-06-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2471
Valid CSS Valid XHTML 1.0 Strict