|
|
1.1 ! root 1: .fp 1 B1 ! 2: .fp 2 B2 ! 3: .fp 3 B3 ! 4: .TM 1982-11272-1 11173 39199-11 ! 5: .ND "February 10, 1982" ! 6: .TL ! 7: Dynamic Statement Counting: ! 8: A Manual for Users and Owners ! 9: .AU MH2C522 7214 ! 10: P.J. Weinberger ! 11: .AI ! 12: .MH ! 13: .OK ! 14: Program Testing ! 15: .AB ! 16: Although time profiling is a standard ! 17: .UX ! 18: tool, ! 19: until now there has been no convenient way to find out ! 20: how often each line of a C or Fortran program is executed ! 21: when the program is run. ! 22: This memo describes a simple tool which gives statement and ! 23: instruction execution counts at a modest cost (about 50%) ! 24: in run-time efficiency. ! 25: The programs works on VAXes, and can be modified to work ! 26: on other machines with adequate address space. ! 27: Any user can install and use the programs without ! 28: affecting the compilers, assembler, or loader, and ! 29: without bothering the system administrators. ! 30: .PP ! 31: The typical output ! 32: .DS ! 33: .nf ! 34: .ft CW ! 35: 1 main(argc) ! 36: 1 { int i; ! 37: 1 if(argc > 3) ! 38: 0 exit(1); ! 39: 1 for(i = 0; i < 100; i++) ! 40: 67 if(i % 3 == 0) ! 41: 34 i++; ! 42: 67 } ! 43: .ft P ! 44: .fi ! 45: .DE ! 46: shows how often each line was executed; ! 47: alternative forms would show that ! 48: of the 18 machine instructions, exactly one was never executed, ! 49: or would say how many instructions were executed. ! 50: .AE ! 51: .CS 6 0 6 0 0 1 ! 52: .NH ! 53: What is Execution Counting? ! 54: .PP ! 55: Dynamic execution counting provides counts of how often each part ! 56: of a program was executed. ! 57: The results of several tests can be combined, or the data ! 58: can be collected one run at a time. ! 59: Information about your program can be presented in several forms. ! 60: .NH 2 ! 61: Summarizing Test Coverage ! 62: .PP ! 63: Condensed summary data like ! 64: .DS ! 65: .ft CW ! 66: .nf ! 67: 1962519ie 390i 175ine 471439bbe 106bb 55bbne /usr/sys/pseki/uba.c ! 68: 16893220ie 334i 49ine 5562730bbe 115bb 21bbne /usr/sys/pseki/clock.c ! 69: .fi ! 70: .ft P ! 71: .DE ! 72: says that of the 390 instructions in \f2uba.c\fP 175 were never executed, ! 73: and 49 of the 334 instructions in \f2clock.c\fP were never executed. ! 74: Section 4.1 explains the output fully. ! 75: Data like this summarizes test coverage. ! 76: .NH 2 ! 77: Source Statement Counts ! 78: .PP ! 79: Compiling the program ! 80: .KS ! 81: .nf ! 82: .ft CW ! 83: main() ! 84: { int i; ! 85: for(i = 0; i < 100; i++) ! 86: if(i % 3 == 0) ! 87: i++; ! 88: } ! 89: .fi ! 90: .ft P ! 91: .KE ! 92: with execution counting enabled (see Section 2), and running it once, ! 93: would give the following source statement counts. ! 94: .KS ! 95: .nf ! 96: .ft CW ! 97: 1 main() ! 98: 1 { int i; ! 99: 1 for(i = 0; i < 100; i++) ! 100: 67 if(i % 3 == 0) ! 101: 34 i++; ! 102: 67 } ! 103: .fi ! 104: .ft P ! 105: .KE ! 106: Interpreting the output is discussed in section 4. ! 107: .NH ! 108: The Three Roads to Invoking Execution Counting ! 109: .PP ! 110: The statement count profiler works on C or Fortran programs. ! 111: There are two parts to it, ! 112: one to compile the program with execution counting enabled, ! 113: and the other, named \f2lprint\fP, to print the results. ! 114: The first part, a program named ! 115: .I bb , ! 116: modifies the assembly language produced by the compilers ! 117: by inserting counting instructions at the beginning of each basic block. ! 118: (A basic block is a set of instructions that have to be executed ! 119: if any one of them is.) ! 120: The program described here works only on VAXes, ! 121: but it is easy to modify it to work on almost any machine ! 122: with an adequate address space. ! 123: .PP ! 124: The ease of using the program depends on how easy it is to ! 125: get the local system to interpolate \f2bb\fP ! 126: into the compilation process. ! 127: There are three sorts of systems. ! 128: .NH 2 ! 129: Good Systems ! 130: .PP ! 131: On friendly well-run systems the \f2cc\fP and \f2f77\fP commands ! 132: know about \f2bb\fP. ! 133: The \f2-L\fP (for Line-counting) flag enables execution counts, as in ! 134: .DS ! 135: .nf ! 136: .I ! 137: cc -L main.c subr.c lib.o -o xxx ! 138: .R ! 139: or ! 140: .I ! 141: cc -L -c main.c; cc -L -c subr.c; ! 142: cc -L main.o subr.o lib.o -o xxx ! 143: .R ! 144: .fi ! 145: .DE ! 146: or similarly for \f2f77\fP. ! 147: .PP ! 148: In this example, statement counts will be generated for \f2main.c\fP ! 149: and for \f2subr.c\fP, ! 150: but not for \f2lib.c\fP, ! 151: unless it too had been compiled with \f2-L\fP. ! 152: .NH 2 ! 153: Adequate Systems ! 154: .PP ! 155: An adequate system is one which has the counting software, ! 156: but the software is not integrated into \f2cc\fP. ! 157: The distributed software contains two shell scripts, ! 158: .I lcomp ! 159: and ! 160: .I lcc . ! 161: The former takes any combination of C and Fortran ! 162: source, \f2.o\fP files, and \f2.s\fP files, and produces an ! 163: .I a.out ! 164: file, rather like \f2cc\fP, except that it does not produce ! 165: \&\f2.o\fP files. ! 166: .DS ! 167: .I ! 168: lcomp main.c subr.c lib.o ! 169: .R ! 170: .DE ! 171: has the same effect as the first \f2cc\fP example above, ! 172: except that it produces its output in \f2a.out\fP, ! 173: rather than in \f2xxx\fP. ! 174: .PP ! 175: .I lcc ! 176: is used to prepare \f2.o\fP files, ! 177: so that count profiling can be used with separate compilations. ! 178: The second \f2cc\fP example above would be ! 179: .DS ! 180: .I ! 181: lcc main.c; lcc subr.c; lcomp main.o subr.o lib.o ! 182: .R ! 183: .DE ! 184: on merely adequate systems. ! 185: .NH 2 ! 186: Not Yet Adequate Systems ! 187: .PP ! 188: Your system is less adequate if it does not have this software. ! 189: You can get the counting software by sending mail to me at ! 190: \f2rabbit!pjw\fP, and I will send it to you. ! 191: It can be installed and used without any special help from ! 192: system administrators. ! 193: .NH ! 194: What it Leaves Behind, and Why ! 195: .PP ! 196: After programs have been compiled using either of the techniques ! 197: described above, there will be some new files, ! 198: named \f2main.sL\fP and \f2subr.sL\fP. ! 199: When the \f2a.out\fP executes ! 200: it appends to a file \f2prof.out\fP in the current directory. ! 201: .PP ! 202: The \f2prof.out\fP file contains information on how often each ! 203: basic block was executed. ! 204: The various \f2.sL\fP files contain information correlating ! 205: basic blocks with source lines, and with the instructions in ! 206: the basic block. ! 207: .PP ! 208: Do not move the \f2.sL\fP files, since they are found by their ! 209: full path names. ! 210: .PP ! 211: Since the \f2prof.out\fP is cumulative, it must be empty the ! 212: first time a new version of a program is run. ! 213: The compilation procedures try to remove a lingering \f2prof.out\fP, ! 214: but the user should check carefully. ! 215: .NH ! 216: Getting Output ! 217: .PP ! 218: After you run your program one or more times, ! 219: run the \f2lprint\fP command to produce a listing. ! 220: The listing contains only those files that had some program in them ! 221: executed, and that were compiled with count profiling. ! 222: Here is a simple example. ! 223: .KS ! 224: \f(CW ! 225: ! 226: .nf ! 227: 1 #include "stdio.h" ! 228: 1 main() ! 229: 1 { int n; ! 230: 81 while((n = getchar()) != EOF) putchar(n); ! 231: 1 } ! 232: .fi ! 233: \fP ! 234: .KE ! 235: .PP ! 236: The basic information is that the program \f2main\fP was executed ! 237: once, and the loop was executed 81 times. ! 238: The non-executable lines seem to have been executed also, but that ! 239: is an artifact. ! 240: Each line in the source corresponds to zero, one, or several basic ! 241: blocks, and basic blocks can span several lines of source. ! 242: To each line, the program attributes the next basic block in ! 243: the assembly language, which is usually the correct one when there ! 244: is one basic block corresponding to a line. ! 245: The count of 1 on the closing curly brace above is not an artifact; ! 246: unoptimized programs contain a jump to the end at their entry point. ! 247: These points can be seen more clearly in the following example. ! 248: .KS ! 249: \f(CW ! 250: ! 251: .nf ! 252: 1 #include "stdio.h" ! 253: 1 main() ! 254: 1 { int n, i; ! 255: 1 for( ! 256: 1 i = 0; /* line 5 */ ! 257: 1 (n = getchar()) != EOF; i++) ! 258: 110 putchar(n); ! 259: 1 exit(0); ! 260: 1 } ! 261: .fi ! 262: \fP ! 263: .KE ! 264: For reasons known best to itself, the C compiler ! 265: believes that no code is generated for line 5, so that the ! 266: initialization code, which is executed only once, is associated ! 267: with the next line. ! 268: This flaw would be seen if the program were single-stepped using ! 269: \f2sdb\fP, since \f2bb\fP and \f2sdb\fP use exactly the ! 270: same line-numbers generated by the compiler. ! 271: .PP ! 272: By saying \f2lprint -i\fP the user gets the following, on the same ! 273: data as above. ! 274: .KS ! 275: \f(CW ! 276: ! 277: .nf ! 278: 0i #include "stdio.h" ! 279: 0i main() ! 280: 1i { int n, i; ! 281: 0i for( ! 282: 0i i = 0; ! 283: 1105i (n = getchar()) != EOF; i++) ! 284: 770i putchar(n); ! 285: 2i exit(0); ! 286: 3i } ! 287: .fi ! 288: \fP ! 289: .KE ! 290: The numbers on the left are the number of instructions executed ! 291: for each line. ! 292: The strange attribution of the initialization code to line 6 ! 293: is still present, but it doesn't hide the 1104 other instructions ! 294: executed in line 6. ! 295: .PP ! 296: The command \f2lprint -i -p\fP gets both statement counts and ! 297: instruction counts. ! 298: .NH 2 ! 299: Other Options ! 300: .PP ! 301: \f2lprint\fP has two other options. ! 302: \f2lprint -c\fP compresses the \f2prof.out\fP file. ! 303: After each execution of the profiled program, count data is ! 304: written at the end of \f2prof.out\fP. ! 305: Big programs generate a lot of counting data, ! 306: so that compressing it back to the amount generated by one run ! 307: will save space, and make \f2lprint\fP run faster when ! 308: it is producing listings ! 309: .PP ! 310: \f2lprint -s\fP produces summary data, as in ! 311: .KS ! 312: \f(CW ! 313: ! 314: 1949ie 31i 5ine 691bbe 12bb 1bbne /usr/pjw/prof/a.c ! 315: ! 316: \fP ! 317: .KE ! 318: This line says that \f2/usr/pjw/prof/a.c\fP contains ! 319: 31 assembly instructions and 12 basic blocks. ! 320: During testing (or whatever produced \f2prof.out\fP) ! 321: there were 1949 instruction executions, and 5 of the 31 instructions ! 322: were never executed. ! 323: There were 691 basic blocks executed, and 1 of the 12 basic ! 324: blocks was never executed. ! 325: This option is most useful for summarizing test coverage ! 326: in programs which are made of a lot of files. ! 327: .NH 2 ! 328: Another Peculiarity ! 329: .PP ! 330: The order of the listing may puzzle the user. ! 331: The files are listed in inverse order of first use. ! 332: .NH ! 333: Installing the Distributed Programs ! 334: .PP ! 335: The distribution (mailed out as described in section 2.3) ! 336: contains four C programs, a \f2makefile\fP, ! 337: the two shell scripts \f2lcomp\fP and \f2lcc\fP, ! 338: some manual pages, possibly an up-to-date version of ! 339: this document, and a file that describes installation. ! 340: .PP ! 341: The two C programs \f2instr.c\fP and \f2bb.c\fP ! 342: are to be compiled together to make the program \f2bb\fP. ! 343: \f2bb\fP is the program that modifies the compiler's output ! 344: and leaves behind \f2.sL\fP files for \f2lprint\fP. ! 345: The shell scripts expect to find \f2bb\fP in the directory ! 346: whose name is the value of the shell variable \f2DIR\fP. ! 347: The C program \f2nexit.o\fP (obtained by compiling \f2nexit.c\fP) ! 348: must also be in \f2DIR\fP. ! 349: It must be loaded in place of the standard \f2exit\fP ! 350: routine to get the \f2prof.out\fP file written when the ! 351: program being profiled terminates. ! 352: \f2lcomp\fP runs \f2bb\fP and loads \f2nexit.o\fP. ! 353: .PP ! 354: The two shell files and \f2lprint\fP (obtained by compiling ! 355: \f2lprint.c\fP) should be put in \f2/usr/bin\fP, ! 356: or some place where the user community can find them. ! 357: .NH 2 ! 358: Does It Work? ! 359: .PP ! 360: Try it on one of the example programs given in the first section. ! 361: If you do not get through \f2lcomp\fP because \f2bb\fP fails, ! 362: perhaps you aren't on a VAX. ! 363: A more likely hypothesis is that the assembly language put out ! 364: by your version of the C compiler is incomprehensible to the program. ! 365: This should not happen with any version of ! 366: .UX ! 367: now running on VAXes. ! 368: .PP ! 369: Now run the \f2a.out\fP, and type \f2lprint\fP. ! 370: If you get a listing with counts, all is well. ! 371: If you get nothing, look at the \f2.sL\fP file. ! 372: If there are lines like \f2a.c: 1\fP interspersed with ! 373: the assembly language, and if there is a \f2prof.out\fP ! 374: file, but \f2lprint\fP won't produce output, ! 375: let me know. ! 376: If there are no such lines, then \f2bb\fP failed to find ! 377: symbol table information describing line numbers in the ! 378: C compiler's output. ! 379: This will happen if your C compiler is sufficiently non-standard. ! 380: The subroutine that recognizes file names and line numbers in ! 381: \f2bb.c\fP will have to be changed. ! 382: .PP ! 383: The author would like to hear about problems. ! 384: .NH ! 385: Summary ! 386: .PP ! 387: The statement counting code works on all languages which ! 388: use the assembler: C, Fortran, and (on some systems) Pascal. ! 389: It works on VAXes, an earlier version was easily converted to ! 390: work on Motorola 68000s by Tom London, and it will work on 3Bs ! 391: and 370s soon. ! 392: It can be installed and used without affecting any of the software ! 393: vital to the system and without the help or approval of system ! 394: administrators. ! 395: In particular it renders obsolete a previous test coverage processor ! 396: for C [1]. ! 397: .NH ! 398: Esoterica ! 399: .NH 2 ! 400: Programs that don't Terminate ! 401: .PP ! 402: Some programs, like the operating system, or network daemons, ! 403: are not supposed to terminate, so \f2nexit\fP would never ! 404: be called, so the \f2prof.out\fP file would never be written. ! 405: Nonetheless it is desirable to be able to profile such programs. ! 406: .PP ! 407: Assuming that the programs have been compiled with the ! 408: counting code inserted by \f2bb\fP, the problem ! 409: is to get the counting data out of them periodically. ! 410: Distributed with the source is a file \f2sysprof.c\fP ! 411: which shows how to solve the problem with the kernel. ! 412: A subroutine with the same structure would have to be included ! 413: in a non-terminating user program, ! 414: and invoked either periodically or by a signal. ! 415: .NH 2 ! 416: More Detailed Output ! 417: .PP ! 418: \f2lprint -a\fP prints intermediate data which ! 419: lists each instruction and how often it was executed. ! 420: Here is a Fortran example. ! 421: (C is exactly the same.) ! 422: The Fortran program \f2a.f\fP is ! 423: .KS ! 424: .nf ! 425: \f(CW ! 426: real a(100), b(100), x ! 427: integer i ! 428: do 10 i = 1, 100 ! 429: a(i) = i ! 430: b(i) = i ! 431: 10 continue ! 432: x = 0 ! 433: do 20 i = 1, 100 ! 434: x = x + a(i) * b(i) ! 435: 20 continue ! 436: stop 12 ! 437: end ! 438: \fP ! 439: .fi ! 440: .KE ! 441: The output from \f2lprint -a\fP is ! 442: .DS ! 443: \f(CW ! 444: .nf ! 445: a.f: 1 ! 446: 1 subl2 $LF1,sp ! 447: 1 jmp L12 ! 448: a.f: 2 ! 449: a.f: 3 ! 450: 1 movl $1,r11 ! 451: 100 movl r11,v.1 ! 452: a.f: 4 ! 453: 100 cvtlf r11,r0 ! 454: 100 movf r0,v.2+-4[r11] ! 455: a.f: 5 ! 456: 100 cvtlf r11,r0 ! 457: 100 movf r0,v.3+-4[r11] ! 458: a.f: 6 ! 459: 100 incl r11 ! 460: 100 cmpl r11,$100 ! 461: 100 jleq L17 ! 462: 1 movl r11,v.1 ! 463: a.f: 7 ! 464: 1 clrf v.4 ! 465: a.f: 8 ! 466: 1 movl $1,r11 ! 467: 100 movl r11,v.1 ! 468: a.f: 9 ! 469: 100 mulf3 v.3+-4[r11],v.2+-4[r11],r0 ! 470: 100 addf2 v.4,r0 ! 471: 100 movf r0,v.4 ! 472: a.f: 10 ! 473: 100 incl r11 ! 474: 100 cmpl r11,$100 ! 475: 100 jleq L20 ! 476: 1 movl r11,v.1 ! 477: a.f: 11 ! 478: 1 pushl $2 ! 479: 1 pushl $L21 ! 480: 1 calls $2,_s_stop ! 481: a.f: 12 ! 482: 0 ret ! 483: 1 jmp L13 ! 484: .fi ! 485: \fP ! 486: .DE ! 487: .PP ! 488: From this level of detail, it is possible to answer most ! 489: questions about the behavior of the program. ! 490: .SH ! 491: References ! 492: .LP ! 493: [1] Michael Lesk, A C Profiler for Test Case Verification. TM-80-1274-8. ! 494: .SG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.