Annotation of researchv10no/cmd/lcomp/profmemo, revision 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.