home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume8 / cprof_tc < prev    next >
Encoding:
Text File  |  1989-10-03  |  12.9 KB  |  539 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v08i090: cprof Turbo C version
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: hjphr@honey.UUCP
  5.  
  6. Posting-number: Volume 8, Issue 90
  7. Submitted-by: hjphr@honey.UUCP
  8. Archive-name: cprof_tc
  9.  
  10. [...by which time I've switched to my Mac.  (No, don't port it there for me!
  11. I'm using Pascal instead.  ;-)  ++bsa]
  12.  
  13. About a month ago, a profiler for Microsoft C was posted to
  14. comp.sources.misc and you asked about a Turbo-C version.
  15.  
  16. Well, here it is.
  17.  
  18. I have tested it with Turbo C 2.0 and it works fine.
  19.  
  20. It should still work with MSC, but I had no possibility to
  21. test it.
  22.  
  23.     Regards,
  24.         Peter.
  25.  
  26. ----------------------------------------------------------------
  27. /*
  28.  * A C program profiler.
  29.  *
  30.  * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
  31.  *
  32.  * Redistribution and use in source and binary forms are permitted
  33.  * provided that the above copyright notice and this paragraph are
  34.  * duplicated in all such forms and that any documentation,
  35.  * advertising materials, and other materials related to such
  36.  * distribution and use acknowledge that the software was developed
  37.  * by Diomidis Spinellis.
  38.  *
  39.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  40.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  41.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  42.  *
  43.  *
  44.  * Author: Diomidis D. Spinellis (dds@cc.ic.ac.uk)
  45.  *       Myrsinis 1
  46.  *       GR-145 62 Kifisia
  47.  *       GREECE
  48.  *
  49.  *    Peter J. Holzer (hjphr@ehoney.tuwien.ac.at)
  50.  *    Erlachgasse 70
  51.  *    A-1100 Wien
  52.  *    AUSTRIA
  53.  *
  54.  * Modification history:
  55.  *
  56.  * $Log:    PROF.C^v $
  57.  * Revision 1.1  88/11/20  17:33:16  dds
  58.  * Initial revision
  59.  *
  60.  * Revision 1.2        89-09-03    hjp
  61.  * Support for Turbo C added
  62.  *
  63.  */
  64.  
  65. #include <stddef.h>
  66. #include <stdlib.h>
  67. #include <stdio.h>
  68. #include <string.h>
  69. #include <dos.h>
  70.  
  71. #ifdef __TURBOC__
  72. #define _dos_getvect(x) getvect(x)
  73. #define _dos_setvect(i,f) setvect(i,f)
  74. #define onexit(x)    atexit(x)
  75. #define ENDCODE_SYMB    "DATA"
  76. #else
  77. #define ENDCODE_SYMB    "ENDCODE"
  78. #endif
  79.  
  80. /* Linker output maximum line length */
  81. #define LINELEN 129
  82. /* Linker output maximum symbol length */
  83. #define STRLEN    65
  84.  
  85. /* Entries can be absolute or relocatable */
  86. enum relocation { absolute, relocatable };
  87.  
  88. /* Function prototypes */
  89. static void add_proc(char * name, unsigned long addr, enum relocation rel);
  90. static void adjust_proc(long main_offset);
  91. static void install_int(void);
  92. #ifdef __TURBOC__
  93. static void prof_end(void);
  94. #else
  95. static int prof_end(void);
  96. #endif
  97. static void * xmalloc(size_t size);
  98. static void * xrealloc(void * buffer, size_t size);
  99. static char * strsave(char * string);
  100. #ifdef __TURBOC__
  101. static void interrupt far timer_handler (
  102.     unsigned bp,unsigned di,unsigned si,unsigned ds,unsigned es,
  103.     unsigned dx,unsigned cx,unsigned bx,unsigned ax,
  104.     unsigned ip,unsigned cs,unsigned flags);
  105. #else
  106. static void interrupt far timer_handler (unsigned es,unsigned ds,unsigned di,unsigned si,unsigned bp,
  107.         unsigned sp,unsigned bx,unsigned dx,unsigned cx,unsigned ax,unsigned ip,unsigned cs,unsigned flags);
  108. #endif
  109. void main(int argc, char *argv[]);
  110. #ifdef DEBUG
  111. static void dump_table(void);
  112. static void test_search(void);
  113. static void disp(long n);
  114. #endif
  115.  
  116. static char rcsid[] = "$Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $";
  117. static char VER[] = "@(#)    prof.c    1.2    89-09-03    hjp";
  118.  
  119. void
  120. prof_start(char * argv0)
  121. {
  122.     FILE *f;
  123.     static char fname[65];
  124.     static char line[LINELEN];
  125.     static char str1[STRLEN], str2[STRLEN], str3[STRLEN], str4[STRLEN],
  126.             str5[STRLEN];
  127.     enum {searchsegs, scansegs, searchprocs, scanprocs } state;
  128.     static char *state_errs[] = {
  129.         "start of segment definitions",
  130.         ENDCODE_SYMB " segment definition",
  131.         "the ``Publics by Value'' line",
  132.         "address greater than " ENDCODE_SYMB " was found"
  133.     };
  134.     unsigned int seg, off;
  135.     unsigned long endcode;
  136.     int linenum = 0;
  137.     unsigned long main_addr, addr;
  138.     long main_offset = -1;
  139.     void far * main_p;
  140.  
  141.     /* Find the address of main to adjust everything else */
  142.     main_p = (void far *)main;
  143.     main_addr = ((unsigned long)FP_SEG(main_p) << 4) +
  144.              (unsigned long)FP_OFF(main_p);
  145.     #ifdef DEBUG
  146.     printf("main=%08lx\n", main_addr);
  147.     #endif
  148.  
  149.     add_proc("DOS", 0l, absolute);
  150.     strcpy(fname, argv0);
  151.     strcpy(strrchr(fname, '.'), ".MAP");
  152.  
  153.     if ((f = fopen(fname, "r")) == NULL) {
  154.         perror(fname);
  155.         exit(1);
  156.     }
  157.  
  158.     state = searchsegs;
  159.     while (fgets(line, LINELEN, f)) {
  160.         linenum++;
  161.         if (* line == '\n') continue;    /*    ignore empty lines    */
  162.         switch (state) {
  163.         case searchsegs :
  164.             if (sscanf(line, " %s %s %s %s %s ",
  165.                    str1, str2, str3, str4, str5) == 5 &&
  166.                    strcmp(str1, "Start") == 0 &&
  167.                    strcmp(str2, "Stop") == 0 &&
  168.                    strcmp(str3, "Length") == 0 &&
  169.                    strcmp(str4, "Name") == 0 &&
  170.                    strcmp(str5, "Class") == 0)
  171.                 state = scansegs;
  172.             break;
  173.         case scansegs :
  174.             if (sscanf(line, " %lxH %*lxH %*lxH %*s %s ",
  175.                    &endcode, str1) != 2) {
  176.                 fprintf(stderr,
  177.                     "%s(%d) : Unable to parse line : %s\n",
  178.                     fname, linenum, line);
  179.                 exit(1);
  180.             }
  181.             if (strcmp(str1, ENDCODE_SYMB) == 0)
  182.                 state = searchprocs;
  183.             break;
  184.         case searchprocs :
  185.             if (sscanf(line, " %s %s %s %s ", str1, str2, str3,
  186.                    str4) == 4 &&
  187.                    strcmp(str1, "Address") == 0 &&
  188.                    strcmp(str2, "Publics") == 0 &&
  189.                    strcmp(str3, "by") == 0 &&
  190.                    strcmp(str4, "Value") == 0)
  191.                 state = scanprocs;
  192.             break;
  193.         case scanprocs :
  194.             if (*line == '\n' || sscanf(line, " %x:%x Abs %s ",
  195.                             &seg, &off, str1) == 3)
  196.                 break;
  197.             if (sscanf(line, " %x:%x %s ", &seg, &off, str1) != 3) {
  198.                 fprintf(stderr,
  199.                     "%s(%d) : Unable to parse line : %s\n",
  200.                     fname, linenum, line);
  201.                 exit(1);
  202.             }
  203.             addr = ((unsigned long)seg << 4) + (unsigned long)off;
  204.             if (strcmp(str1, "_main") == 0)
  205.                 main_offset = addr;
  206.             add_proc(str1, addr + main_addr, relocatable);
  207.             if (addr > endcode) {
  208.                 /*
  209.                  * Add here in ascending order any important
  210.                  * memory bounds. One idea would be to partition
  211.                  * the BIOS in tasks e.g. printer, screen etc.
  212.                  */
  213.                 add_proc("UNKOWN", addr + main_addr + 1,
  214.                       relocatable);
  215.                 add_proc("EGA_BIOS", 0xc0000l, absolute);
  216.                 add_proc("FDISK_BIOS", 0xc8000l, absolute);
  217.                 add_proc("SYSTEM_ROM", 0xf0000l, absolute);
  218.                 add_proc("SYSTEM_BIOS", 0xfe000l, absolute);
  219.                 add_proc("OUTER_SPACE", (unsigned long)-1l,
  220.                       absolute);
  221.                 fclose(f);
  222.                 if (main_offset == -1) {
  223.                     fputs("_main address not found\n",
  224.                           stderr);
  225.                     exit(1);
  226.                 }
  227.                 adjust_proc(main_offset);
  228.                 #ifdef __TURBOC__
  229.                 if (atexit(prof_end) != 0) {
  230.                     fputs("atexit failed\n", stderr);
  231.                     exit(1);
  232.                 }
  233.                 #else
  234.                 if (onexit(prof_end) == NULL) {
  235.                     fputs("onexit failed\n", stderr);
  236.                     exit(1);
  237.                 }
  238.                 #endif
  239.                 #ifdef DEBUG
  240.                 dump_table();
  241.                 test_search();
  242.                 #endif
  243.                 install_int();
  244.                 return ;
  245.             }
  246.         }
  247.     }
  248.     /* Something went wrong */
  249.     fprintf(stderr, "%s(%d) EOF reached before %s\n", fname, linenum,
  250.         state_errs[state]);
  251.     exit(1);
  252. }
  253.  
  254. /* The structure where procedures are kept */
  255. static struct proc_data {
  256.     unsigned long addr ;            /* Procedure start address */
  257.     unsigned long count ;            /* Hit count set by interrupt */
  258.     char *name ;                /* Procedure name */
  259.     enum relocation rel ;            /* Relocation type */
  260. } *procs;
  261.  
  262. /* Number of procedures and allocated memory */
  263. static int procnum, procalloc;
  264.  
  265. /* Size of memory allocation chunk */
  266. #define BLK    30
  267.  
  268. /* Define a procedure */
  269. static void
  270. add_proc(char * name, unsigned long addr, enum relocation rel)
  271. {
  272.     if (procs == NULL) {
  273.         procs = xmalloc(sizeof(struct proc_data) * BLK);
  274.         procalloc = BLK;
  275.     }
  276.     procs[procnum].addr = addr;
  277.     procs[procnum].count = 0l;
  278.     procs[procnum].name = strsave(name);
  279.     procs[procnum].rel = rel;
  280.     procnum++;
  281.     if (procnum >= procalloc) {
  282.         procalloc += BLK;
  283.         procs = xrealloc(procs, sizeof(struct proc_data) *
  284.                   procalloc);
  285.     }
  286. }
  287.  
  288. /*
  289.  * Adjust downwards the memory allocated for procedure data storage
  290.  * and subtract main_offset.
  291.  */
  292. static void
  293. adjust_proc(long main_offset)
  294. {
  295.     struct proc_data *pp;
  296.  
  297.     procs = xrealloc(procs, sizeof(struct proc_data) * procnum);
  298.     for (pp = procs ; pp < &procs[procnum] ; pp++)
  299.         if (pp->rel == relocatable)
  300.             pp->addr -= main_offset;
  301. }
  302.  
  303. /* Timer interrupt (Do not use 0x1c since it is always called from BIOS) */
  304. #define TIMER_INT    8
  305.  
  306. /* Old timer handler to chain to */
  307. static void (interrupt far * old_timer_handler)(void);
  308.  
  309. /* Disable timer handler and print the profiling results */
  310.  
  311. #ifdef __TURBOC__
  312. static void
  313. #else
  314. static int
  315. #endif
  316. prof_end(void)
  317. {
  318.     register i;
  319.     FILE *f;
  320.  
  321.     _dos_setvect(TIMER_INT, old_timer_handler);
  322.     if ((f = fopen("prof.out", "w")) == NULL) {
  323.         perror("prof.out");
  324.         #ifdef __TURBOC__
  325.         return;
  326.         #else
  327.         return 1;
  328.         #endif
  329.     }
  330.     for (i = 0 ; i < procnum ; i++)
  331.         fprintf(f, "%s %ld\n", procs[i].name, procs[i].count);
  332.     fclose(f);
  333.     #ifdef __TURBOC__
  334.     return;
  335.     #else
  336.     return 0;
  337.     #endif
  338. }
  339.  
  340. /* Allocate memory with error checking. */
  341. static void *
  342. xmalloc(size_t size)
  343. {
  344.     void * p;
  345.  
  346.     if ((p = malloc(size)) == NULL) {
  347.         fputs("Profiler : Out of memory\n", stderr);
  348.         exit(1);
  349.     }
  350.     return p;
  351. }
  352.  
  353. /* Reallocate memory with error checking.  */
  354. static void *
  355. xrealloc(void * buffer, size_t size)
  356. {
  357.     void * p;
  358.  
  359.  
  360.     if ((p = realloc(buffer, size)) == NULL) {
  361.         fputs("Profiler : Out of memory\n", stderr);
  362.         exit(1);
  363.     }
  364.     return p;
  365. }
  366.  
  367. /* Save a string in allocated memory */
  368. static char *
  369. strsave(char * string)
  370. {
  371.     return strcpy(xmalloc(strlen(string) + 1), string);
  372. }
  373.  
  374. /* The timer interrupt handler */
  375. #ifdef __TURBOC__
  376. static void interrupt far
  377. timer_handler(unsigned bp,unsigned di,unsigned si,unsigned ds,unsigned es,
  378.           unsigned dx,unsigned cx,unsigned bx,unsigned ax,
  379.           unsigned ip,unsigned cs,unsigned flags)
  380. #else
  381. static void interrupt far
  382. timer_handler(unsigned es,unsigned ds,unsigned di,unsigned si,unsigned bp,
  383.           unsigned sp,unsigned bx,unsigned dx,unsigned cx,unsigned ax,
  384.           unsigned ip,unsigned cs,unsigned flags)
  385. #endif
  386. {
  387.     long addr;
  388.     int lower, upper, middle;
  389.  
  390.     addr = ((unsigned long)cs << 4) + (unsigned long)ip;
  391.  
  392.     #ifdef DEBUG
  393.     disp(addr);
  394.     #endif
  395.     /*
  396.      * Precondition :
  397.      * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
  398.      */
  399.     lower = 0;
  400.     upper = procnum - 2;
  401.     /*
  402.      * Invariant :
  403.      * { a[l] <= addr < a[u] }
  404.      * Variant :
  405.      * { u - l }
  406.      */
  407.     while (upper - lower > 1) {
  408.         middle = (lower + upper) / 2;
  409.         /*
  410.          * m = l + (u - l) / 2 = (u + l) / 2
  411.          * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
  412.          * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
  413.          * m = l + (u - l) / 2 >= l + 1 implies m > l
  414.          */
  415.         if (procs[middle].addr <= addr)
  416.             lower = middle;
  417.         else
  418.             upper = middle;
  419.     }
  420.     /*
  421.      * Postcondition :
  422.      * { a[f] <= addr < a[f + 1] } which can be expressed as:
  423.      * { a[l] <= addr < a[u] & u = l + 1 }
  424.      */
  425.     procs[lower].count++;
  426.     (*old_timer_handler)();
  427. #ifndef __TURBOC__
  428.     /* Silence warnings */
  429.     (void)(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags);
  430. #endif
  431. }
  432.  
  433. /* Install the interrupt driver */
  434. static void
  435. install_int(void)
  436. {
  437.     old_timer_handler = _dos_getvect(TIMER_INT);
  438.     _dos_setvect(TIMER_INT, timer_handler);
  439. }
  440.  
  441. #ifdef DEBUG
  442.  
  443. /* Very fast display of a number on the screen. (Define MDA for mono adapter) */
  444.  
  445. #ifdef MDA
  446. #define REGEN_BASE 0xb0000000
  447. #else /* CGA */
  448. #define REGEN_BASE 0xb8000000
  449. #endif
  450.  
  451. static void
  452. disp(long n)
  453. {
  454.     register i;
  455.     char far * sb = (char far *)(REGEN_BASE + 20);
  456.  
  457.     for (i = 0 ; i < 8 ; i++) {
  458.         *sb = "0123456789abcdef"[(int)n & 0xF];
  459.         n >>= 4;
  460.         sb -= 2;
  461.     }
  462. }
  463.  
  464. /* Test the binary search algorithm */
  465. static void
  466. pr_name(long addr)
  467. {
  468.     int lower, upper, middle;
  469.  
  470.     /*
  471.      * Precondition :
  472.      * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
  473.      */
  474.     lower = 0;
  475.     upper = procnum - 2;
  476.     /*
  477.      * Invariant :
  478.      * { a[l] <= addr < a[u] }
  479.      * Variant :
  480.      * { u - l }
  481.      */
  482.     while (upper - lower > 1) {
  483.         middle = (lower + upper) / 2;
  484.         /*
  485.          * m = l + (u - l) / 2 = (u + l) / 2
  486.          * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
  487.          * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
  488.          * m = l + (u - l) / 2 >= l + 1 implies m > l
  489.          */
  490.         if (procs[middle].addr <= addr)
  491.             lower = middle;
  492.         else
  493.             upper = middle;
  494.         printf("%5d %5d %5d\n", lower, middle, upper);
  495.     }
  496.     /*
  497.      * Postcondition :
  498.      * { a[f] <= addr < a[f + 1] } which can be expressed as:
  499.      * { a[l] <= addr < a[u] & u = l + 1 }
  500.      */
  501.     puts(procs[lower].name);
  502. }
  503.  
  504. /* Interact with the user testing the search algorithm */
  505. static void
  506. test_search()
  507. {
  508.     char buff[80];
  509.     long addr;
  510.  
  511.     puts("Enter -1 to finish");
  512.     do{
  513.         gets(buff);
  514.         sscanf(buff, " %lx ", &addr);
  515.         pr_name(addr);
  516.     } while (addr != -1l);
  517. }
  518.  
  519. /* Dump the procedure table */
  520. static void
  521. dump_table()
  522. {
  523.     struct proc_data *pd;
  524.  
  525.     for (pd = procs ; pd < &procs[procnum] ; pd++)
  526.         printf("%08lx    %s\n", pd->addr, pd->name);
  527. }
  528. #endif
  529. ----------------------------------------------------------------
  530.  _______________________________________________________________
  531. |    __   |                            |
  532. |  |   |  \  | Peter J. Holzer                    |
  533. |  |___|__/  | Technische Universitaet Wien            |
  534. |  |   |     |                            |
  535. |  |   |     | ...!uunet!mcvax!tuvie!asupa!honey!hjphr        |
  536. |  ____/     |--------------------------------------------------|
  537. |         | Think of it as evolution in action -- Tony Rand    |
  538. |____________|__________________________________________________|
  539.