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