home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume8 / prof.msc / prof.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-19  |  10.3 KB  |  441 lines

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