Annotation of researchv10no/cmd/lcomp/profmemo, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.