v08i090: cprof Turbo C version
Brandon S. Allbery - comp.sources.misc
allbery at uunet.UU.NET
Wed Oct 4 09:22:37 AEST 1989
Posting-number: Volume 8, Issue 90
Submitted-by: hjphr at 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 at cc.ic.ac.uk)
* Myrsinis 1
* GR-145 62 Kifisia
* GREECE
*
* Peter J. Holzer (hjphr at 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 |
|____________|__________________________________________________|
More information about the Comp.sources.misc
mailing list