home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- subject: v08i090: cprof Turbo C version
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Reply-To: hjphr@honey.UUCP
-
- Posting-number: Volume 8, Issue 90
- Submitted-by: hjphr@honey.UUCP
- Archive-name: cprof_tc
-
- [...by which time I've switched to my Mac. (No, don't port it there for me!
- I'm using Pascal instead. ;-) ++bsa]
-
- About a month ago, a profiler for Microsoft C was posted to
- comp.sources.misc and you asked about a Turbo-C version.
-
- Well, here it is.
-
- I have tested it with Turbo C 2.0 and it works fine.
-
- It should still work with MSC, but I had no possibility to
- test it.
-
- Regards,
- Peter.
-
- ----------------------------------------------------------------
- /*
- * A C program profiler.
- *
- * (C) Copyright 1988, 1989 Diomidis D. Spinellis. All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Diomidis Spinellis.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- *
- * Author: Diomidis D. Spinellis (dds@cc.ic.ac.uk)
- * Myrsinis 1
- * GR-145 62 Kifisia
- * GREECE
- *
- * Peter J. Holzer (hjphr@ehoney.tuwien.ac.at)
- * Erlachgasse 70
- * A-1100 Wien
- * AUSTRIA
- *
- * Modification history:
- *
- * $Log: PROF.C^v $
- * Revision 1.1 88/11/20 17:33:16 dds
- * Initial revision
- *
- * Revision 1.2 89-09-03 hjp
- * Support for Turbo C added
- *
- */
-
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <dos.h>
-
- #ifdef __TURBOC__
- #define _dos_getvect(x) getvect(x)
- #define _dos_setvect(i,f) setvect(i,f)
- #define onexit(x) atexit(x)
- #define ENDCODE_SYMB "DATA"
- #else
- #define ENDCODE_SYMB "ENDCODE"
- #endif
-
- /* Linker output maximum line length */
- #define LINELEN 129
- /* Linker output maximum symbol length */
- #define STRLEN 65
-
- /* Entries can be absolute or relocatable */
- enum relocation { absolute, relocatable };
-
- /* Function prototypes */
- static void add_proc(char * name, unsigned long addr, enum relocation rel);
- static void adjust_proc(long main_offset);
- static void install_int(void);
- #ifdef __TURBOC__
- static void prof_end(void);
- #else
- static int prof_end(void);
- #endif
- static void * xmalloc(size_t size);
- static void * xrealloc(void * buffer, size_t size);
- static char * strsave(char * string);
- #ifdef __TURBOC__
- static void interrupt far timer_handler (
- unsigned bp,unsigned di,unsigned si,unsigned ds,unsigned es,
- unsigned dx,unsigned cx,unsigned bx,unsigned ax,
- unsigned ip,unsigned cs,unsigned flags);
- #else
- static void interrupt far timer_handler (unsigned es,unsigned ds,unsigned di,unsigned si,unsigned bp,
- unsigned sp,unsigned bx,unsigned dx,unsigned cx,unsigned ax,unsigned ip,unsigned cs,unsigned flags);
- #endif
- void main(int argc, char *argv[]);
- #ifdef DEBUG
- static void dump_table(void);
- static void test_search(void);
- static void disp(long n);
- #endif
-
- static char rcsid[] = "$Header: PROF.C^v 1.1 88/11/20 17:33:16 dds Rel $";
- static char VER[] = "@(#) prof.c 1.2 89-09-03 hjp";
-
- void
- prof_start(char * argv0)
- {
- FILE *f;
- static char fname[65];
- static char line[LINELEN];
- static char str1[STRLEN], str2[STRLEN], str3[STRLEN], str4[STRLEN],
- str5[STRLEN];
- enum {searchsegs, scansegs, searchprocs, scanprocs } state;
- static char *state_errs[] = {
- "start of segment definitions",
- ENDCODE_SYMB " segment definition",
- "the ``Publics by Value'' line",
- "address greater than " ENDCODE_SYMB " was found"
- };
- unsigned int seg, off;
- unsigned long endcode;
- int linenum = 0;
- unsigned long main_addr, addr;
- long main_offset = -1;
- void far * main_p;
-
- /* Find the address of main to adjust everything else */
- main_p = (void far *)main;
- main_addr = ((unsigned long)FP_SEG(main_p) << 4) +
- (unsigned long)FP_OFF(main_p);
- #ifdef DEBUG
- printf("main=%08lx\n", main_addr);
- #endif
-
- add_proc("DOS", 0l, absolute);
- strcpy(fname, argv0);
- strcpy(strrchr(fname, '.'), ".MAP");
-
- if ((f = fopen(fname, "r")) == NULL) {
- perror(fname);
- exit(1);
- }
-
- state = searchsegs;
- while (fgets(line, LINELEN, f)) {
- linenum++;
- if (* line == '\n') continue; /* ignore empty lines */
- switch (state) {
- case searchsegs :
- if (sscanf(line, " %s %s %s %s %s ",
- str1, str2, str3, str4, str5) == 5 &&
- strcmp(str1, "Start") == 0 &&
- strcmp(str2, "Stop") == 0 &&
- strcmp(str3, "Length") == 0 &&
- strcmp(str4, "Name") == 0 &&
- strcmp(str5, "Class") == 0)
- state = scansegs;
- break;
- case scansegs :
- if (sscanf(line, " %lxH %*lxH %*lxH %*s %s ",
- &endcode, str1) != 2) {
- fprintf(stderr,
- "%s(%d) : Unable to parse line : %s\n",
- fname, linenum, line);
- exit(1);
- }
- if (strcmp(str1, ENDCODE_SYMB) == 0)
- state = searchprocs;
- break;
- case searchprocs :
- if (sscanf(line, " %s %s %s %s ", str1, str2, str3,
- str4) == 4 &&
- strcmp(str1, "Address") == 0 &&
- strcmp(str2, "Publics") == 0 &&
- strcmp(str3, "by") == 0 &&
- strcmp(str4, "Value") == 0)
- state = scanprocs;
- break;
- case scanprocs :
- if (*line == '\n' || sscanf(line, " %x:%x Abs %s ",
- &seg, &off, str1) == 3)
- break;
- if (sscanf(line, " %x:%x %s ", &seg, &off, str1) != 3) {
- fprintf(stderr,
- "%s(%d) : Unable to parse line : %s\n",
- fname, linenum, line);
- exit(1);
- }
- addr = ((unsigned long)seg << 4) + (unsigned long)off;
- if (strcmp(str1, "_main") == 0)
- main_offset = addr;
- add_proc(str1, addr + main_addr, relocatable);
- if (addr > endcode) {
- /*
- * Add here in ascending order any important
- * memory bounds. One idea would be to partition
- * the BIOS in tasks e.g. printer, screen etc.
- */
- add_proc("UNKOWN", addr + main_addr + 1,
- relocatable);
- add_proc("EGA_BIOS", 0xc0000l, absolute);
- add_proc("FDISK_BIOS", 0xc8000l, absolute);
- add_proc("SYSTEM_ROM", 0xf0000l, absolute);
- add_proc("SYSTEM_BIOS", 0xfe000l, absolute);
- add_proc("OUTER_SPACE", (unsigned long)-1l,
- absolute);
- fclose(f);
- if (main_offset == -1) {
- fputs("_main address not found\n",
- stderr);
- exit(1);
- }
- adjust_proc(main_offset);
- #ifdef __TURBOC__
- if (atexit(prof_end) != 0) {
- fputs("atexit failed\n", stderr);
- exit(1);
- }
- #else
- if (onexit(prof_end) == NULL) {
- fputs("onexit failed\n", stderr);
- exit(1);
- }
- #endif
- #ifdef DEBUG
- dump_table();
- test_search();
- #endif
- install_int();
- return ;
- }
- }
- }
- /* Something went wrong */
- fprintf(stderr, "%s(%d) EOF reached before %s\n", fname, linenum,
- state_errs[state]);
- exit(1);
- }
-
- /* The structure where procedures are kept */
- static struct proc_data {
- unsigned long addr ; /* Procedure start address */
- unsigned long count ; /* Hit count set by interrupt */
- char *name ; /* Procedure name */
- enum relocation rel ; /* Relocation type */
- } *procs;
-
- /* Number of procedures and allocated memory */
- static int procnum, procalloc;
-
- /* Size of memory allocation chunk */
- #define BLK 30
-
- /* Define a procedure */
- static void
- add_proc(char * name, unsigned long addr, enum relocation rel)
- {
- if (procs == NULL) {
- procs = xmalloc(sizeof(struct proc_data) * BLK);
- procalloc = BLK;
- }
- procs[procnum].addr = addr;
- procs[procnum].count = 0l;
- procs[procnum].name = strsave(name);
- procs[procnum].rel = rel;
- procnum++;
- if (procnum >= procalloc) {
- procalloc += BLK;
- procs = xrealloc(procs, sizeof(struct proc_data) *
- procalloc);
- }
- }
-
- /*
- * Adjust downwards the memory allocated for procedure data storage
- * and subtract main_offset.
- */
- static void
- adjust_proc(long main_offset)
- {
- struct proc_data *pp;
-
- procs = xrealloc(procs, sizeof(struct proc_data) * procnum);
- for (pp = procs ; pp < &procs[procnum] ; pp++)
- if (pp->rel == relocatable)
- pp->addr -= main_offset;
- }
-
- /* Timer interrupt (Do not use 0x1c since it is always called from BIOS) */
- #define TIMER_INT 8
-
- /* Old timer handler to chain to */
- static void (interrupt far * old_timer_handler)(void);
-
- /* Disable timer handler and print the profiling results */
-
- #ifdef __TURBOC__
- static void
- #else
- static int
- #endif
- prof_end(void)
- {
- register i;
- FILE *f;
-
- _dos_setvect(TIMER_INT, old_timer_handler);
- if ((f = fopen("prof.out", "w")) == NULL) {
- perror("prof.out");
- #ifdef __TURBOC__
- return;
- #else
- return 1;
- #endif
- }
- for (i = 0 ; i < procnum ; i++)
- fprintf(f, "%s %ld\n", procs[i].name, procs[i].count);
- fclose(f);
- #ifdef __TURBOC__
- return;
- #else
- return 0;
- #endif
- }
-
- /* Allocate memory with error checking. */
- static void *
- xmalloc(size_t size)
- {
- void * p;
-
- if ((p = malloc(size)) == NULL) {
- fputs("Profiler : Out of memory\n", stderr);
- exit(1);
- }
- return p;
- }
-
- /* Reallocate memory with error checking. */
- static void *
- xrealloc(void * buffer, size_t size)
- {
- void * p;
-
-
- if ((p = realloc(buffer, size)) == NULL) {
- fputs("Profiler : Out of memory\n", stderr);
- exit(1);
- }
- return p;
- }
-
- /* Save a string in allocated memory */
- static char *
- strsave(char * string)
- {
- return strcpy(xmalloc(strlen(string) + 1), string);
- }
-
- /* The timer interrupt handler */
- #ifdef __TURBOC__
- static void interrupt far
- timer_handler(unsigned bp,unsigned di,unsigned si,unsigned ds,unsigned es,
- unsigned dx,unsigned cx,unsigned bx,unsigned ax,
- unsigned ip,unsigned cs,unsigned flags)
- #else
- static void interrupt far
- timer_handler(unsigned es,unsigned ds,unsigned di,unsigned si,unsigned bp,
- unsigned sp,unsigned bx,unsigned dx,unsigned cx,unsigned ax,
- unsigned ip,unsigned cs,unsigned flags)
- #endif
- {
- long addr;
- int lower, upper, middle;
-
- addr = ((unsigned long)cs << 4) + (unsigned long)ip;
-
- #ifdef DEBUG
- disp(addr);
- #endif
- /*
- * Precondition :
- * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
- */
- lower = 0;
- upper = procnum - 2;
- /*
- * Invariant :
- * { a[l] <= addr < a[u] }
- * Variant :
- * { u - l }
- */
- while (upper - lower > 1) {
- middle = (lower + upper) / 2;
- /*
- * m = l + (u - l) / 2 = (u + l) / 2
- * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
- * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
- * m = l + (u - l) / 2 >= l + 1 implies m > l
- */
- if (procs[middle].addr <= addr)
- lower = middle;
- else
- upper = middle;
- }
- /*
- * Postcondition :
- * { a[f] <= addr < a[f + 1] } which can be expressed as:
- * { a[l] <= addr < a[u] & u = l + 1 }
- */
- procs[lower].count++;
- (*old_timer_handler)();
- #ifndef __TURBOC__
- /* Silence warnings */
- (void)(es,ds,di,si,bp,sp,bx,dx,cx,ax,ip,cs,flags);
- #endif
- }
-
- /* Install the interrupt driver */
- static void
- install_int(void)
- {
- old_timer_handler = _dos_getvect(TIMER_INT);
- _dos_setvect(TIMER_INT, timer_handler);
- }
-
- #ifdef DEBUG
-
- /* Very fast display of a number on the screen. (Define MDA for mono adapter) */
-
- #ifdef MDA
- #define REGEN_BASE 0xb0000000
- #else /* CGA */
- #define REGEN_BASE 0xb8000000
- #endif
-
- static void
- disp(long n)
- {
- register i;
- char far * sb = (char far *)(REGEN_BASE + 20);
-
- for (i = 0 ; i < 8 ; i++) {
- *sb = "0123456789abcdef"[(int)n & 0xF];
- n >>= 4;
- sb -= 2;
- }
- }
-
- /* Test the binary search algorithm */
- static void
- pr_name(long addr)
- {
- int lower, upper, middle;
-
- /*
- * Precondition :
- * { a[k] < a[k+1] & 0 <= k <= procnum & a[0] <= addr < a[procnum] }
- */
- lower = 0;
- upper = procnum - 2;
- /*
- * Invariant :
- * { a[l] <= addr < a[u] }
- * Variant :
- * { u - l }
- */
- while (upper - lower > 1) {
- middle = (lower + upper) / 2;
- /*
- * m = l + (u - l) / 2 = (u + l) / 2
- * m = l + (u - l) / 2 & u - l > 1 implies l < m < u as:
- * m = (u + l) / 2 < (u + u) / 2 = u implies m < u
- * m = l + (u - l) / 2 >= l + 1 implies m > l
- */
- if (procs[middle].addr <= addr)
- lower = middle;
- else
- upper = middle;
- printf("%5d %5d %5d\n", lower, middle, upper);
- }
- /*
- * Postcondition :
- * { a[f] <= addr < a[f + 1] } which can be expressed as:
- * { a[l] <= addr < a[u] & u = l + 1 }
- */
- puts(procs[lower].name);
- }
-
- /* Interact with the user testing the search algorithm */
- static void
- test_search()
- {
- char buff[80];
- long addr;
-
- puts("Enter -1 to finish");
- do{
- gets(buff);
- sscanf(buff, " %lx ", &addr);
- pr_name(addr);
- } while (addr != -1l);
- }
-
- /* Dump the procedure table */
- static void
- dump_table()
- {
- struct proc_data *pd;
-
- for (pd = procs ; pd < &procs[procnum] ; pd++)
- printf("%08lx %s\n", pd->addr, pd->name);
- }
- #endif
- ----------------------------------------------------------------
- _______________________________________________________________
- | __ | |
- | | | \ | Peter J. Holzer |
- | |___|__/ | Technische Universitaet Wien |
- | | | | |
- | | | | ...!uunet!mcvax!tuvie!asupa!honey!hjphr |
- | ____/ |--------------------------------------------------|
- | | Think of it as evolution in action -- Tony Rand |
- |____________|__________________________________________________|
-