112892Ssam #ifndef lint 2*13174Sroot static char *sccsid = "@(#)prof.c 4.2 (Berkeley) 06/17/83"; 312892Ssam #endif 412892Ssam /* 512892Ssam * prof 612892Ssam */ 712892Ssam #include <stdio.h> 812892Ssam #include <sys/types.h> 912892Ssam #include <sys/stat.h> 1012892Ssam #include <a.out.h> 1112892Ssam 1212892Ssam typedef short UNIT; /* unit of profiling */ 1312892Ssam #define A_OUTNAME "a.out" 1412892Ssam #define MON_OUTNAME "mon.out" 1512892Ssam #define MON_SUMNAME "mon.sum" 1612892Ssam 1712892Ssam /* 1812892Ssam * The symbol table; 1912892Ssam * for each external in the specified file we gather 2012892Ssam * its address, the number of calls and compute its share of cpu time. 2112892Ssam */ 2212892Ssam struct nl { 2312892Ssam char *name; 2412892Ssam unsigned value; 2512892Ssam float time; 2612892Ssam long ncall; 2712892Ssam } *nl; 2812892Ssam int nname; 2912892Ssam struct nl *np; 3012892Ssam struct nl *npe; 3112892Ssam 3212892Ssam /* 3312892Ssam * The header on the mon.out file. 3412892Ssam * Mon.out consists of one of these headers, an array of ncount 3512892Ssam * cnt structures (as below) and then an array of samples 3612892Ssam * representing the discretized program counter values. 3712892Ssam */ 3812892Ssam struct hdr { 3912892Ssam UNIT *lowpc, *highpc; 4012892Ssam int ncount; 4112892Ssam } h; 4212892Ssam 4312892Ssam /* 4412892Ssam * Each counter has an address and a number of calls. 4512892Ssam */ 4612892Ssam struct cnt { 4712892Ssam unsigned cvalue; 4812892Ssam long cncall; 4912892Ssam } *cbuf; 5012892Ssam 5112892Ssam /* 5212892Ssam * Each discretized pc sample has 5312892Ssam * a count of the number of samples in its range 5412892Ssam */ 5512892Ssam unsigned UNIT *samples; 5612892Ssam 5712892Ssam FILE *pfile, *nfile; 5812892Ssam 5912892Ssam unsigned lowpc, highpc; /* range profiled */ 6012892Ssam double ransca, ranoff; /* scaling for blowing up plots */ 6112892Ssam unsigned sampbytes; /* number of bytes of samples */ 6212892Ssam int nsamples; /* number of samples */ 6312892Ssam double totime; /* total time for all routines */ 6412892Ssam double maxtime; /* maximum time of any routine (for plot) */ 6512892Ssam double scale; /* scale factor converting samples to pc 6612892Ssam values: each sample covers scale bytes */ 6712892Ssam char *strtab; /* string table in core */ 6812892Ssam off_t ssiz; /* size of the string table */ 6912892Ssam struct exec xbuf; /* exec header of a.out */ 7012892Ssam 7112892Ssam int aflg; 7212892Ssam int nflg; 7312892Ssam int vflg; 7412892Ssam int lflg; 7512892Ssam int zflg; 7612892Ssam int sflag; 7712892Ssam 7812892Ssam char *namfil; 7912892Ssam 8012892Ssam int timcmp(), valcmp(), cntcmp(); 8112892Ssam 8212892Ssam main(argc, argv) 8312892Ssam char **argv; 8412892Ssam { 8512892Ssam int lowpct, highpct; 8612892Ssam 8712892Ssam /* 8812892Ssam * Use highpct and lowpc as percentages, temporarily 8912892Ssam * for graphing options involving blow-up 9012892Ssam */ 9112892Ssam lowpct = -1; 9212892Ssam highpct = -1; 9312892Ssam argv++; 9412892Ssam while ( *argv != 0 && **argv == '-' ) { 9512892Ssam *argv += 1; 9612892Ssam if (**argv == 'l') 9712892Ssam lflg++; 9812892Ssam else if (**argv == 'a') 9912892Ssam aflg++; 10012892Ssam else if (**argv == 'n') 10112892Ssam nflg++; 10212892Ssam else if (**argv == 'z') 10312892Ssam zflg++; 10412892Ssam else if (**argv == 'v') 10512892Ssam vflg++; 10612892Ssam else if ( **argv == 's' ) 10712892Ssam sflag++; 10812892Ssam else if (**argv >= '0' && **argv <= '9') { 10912892Ssam int i = atoi(*argv); 11012892Ssam if (lowpct == -1) 11112892Ssam lowpct = i; 11212892Ssam else 11312892Ssam highpct = i; 11412892Ssam } 11512892Ssam argv++; 11612892Ssam } 11712892Ssam if ( *argv != 0 ) { 11812892Ssam namfil = *argv; 11912892Ssam argv++; 12012892Ssam } else { 12112892Ssam namfil = A_OUTNAME; 12212892Ssam } 12312892Ssam if (lowpct >= 100) 12412892Ssam lowpct = 0; 12512892Ssam if (highpct <= lowpct || highpct > 100) 12612892Ssam highpct = 100; 12712892Ssam ransca = 100./(highpct-lowpct); 12812892Ssam ranoff = 2040. + 40.8*lowpc*ransca; 12912892Ssam /* 13012892Ssam * get information about a.out file. 13112892Ssam */ 13212892Ssam getnfile(); 13312892Ssam /* 13412892Ssam * get information about mon.out file(s). 13512892Ssam */ 13612892Ssam if ( *argv == 0 ) { 13712892Ssam getpfile( MON_OUTNAME ); 13812892Ssam } else { 13912892Ssam do { 14012892Ssam getpfile( *argv ); 14112892Ssam argv++; 14212892Ssam } while ( *argv != 0 ); 14312892Ssam } 14412892Ssam asgnsamples(); /* assign samples to procedures */ 14512892Ssam #ifdef plot 14612892Ssam if (vflg) 14712892Ssam plotprof(); /* a plotted or ... */ 14812892Ssam else 14912892Ssam #endif 15012892Ssam printprof(); /* a printed profile */ 15112892Ssam if ( sflag != 0 ) { 15212892Ssam putprof(); 15312892Ssam } 15412892Ssam done(); 15512892Ssam } 15612892Ssam 15712892Ssam printprof() 15812892Ssam { 15912892Ssam double time, actime; 16012892Ssam 16112892Ssam actime = 0; 16212892Ssam printf(" %%time cumsecs #call ms/call name\n"); 16312892Ssam if (!lflg) 16412892Ssam qsort(nl, nname, sizeof(struct nl), timcmp); 16512892Ssam for (np = nl; np<npe-1; np++) { 16612892Ssam if (zflg == 0 && np->time == 0 && np->ncall == 0) 16712892Ssam continue; 16812892Ssam time = np->time/totime; 16912892Ssam actime += np->time; 17012892Ssam printf("%6.1f%9.2f", 100*time, actime/60); 17112892Ssam if (np->ncall != 0) 17212892Ssam printf("%7ld %8.2f", 17312892Ssam np->ncall, np->time/(np->ncall*.06)); 17412892Ssam else 17512892Ssam printf("%7.7s %8.8s", "", ""); 17612892Ssam printf(" %s\n", np->name); 17712892Ssam } 17812892Ssam } 17912892Ssam 18012892Ssam /* 18112892Ssam * Set up string and symbol tables from a.out. 18212892Ssam * On return symbol table is sorted by value. 18312892Ssam */ 18412892Ssam getnfile() 18512892Ssam { 18612892Ssam 18712892Ssam nfile = fopen(namfil,"r"); 18812892Ssam if (nfile == NULL) { 18912892Ssam perror(namfil); 19012892Ssam done(); 19112892Ssam } 19212892Ssam fread(&xbuf, 1, sizeof(xbuf), nfile); 19312892Ssam if (N_BADMAG(xbuf)) { 19412892Ssam fprintf(stderr, "%s: bad format\n", namfil); 19512892Ssam done(); 19612892Ssam } 19712892Ssam getstrtab(); 19812892Ssam getsymtab(); 19912892Ssam qsort(nl, nname, sizeof(struct nl), valcmp); 20012892Ssam } 20112892Ssam 20212892Ssam getstrtab() 20312892Ssam { 20412892Ssam 20512892Ssam fseek(nfile, N_SYMOFF(xbuf) + xbuf.a_syms, 0); 20612892Ssam if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 20712892Ssam fprintf(stderr, "%s: no string table (old format?)\n", namfil); 20812892Ssam done(); 20912892Ssam } 21012892Ssam strtab = (char *)calloc(ssiz, 1); 21112892Ssam if (strtab == NULL) { 21212892Ssam fprintf(stderr, "%s: no room for %d bytes of string table", 21312892Ssam namfil, ssiz); 21412892Ssam done(); 21512892Ssam } 21612892Ssam if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 21712892Ssam fprintf(stderr, "%s: error reading string table\n", namfil); 21812892Ssam done(); 21912892Ssam } 22012892Ssam } 22112892Ssam 22212892Ssam /* 22312892Ssam * Read in symbol table 22412892Ssam */ 22512892Ssam getsymtab() 22612892Ssam { 22712892Ssam register int i; 22812892Ssam 22912892Ssam /* pass1 - count symbols */ 23012892Ssam fseek(nfile, N_SYMOFF(xbuf), 0); 23112892Ssam nname = 0; 23212892Ssam for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 23312892Ssam struct nlist nbuf; 23412892Ssam fread(&nbuf, sizeof(nbuf), 1, nfile); 23512892Ssam if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT) 23612892Ssam continue; 23712892Ssam if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT) 23812892Ssam continue; 23912892Ssam nname++; 24012892Ssam } 24112892Ssam if (nname == 0) { 24212892Ssam fprintf(stderr, "%s: no symbols\n", namfil); 24312892Ssam done(); 24412892Ssam } 24512892Ssam nl = (struct nl *)calloc((nname+1), sizeof (struct nl)); 24612892Ssam if (nl == 0) { 24712892Ssam fprintf(stderr, "prof: No room for %d bytes of symbol table\n", 24812892Ssam (nname+1) * sizeof (struct nlist)); 24912892Ssam done(); 25012892Ssam } 25112892Ssam 25212892Ssam /* pass2 - read symbols */ 25312892Ssam fseek(nfile, N_SYMOFF(xbuf), 0); 25412892Ssam npe = nl; 25512892Ssam nname = 0; 25612892Ssam for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 25712892Ssam struct nlist nbuf; 25812892Ssam fread(&nbuf, sizeof(nbuf), 1, nfile); 25912892Ssam if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT) 26012892Ssam continue; 26112892Ssam if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT) 26212892Ssam continue; 26312892Ssam npe->value = nbuf.n_value/sizeof(UNIT); 26412892Ssam npe->name = strtab+nbuf.n_un.n_strx; 26512892Ssam npe++; 26612892Ssam nname++; 26712892Ssam } 26812892Ssam npe->value = -1; 26912892Ssam npe++; 27012892Ssam } 27112892Ssam 27212892Ssam /* 27312892Ssam * information from a mon.out file is in two parts: 27412892Ssam * the counters of how many times each procedure was called, 27512892Ssam * if it was called at all; 27612892Ssam * and an array of sampling hits within pc ranges. 27712892Ssam * the counters must be dealt with on a file-by-file basis, 27812892Ssam * since which procedures are represented may vary. 27912892Ssam * the samples ranges are fixed, but must be summed across 28012892Ssam * files, and then distributed among procedures, because 28112892Ssam * of the wierd way the plotting is done. 28212892Ssam */ 28312892Ssam getpfile(filename) 28412892Ssam char *filename; 28512892Ssam { 28612892Ssam 28712892Ssam openpfile(filename); 28812892Ssam readcntrs(); 28912892Ssam asgncntrs(); /* assign counts to procedures */ 29012892Ssam readsamples(); 29112892Ssam closepfile(); 29212892Ssam } 29312892Ssam 29412892Ssam openpfile(filename) 29512892Ssam char *filename; 29612892Ssam { 29712892Ssam struct stat stb; 29812892Ssam 29912892Ssam if((pfile = fopen(filename, "r")) == NULL) { 30012892Ssam perror(filename); 30112892Ssam done(); 30212892Ssam } 30312892Ssam fstat(fileno(pfile), &stb); 30412892Ssam fread(&h, sizeof(struct hdr), 1, pfile); 30512892Ssam lowpc = h.lowpc - (UNIT *)0; 30612892Ssam highpc = h.highpc - (UNIT *)0; 30712892Ssam sampbytes = 30812892Ssam stb.st_size - sizeof(struct hdr) - h.ncount*sizeof(struct cnt); 30912892Ssam nsamples = sampbytes / sizeof (unsigned UNIT); 31012892Ssam } 31112892Ssam 31212892Ssam closepfile() 31312892Ssam { 31412892Ssam 31512892Ssam fclose(pfile); 31612892Ssam free(cbuf); 31712892Ssam } 31812892Ssam 31912892Ssam readcntrs() 32012892Ssam { 32112892Ssam struct cnt *kp; 32212892Ssam 32312892Ssam cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt)); 32412892Ssam if (cbuf == 0) { 32512892Ssam fprintf(stderr, "prof: No room for %d bytes of count buffer\n", 32612892Ssam (h.ncount+1) * sizeof (struct cnt)); 32712892Ssam exit(1); 32812892Ssam } 32912892Ssam fread(cbuf, sizeof(struct cnt), h.ncount, pfile); 33012892Ssam /* eliminate zero counters and scale counter pc values */ 33112892Ssam if (h.ncount) { 33212892Ssam kp = &cbuf[h.ncount - 1]; 33312892Ssam for (;;) { 33412892Ssam if (kp->cvalue==0) { 33512892Ssam h.ncount=kp-cbuf; 33612892Ssam ++kp; 33712892Ssam break; 33812892Ssam } 33912892Ssam if (kp == cbuf) { 34012892Ssam h.ncount = 0; 34112892Ssam break; 34212892Ssam } 34312892Ssam --kp; 34412892Ssam } 34512892Ssam for (; --kp>=cbuf; ) 34612892Ssam kp->cvalue /= sizeof(UNIT); 34712892Ssam } 34812892Ssam /* sort counters */ 34912892Ssam qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp); 35012892Ssam } 35112892Ssam 35212892Ssam /* 35312892Ssam * Assign counters to the procedures to which they belong 35412892Ssam */ 35512892Ssam asgncntrs() 35612892Ssam { 35712892Ssam register int i; 35812892Ssam struct cnt *kp; 35912892Ssam 36012892Ssam kp = &cbuf[h.ncount-1]; 36112892Ssam np = npe; 36212892Ssam while (--np>=nl) { 36312892Ssam if (kp<cbuf || np->value > kp->cvalue) 36412892Ssam continue; 36512892Ssam /* skip ``static'' functions */ 36612892Ssam while (kp >= cbuf && kp->cvalue > np->value + 11) 36712892Ssam --kp; 36812892Ssam if (kp->cvalue >= np->value) { 36912892Ssam np->ncall += kp->cncall; 37012892Ssam --kp; 37112892Ssam } 37212892Ssam } 37312892Ssam } 37412892Ssam 37512892Ssam readsamples() 37612892Ssam { 37712892Ssam register i; 37812892Ssam unsigned UNIT sample; 37912892Ssam int totalt; 38012892Ssam 38112892Ssam if (samples == 0) { 38212892Ssam samples = (unsigned UNIT *) 38312892Ssam calloc(sampbytes, sizeof (unsigned UNIT)); 38412892Ssam if (samples == 0) { 38512892Ssam printf("prof: No room for %d sample pc's\n", 38612892Ssam sampbytes / sizeof (unsigned UNIT)); 38712892Ssam done(); 38812892Ssam } 38912892Ssam } 39012892Ssam for (i = 0; ; i++) { 39112892Ssam fread(&sample, sizeof (unsigned UNIT), 1, pfile); 39212892Ssam if (feof(pfile)) 39312892Ssam break; 39412892Ssam samples[i] += sample; 39512892Ssam totalt += sample; 39612892Ssam } 39712892Ssam if (i != nsamples) { 39812892Ssam fprintf(stderr, 39912892Ssam "prof: unexpected EOF after reading %d/%d samples\n", 40012892Ssam --i, nsamples); 40112892Ssam done(); 40212892Ssam } 40312892Ssam } 40412892Ssam 40512892Ssam /* 40612892Ssam * Assign samples to the procedures to which they belong. 40712892Ssam */ 40812892Ssam asgnsamples() 40912892Ssam { 41012892Ssam register j; 41112892Ssam unsigned UNIT ccnt; 41212892Ssam double time; 41312892Ssam unsigned pcl, pch; 41412892Ssam register int i; 41512892Ssam int overlap; 41612892Ssam 41712892Ssam /* read samples and assign to namelist symbols */ 41812892Ssam scale = highpc - lowpc; 41912892Ssam scale /= nsamples; 42012892Ssam for (i=0; i < nsamples; i++) { 42112892Ssam ccnt = samples[i]; 42212892Ssam if (ccnt == 0) 42312892Ssam continue; 42412892Ssam pcl = lowpc + scale*i; 42512892Ssam pch = lowpc + scale*(i+1); 42612892Ssam time = ccnt; 42712892Ssam totime += time; 42812892Ssam if(time > maxtime) 42912892Ssam maxtime = time; 43012892Ssam for (j=0; j<nname; j++) { 43112892Ssam if (pch < nl[j].value) 43212892Ssam break; 43312892Ssam if (pcl >= nl[j+1].value) 43412892Ssam continue; 43512892Ssam overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value)); 43612892Ssam if (overlap>0) 43712892Ssam nl[j].time += overlap*time/scale; 43812892Ssam } 43912892Ssam } 44012892Ssam if (totime==0.0) { 44112892Ssam fprintf(stderr, "No time accumulated\n"); 44212892Ssam /* 44312892Ssam done(); 44412892Ssam */ 44512892Ssam totime=1.0; 44612892Ssam } 44712892Ssam } 44812892Ssam 44912892Ssam /* 45012892Ssam * dump what you have out to a mon.out style file. 45112892Ssam */ 45212892Ssam putprof() 45312892Ssam { 45412892Ssam FILE *sfile; 45512892Ssam struct nl *np; 45612892Ssam struct cnt kp; 45712892Ssam int i; 45812892Ssam 45912892Ssam sfile = fopen(MON_SUMNAME, "w"); 46012892Ssam if (sfile == NULL) { 46112892Ssam perror(MON_SUMNAME); 46212892Ssam done(); 46312892Ssam } 46412892Ssam /* 46512892Ssam * build a new header. 46612892Ssam * h.lowpc and h.highpc are already fine. 46712892Ssam * fix h.ncount to count non-zero calls, 46812892Ssam * and the one zero call which marks the end. 46912892Ssam */ 47012892Ssam h.ncount = 0; 47112892Ssam for (np = nl; np < npe-1 ; np++) 47212892Ssam if (np->ncall > 0) 47312892Ssam h.ncount++; 47412892Ssam h.ncount++; 47512892Ssam fwrite(&h, sizeof (struct hdr), 1, sfile); 47612892Ssam for (np = nl; np < npe-1; np++) { 47712892Ssam if (np->ncall > 0) { 47812892Ssam kp.cvalue = np->value * sizeof (unsigned UNIT); 47912892Ssam kp.cncall = np->ncall; 48012892Ssam fwrite(&kp, sizeof (struct cnt), 1, sfile); 48112892Ssam } 48212892Ssam } 48312892Ssam kp.cvalue = 0; 48412892Ssam kp.cncall = 0; 48512892Ssam fwrite(&kp, sizeof (struct cnt), 1, sfile); 48612892Ssam fwrite(samples, sizeof (unsigned UNIT), nsamples, sfile); 48712892Ssam fclose(sfile); 48812892Ssam } 48912892Ssam 49012892Ssam min(a, b) 49112892Ssam { 49212892Ssam if (a<b) 49312892Ssam return(a); 49412892Ssam return(b); 49512892Ssam } 49612892Ssam 49712892Ssam max(a, b) 49812892Ssam { 49912892Ssam if (a>b) 50012892Ssam return(a); 50112892Ssam return(b); 50212892Ssam } 50312892Ssam 50412892Ssam valcmp(p1, p2) 50512892Ssam struct nl *p1, *p2; 50612892Ssam { 50712892Ssam 50812892Ssam return(p1->value - p2->value); 50912892Ssam } 51012892Ssam 51112892Ssam timcmp(p1, p2) 51212892Ssam struct nl *p1, *p2; 51312892Ssam { 51412892Ssam float d; 51512892Ssam 51612892Ssam if (nflg && p2->ncall != p1->ncall) 51712892Ssam return (p2->ncall - p1->ncall); 51812892Ssam d = p2->time - p1->time; 51912892Ssam if (d > 0.0) 52012892Ssam return(1); 52112892Ssam if (d < 0.0) 52212892Ssam return(-1); 52312892Ssam return(strcmp(p1->name,p2->name)); 52412892Ssam } 52512892Ssam 52612892Ssam cntcmp(p1, p2) 52712892Ssam struct cnt *p1, *p2; 52812892Ssam { 52912892Ssam 53012892Ssam return(p1->cvalue - p2->cvalue); 53112892Ssam } 53212892Ssam 53312892Ssam done() 53412892Ssam { 53512892Ssam 53612892Ssam #ifdef plot 53712892Ssam if(vflg) { 53812892Ssam point(0, -2040); 53912892Ssam closepl(); 54012892Ssam } 54112892Ssam #endif 54212892Ssam exit(0); 54312892Ssam } 54412892Ssam 54512892Ssam #ifdef plot 54612892Ssam plotprof() 54712892Ssam { 54812892Ssam double time, lastx, lasty, lastsx; 54912892Ssam register i; 55012892Ssam 55112892Ssam openpl(); 55212892Ssam erase(); 55312892Ssam space(-2048, -2048, 2048, 2048); 55412892Ssam line(-2040, -2040, -2040, 2040); 55512892Ssam line(0, 2040, 0, -2040); 55612892Ssam for(i=0; i<11; i++) 55712892Ssam line(-2040, 2040-i*408, 0, 2040-i*408); 55812892Ssam lastx = 0.; 55912892Ssam lasty = ranoff; 56012892Ssam scale = (4080.*ransca)/(sampbytes/sizeof(UNIT)); 56112892Ssam lastsx = 0.0; 56212892Ssam for(i = 0; i < nsamples; i++) { 56312892Ssam unsigned UNIT ccnt; 56412892Ssam double tx, ty; 56512892Ssam ccnt = samples[i]; 56612892Ssam time = ccnt; 56712892Ssam tx = lastsx; 56812892Ssam ty = lasty; 56912892Ssam lastsx -= 2000.*time/totime; 57012892Ssam lasty -= scale; 57112892Ssam if(lasty >= -2040. && ty <= 2040.) { 57212892Ssam line((int)tx, (int)ty, (int)lastsx, (int)lasty); 57312892Ssam if (ccnt!=0 || lastx!=0.0) { 57412892Ssam tx = lastx; 57512892Ssam lastx = -time*2000./maxtime; 57612892Ssam ty += scale/2; 57712892Ssam line(0, (int)ty, (int)tx, (int)ty); 57812892Ssam } 57912892Ssam } 58012892Ssam } 58112892Ssam scale = (4080.*ransca)/(highpc-lowpc); 58212892Ssam lastx = 50.; 58312892Ssam for(np = nl; np<npe; np++) { 58412892Ssam if(np->value < lowpc) 58512892Ssam continue; 58612892Ssam if(np->value >= highpc) 58712892Ssam continue; 588*13174Sroot if(zflg == 0 && np->time == 0 && np->ncall == 0) 589*13174Sroot continue; 59012892Ssam time = np->time/totime; 59112892Ssam lasty = ranoff - (np->value - lowpc)*scale; 59212892Ssam if(lasty >= -2040. && lasty <= 2040.) { 59312892Ssam char bufl[BUFSIZ], *namp; 59412892Ssam register j; 59512892Ssam line(0, (int)lasty, 50, (int)lasty); 59612892Ssam line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty); 59712892Ssam move((int)(lastx+30), (int)(lasty+10)); 59812892Ssam sprintf(bufl, "%s", np->name + (np->name[0] == '_')); 59912892Ssam label(bufl); 60012892Ssam } 60112892Ssam lastx += 500.; 60212892Ssam if(lastx > 2000.) 60312892Ssam lastx = 50.; 60412892Ssam } 60512892Ssam } 60612892Ssam #endif 607