home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
355_01
/
slk1.exe
/
MEASURE
/
MEASURE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-04
|
13KB
|
610 lines
/*
Suggest appropriate values for the TIME_ADJUST constant.
source: measure.c
started: August 2, 1989
version: see below
By setting the TIME_ADJUST constant to the value proposed by this
program, you should more accurate timing statistics.
The TIME_ADJUST constant is used only in the sl_adjust() function
in Sherlock.c. It is used to subtract the "unmeasured overhead"
caused by calling and returning from Sherlock support routines.
This program measures this "unmeasured overhead" by calling dummy
Sherlock routines and counting the ticks that result.
WARNING: This program defines a value for sl_speed, which must match
the value of sl_speed used in sherlock.c in order for this program
to give a reasonable suggestion for the value of TIME_ADJUST.
By default, sl_speed is initialized to 55 in this file and in
sherlock.c. This program prints the value of sl_speed right after
signing on.
The units of TIME_ADJUST are ticks per 1000 "average" calls to
Sherlock macros. Since there is no way to determine exactly what
an average call really is, using TIME_ADJUST will probably not produce
perfect statistics.
The sl_adjust() routine in sherlock.c handles the details of adjusting
the statistics based on TIME_ADJUST. The TIME_ADJUST constant does not
affect the gathering of statistics in any way, just the way that
sl_dump() reports the statistics already gathered.
Exactly one of the constants FAR_MODEL and NEAR_MODEL should be
#defined on the command line of this program. The program M1.EXE
should be compiled with NEAR_MODEL #defined. The program M2.EXE
should be compiled with FAR_MODEL #defined.
The values reported by M1.EXE and M2.EXE will be different. Modify the
make files for the tiny, small and compact models to use the value
suggested by M1.EXE. Modify the make files for the medium, large and
huge memory model to the value suggested by M2.EXE. The make files
distributed with Sherlock use 0 for TIME_ADJUST, as follows:
-DTIME_ADJUST=0 Turbo C
/DTIME_ADJUST=0 MicroSoft C
Both M1.EXE and M2.EXE suggest two values for TIME_ADJUST,
one value for when using the preferred macros and one value for
when using the alternate macros. Make sure to use to proper value.
In the interest of getting the best statistics, several routines below
are passed parameters that are never used, or assign values to
variables which are never used. The Turbo C compiler will issue
warnings about such matters, and those warnings can safely be ignored.
The -w-aus and -w-par compiler options are used to suppress these
warnings in measure.mak.
*/
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <string.h>
#include <ctype.h>
#define VERSION "August 4, 1989\n"
/*
WARNING! This value of sl_speed should match that in sherlock.c!
*/
int sl_speed = 55;
unsigned long sl_count = 0;
#define TRUE (1)
#define FALSE (0)
#define BAD_EXIT (1)
/*
Define data structure used by the dummy Sherlock routines.
*/
struct stat {
struct stat * next; /* pointer to next bucket. */
struct stat * alpha; /* alphabetical list. */
char * name; /* pointer to checkpoint name. */
long n_stat; /* # of calls to macros. */
long n_disable; /* # of prints to skip or 0. */
long n_times; /* # of profiler ticks. */
long n_2times; /* Cumulative ticks. */
long n_ftime; /* single execution time. 8/3/89 */
int trace; /* trace flag. */
};
struct stat a_list;
#define MAX_STAT 500
struct stat sl__nodes [MAX_STAT]; /* Static node table. */
int cur_stat = 0;
#define MAX_BUG_LEVEL 100
struct stat * call_stack [MAX_BUG_LEVEL];
int sl_level = 0;
#define MAX_HASH 241
struct stat * hash_tab [MAX_HASH];
struct stat * wildcard = NULL; /* Head of wildcard list. */
int troff = FALSE; /* TRUE if all tracing disabled. */
char * check_s = NULL; /* Name of current macro. */
long disable = 0; /* Local disable count. */
long g_disable = 0; /* Global disable printing counter. */
unsigned long t_check = 0;
unsigned long t_find = 0;
unsigned long t_new = 0;
/*
Function prototypes for dummy Sherlock routines.
*/
int sl_ret (void);
int sl_visit (struct stat *p, int stat_flag, int entry_flag);
int sl1trace (char * name);
int sl2trace (struct stat ** h, char * name);
void sl_check (char *);
struct stat * sl_find (char *, char *);
int sl_hash (char *);
int prefix (char *, char *);
struct stat * sl_new (char *);
void sl_init (char *);
void sl_cout (char);
void sl_sout (char *);
void sl_s2out (char *, char *);
void sl_s3out (char *, char *, char *);
void sl_slout (int, char *);
int sl_visit (struct stat *, int, int);
int has_wild (char *);
int is_match (char *, char *);
int strcmp_ (char *, char *);
int streq_ (char *, char *);
/*
Dummy Sherlock macros.
*/
#define TRACEPB2(a) {static struct stat *h=0; if(sl2trace(&h,a)) {}}
#define TRACEPB1(a) if(sl1trace(a)) {}
/*
Execute a loop 1000 times, both with and without Sherlock macros.
Report the difference in clock ticks.
*/
main()
{
int i;
unsigned long sl_fast, sl_slow;
/* Make sure exactly one of FAR_MODEL or NEAR_MODEL is defined. */
#ifndef FAR_MODEL
#ifndef NEAR_MODEL
printf("Please #define NEAR_MODEL or FAR_MODEL");
exit(BAD_EXIT);
#endif
#endif
#ifdef FAR_MODEL
#ifdef NEAR_MODEL
printf("Please #define only one of NEAR_MODEL or FAR_MODEL");
exit(BAD_EXIT);
#endif
#endif
/* Sign on. */
#ifdef NEAR_MODEL
printf("m1: %s", VERSION);
#endif
#ifdef FAR_MODEL
printf("m2: %s", VERSION);
#endif
/* Print speed up factor. */
printf("sl_speed = %d\n", sl_speed);
sl_init("dummy version");
/* Part I: for preferred macros. */
/* Calculate 1000 times the Sherlock overhead. */
sl_count = 0;
for(i = 0; i < 1000; i++) {
dummy(i);
}
sl_fast = sl_count;
sl_count = 0;
for(i = 0; i < 1000; i++) {
TRACEPB2("count");
dummy(i);
sl_ret();
}
sl_slow = sl_count;
#if 0
printf("sl_slow: %ld, sl_fast: %ld ", sl_slow, sl_fast);
printf("t_check: %ld, t_find: %ld, t_new: %ld\n",
t_check, t_find, t_new);
#endif
#ifdef FAR_MODEL
printf("Set TIME_ADJUST (far code models, preferred macros) to %d\n",
(sl_slow - sl_fast));
#endif
#ifdef NEAR_MODEL
printf("Set TIME_ADJUST (near code models, preferred macros) to %d\n",
(sl_slow - sl_fast));
#endif
/* Part II: Alternate macros. */
t_check = 0;
t_find = 0;
t_new = 0;
/* Calculate 1000 times the Sherlock overhead. */
sl_count = 0;
for(i = 0; i < 1000; i++) {
dummy(i);
}
sl_fast = sl_count;
sl_count = 0;
for(i = 0; i < 1000; i++) {
TRACEPB1("count");
dummy(i);
sl_ret();
}
sl_slow = sl_count;
#if 0
printf("sl_slow: %ld, sl_fast: %ld ", sl_slow, sl_fast);
printf("t_check: %ld, t_find: %ld, t_new: %ld\n",
t_check, t_find, t_new);
#endif
#ifdef FAR_MODEL
printf("Set TIME_ADJUST (far code models, alternate macros) to %d\n",
(sl_slow - sl_fast));
printf("Far code models: medium, large, huge. Use prffar.obj\n");
#endif
#ifdef NEAR_MODEL
printf("Set TIME_ADJUST (near code models, alternate macros) to %d\n",
(sl_slow - sl_fast));
printf("Near code models: tiny, small, compact. Use prfnear.obj\n");
#endif
}
int global_var;
/*
A do-nothing routine that may prevent some unwanted loop optimizations.
The speed of this routine does not affect the value of TIME_ADJUST.
*/
dummy(i)
int i;
{
global_var++;
}
/*
The following routines are taken from sherlock.c.
*/
void
sl_check(register char *s)
{
register char c;
register int i;
char sbuf [40];
char *old_s;
t_check++;
old_s = s;
/* Check for null string. */
if (!*s) {
/* Write the error message. */
sprintf(sbuf, "%p", s);
sl_s3out("sl_check: ", check_s, ": null string @ ");
sl_s2out(sbuf, "\n");
exit(BAD_EXIT);
}
/* 6/27/89: allow up to 31 character names. */
for (i = 0; i < 31; i++) {
c = *s++;
if (c == '\0') {
return ;
}
/* Allow only identifiers and wild cards. */
if (!isalnum(c) && c != '_' && c != '*' && c != '?') {
sprintf(sbuf, "%p", s);
sl_s3out("sl_check: ", check_s, ": bad character: ");
sl_cout(c);
sl_s3out(" in ", old_s, " @ ");
sl_s2out(sbuf, "\n");
exit(BAD_EXIT);
}
}
sprintf(sbuf, "%p", s);
sl_s3out("sl_check: ", check_s, ": run on argument: ");
sl_s3out(old_s, " @ ", sbuf);
sl_sout("\n");
exit(BAD_EXIT);
}
struct stat *
sl_find(char *macro_type, char *s)
{
register int i;
register struct stat *p, *q, *node;
register int hash;
t_find++;
/* Update global error string. */
check_s = macro_type;
/* Search the proper index table. */
hash = sl_hash(s);
p = hash_tab [hash];
if (p != NULL) {
i = strcmp_(s, p -> name);
if (i == 0) {
return p;
}
}
if (p == NULL || i < 0) {
sl_check(s);
node = sl_new(s);
hash_tab [hash] = node;
node -> next = p;
node -> n_disable = disable;
return node;
}
/* Search the list for the node. */
for (q = p, p = p -> next; p; q = p, p = p -> next) {
i = strcmp_(s, p -> name);
if (i == 0) {
return p;
}
else if (i < 0) {
break;
}
}
/* Not found. */
sl_check(s);
node = sl_new(s);
q -> next = node;
node -> next = p;
node -> n_disable = disable;
return node;
}
int
sl_hash(register char *s)
{
register unsigned int hash;
for (hash = 0; *s; ) {
hash += hash + hash + (unsigned int) *s++;
hash %= MAX_HASH;
}
return (int) hash;
}
struct stat *
sl_new(char *s)
{
register struct stat * node, *p;
t_new++;
/* Not found. Point node at a new node. */
if (cur_stat >= MAX_STAT) {
sl_sout("sl_new: trace table overflow\n");
exit(BAD_EXIT);
}
/* Create the new node. */
node = sl__nodes + cur_stat;
cur_stat++;
node -> name = s;
node -> n_stat = 0;
node -> n_disable = disable;
/*
Search the wildcard list for a node which matches s.
If found. Set trace field.
*/
for (p = wildcard; p; p = p -> next) {
if (is_match(p -> name, s)) {
node -> trace = p -> trace;
return node;
}
}
/* No match. */
node -> trace = 0;
return node;
}
int
has_wild(register char *s)
{
register char c;
for (;;) {
c = *s++;
if (c == '\0') {
return FALSE;
}
else if (c == '*' || c == '?') {
return TRUE;
}
}
}
int
is_match(register char *s1, register char *s2)
{
register char c;
for (;;) {
c = *s1++;
if (c == '\0') {
return !*s2;
}
else if (c == '*') {
/* Matches zero or more characters. */
return TRUE;
}
else if (c == '?') {
/* Matches exactly one character. */
if (*s2 == '\0') {
return FALSE;
}
else {
s2++;
}
}
else if (c != *s2++) {
return FALSE;
}
}
}
int
prefix(char *p, char *s)
{
while (*p) {
if (*p++ != *s++) {
return FALSE;
}
}
return TRUE;
}
int
strcmp_(register char *s1, register char *s2)
{
while (*s1 == *s2) {
if (*s1 == '\0') {
return 0;
}
else {
s1++;
s2++;
}
}
return ((int) *s1) - ((int) *s2);
}
int
streq_(register char *s1, register char *s2)
{
while(*s1) {
if (*s1++ != *s2++) {
return FALSE;
}
}
return !*s2;
}
void
sl_init(char * version)
{
int i;
/* Initialize the hash table. */
for (i = 0; i < MAX_HASH; i++) {
hash_tab [i] = NULL;
}
a_list.alpha = NULL;
a_list.next = NULL;
a_list.name = NULL;
sl_von();
}
void
sl_cout(char c)
{
putchar(c);
}
void
sl_sout(char *s)
{
while (*s) {
sl_cout(*s++);
}
}
void
sl_s2out(char *s1, char *s2)
{
sl_sout(s1);
sl_sout(s2);
}
void
sl_s3out(char *s1, char *s2, char *s3)
{
sl_sout(s1);
sl_sout(s2);
sl_sout(s3);
}
/*
The following routines have been modified from
corresponding routines in sherlock.c.
The purpose of the modifications is to measure only the
code that contributes to "unmeasured overhead."
In the case of the preferred macros, some arbitrary guesses
have been made about the frequency of multiple calls to the
same tracepoint name, which will affect the number of times
sl_find() should be counted. If my assumptions seem unreasonable,
try your own.
*/
int sl_mod = 0;
/* The unmeasured portion of sl2trace. */
int
sl2trace(struct stat **pp, char *s)
{
/* Force a call to sl_find every 5th call. */
if (sl_mod++ == 5) {
*pp = sl_find("TRACEP2", s);
sl_mod = 0;
sl_new(s);
}
sl_visit(*pp, 1, 1);
return TRUE;
}
/* The unmeasured portion of sl1trace. */
int
sl1trace(char *s)
{
struct stat * pp;
pp = sl_find("TRACEP1", s);
/* Force a call to sl_new every 5th call. */
if (sl_mod++ == 5) {
sl_mod = 0;
sl_new(s);
}
sl_visit(pp, 1, 1);
return TRUE;
}
/* The unmeasured portion of sl_visit */
int
sl_visit(struct stat *p, int stat_flag, int entry_flag)
{
}
/* The unmeasured portion of sl_ret */
int
sl_ret()
{
if (g_disable > 0) {
;
}
else if (g_disable > 0) {
;
}
else {
return TRUE;
}
}