home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 02 / fox.asc < prev    next >
Text File  |  1989-01-04  |  23KB  |  547 lines

  1. _Benchmarking C Statements_
  2. by David Fox
  3.  
  4. [LISTING ONE] 
  5.   1| /* sbench.c -- C statement benchmark generator. */
  6.   2| /* Released to the public domain by David L. Fox, 1988. */
  7.   3| 
  8.   4| /* This program will read a list of C statements and generate a test
  9.   5|    program to time the execution of each of the statements in the list.
  10.   6|    The list should have the form:
  11.   7| zero or more global declarations
  12.   8| %%
  13.   9| %zero or more local declarations or statements
  14.  10| one or more test statements
  15.  11|     The global and local declarations and statements are not timed.
  16.  12|     Every local statement must have a % in column 1. Every test statement
  17.  13|     should be on one logical line.  Physical lines ending with \ are
  18.  14|     continued, as in C, so long logical lines may be split.
  19.  15| 
  20.  16|     The program is run with a command of the form:
  21.  17| sbench [ -cx ] [ -f name ] [ -n xx ] [ -o ] [ -g ] [ files ... ]
  22.  18|     If no input files are given sbench reads the standard input.
  23.  19|         Available options are:
  24.  20|       -c x     Select compiler: x=a Aztec, x=d Datalight,
  25.  21|                       x=e Ecosoft, x=t Turbo, x=z Zortech
  26.  22|       -f name  Write generated program to file name.
  27.  23|       -n xx    Execute each statement xx times.
  28.  24|       -o       Optimize when compiling benchmark.
  29.  25|       -g       Generate test program only, do not try to compile.
  30.  26| */
  31.  27| #include    <stdio.h>
  32.  28| #include    <stdlib.h>
  33.  29| #include    <string.h>
  34.  30| #include    <ctype.h>
  35.  31| 
  36.  32| #define OUTFNAME   "statbm.c"   /* Default name of generated program. */
  37.  33| 
  38.  34| struct listel {             /* One element in a linked list of lines. */
  39.  35|     struct listel *next;    /* Link to next element. */
  40.  36|     char *line;             /* Pointer to the text of the line. */
  41.  37| };
  42.  38| struct llist {
  43.  39|     struct listel *head;    /* Head of the list. */
  44.  40|     struct listel *tail;    /* Tail of the list. */
  45.  41| };
  46.  42| 
  47.  43| /* The following enum type is used to identify the compilers used. */
  48.  44| enum cctag { aztec = 'a', datalight = 'd', ecosoft = 'e',
  49.  45|     turboc = 't', zortech = 'z'};
  50.  46| struct cmdline {    /* Contains parts of command lines for compilers. */
  51.  47|     enum cctag tag;     /* Identifies compiler. */
  52.  48|     char *cmd;          /* Beginning of command line. */
  53.  49|     char *optimize;     /* Command line option to invoke optimizer. */
  54.  50|     char *lib;          /* Libraries added to end of command line. */
  55.  51|         /* The libraries named should contain the high resolution */
  56.  52|         /* clock() function if it is used.  The exact contents of the */
  57.  53|         /* lib strings will depend on how your hard disk is organized. */
  58.  54| } compilers[] = {     /* Compilers[0] is the default. */
  59.  55|     { aztec, "c -lx -lm -dMu_CLOCK", "+f", "" },
  60.  56|     { datalight, "dlc -dMu_CLOCK", "-o", "\\lib\\dlc\\xs.lib" },
  61.  57|     { ecosoft, "ecc -dMu_CLOCK -lecox", "", "" },
  62.  58|     { turboc, "tcc -dMu_CLOCK", "-G", "\\lib\\tc\\xs.lib" },
  63.  59|     { zortech, "ztc -dMu_CLOCK", "-o", "\\lib\\ztc\\xs.lib" }
  64.  60| };
  65.  61| 
  66.  62| struct cmdoptns {       /* Information extracted from command line. */
  67.  63|     unsigned int ntimes;    /* Repeat count for SUT. */
  68.  64|     char *outfname;         /* Name of output file. */
  69.  65|     int doopt;              /* Flag, non-zero optimizes test program. */
  70.  66|     struct cmdline *compiler;    /* Pointer to command line details. */
  71.  67| } options;
  72.  68| 
  73.  69| /* These strings form parts of the generated program. */
  74.  70| char *pgmincl = "#include\t<stdio.h>\n#include\t<time.h>\n\n";
  75.  71| char *pgmhdr = "#ifdef\tMu_CLOCK\n"   /* Using high-res clock()? */
  76.  72|     "#undef\tCLK_TCK\n#define\tCLK_TCK\t1000000L\n#endif\n"
  77.  73|     "#ifdef\t__STDC__\n"                  /* __STDC__ indicates an ANSI */
  78.  74|     "int main(int argc, char **argv) {\n" /* conforming implementation */
  79.  75|     "\tvoid sb_dummy(unsigned int);\n"    /* with prototypes. */
  80.  76|     "#else\n"           /* otherwise use K&R style function definitions. */
  81.  77|     "int main(argc, argv)\nint argc;\nchar **argv; {\n\tint sb_dummy();\n"
  82.  78|     "#endif\n\tclock_t sb_t0, sb_time, sb_empty;\n"
  83.  79|     "\tunsigned int sb_index, sb_nexpr, sb_niter;\n";
  84.  80| char *pgmend =
  85.  81|     "\treturn 0;\n}\n#ifdef\t__STDC__\nvoid sb_dummy(unsigned int i) {\n"
  86.  82|     "#else\nint sb_dummy(i)\nunsigned int i; {\n#endif\n\treturn;\n}\n";
  87.  83| char *pgminit = "clock();\n"  /* Start clock, avoid first call overhead. */
  88.  84|     "sb_nexpr = 0;\nsb_niter = %u;\n";
  89.  85| char *pgmstart = "sb_t0 = clock();\n";
  90.  86| char *pgmloop = "for (sb_index=0; sb_index < sb_niter; ++sb_index) {\n"
  91.  87|     "sb_dummy(sb_index);\n";   /* Keep optimizers from gutting loop. */
  92.  88| char *pgmnoloop = "{\n";       /* Put expression to be timed in a block. */
  93.  89| char *pgmempty = "}\nsb_empty = clock() - sb_t0;\n";  /* Time empty stmt */
  94.  90| char *pgmstop = "}\nsb_time = clock() - sb_t0;\n"     /* Print results. */
  95.  91|     "printf(\"Statement %u required %6.1f microseconds to execute, "
  96.  92|     "%u iteration%s timed.\\n\",\n++sb_nexpr,"
  97.  93|     "(((double)(sb_time-sb_empty))*(1000000./CLK_TCK))/sb_niter, sb_niter,"
  98.  94|     "sb_niter > 1 ? \"s\" : \"\");\n";
  99.  95| 
  100.  96| /* Function prototypes. */
  101.  97| void docmdline(int argc, char **argv, struct cmdoptns *optptr);
  102.  98| char *getline(FILE *);
  103.  99| int getopt(int argc, char *argv[], char *);
  104. 100| void lladd(struct llist *last, char *str);
  105. 101| void outerr(void);
  106. 102| void writelines(struct llist *list, FILE *outfile);
  107. 103| void usage(void);
  108. 104| 
  109. 105| /* External variables communicate with getopt(). */
  110. 106| extern int optind;      /* Index of next command line argument in argv. */
  111. 107| extern char *optarg;    /* Argument for a command line option (-o arg). */
  112. 108| int
  113. 109| main(int argc, char **argv) {
  114. 110|     char cmdbuf[256], *str;
  115. 111|     FILE *infile, *outfile;
  116. 112|     struct llist *llp,
  117. 113|      globall,               /* Global declaration lines. */
  118. 114|      locall,                /* Local declaration lines. */
  119. 115|      testl;                 /* Lines to be tested. */
  120. 116|     struct listel *lep;
  121. 117| 
  122. 118|     /* Set up default values */
  123. 119|     infile = stdin;
  124. 120|     options.outfname = OUTFNAME;
  125. 121|     options.ntimes = 1;
  126. 122|     options.doopt = 0;                  /* Don't optimize test code. */
  127. 123|     options.compiler = &compilers[0];
  128. 124|     docmdline(argc, argv, &options);    /* Process command line options. */
  129. 125| 
  130. 126|     globall.head  = globall.tail = locall.head  = locall.tail =
  131. 127|         testl.head = testl.tail = NULL;
  132. 128| 
  133. 129|     /* Once through the loop for each input file. */
  134. 130|     do {
  135. 131|         if (optind < argc) {
  136. 132|             /* Try to open a file from the command line. */
  137. 133|             if ((infile = fopen(argv[optind], "r")) == NULL) {
  138. 134|                 perror(argv[optind]);
  139. 135|                 fprintf(stderr, "Failed to open input file\n");
  140. 136|                 continue;    /* Try the next file. */
  141. 137|             }
  142. 138|         }
  143. 139|         else {
  144. 140|             /* There are are no files on the command line, */
  145. 141|             /* use the standard input. */
  146. 142|             infile = stdin;
  147. 143|             if (isatty(fileno(stdin)))
  148. 144|                 fprintf(stderr, "Enter list of statements:\n");
  149. 145|         }
  150. 146| 
  151. 147|         /* Now read the file and append its contents to 
  152. 148|            a linked list of lines. */
  153. 149|         llp = &globall;     /* First section contains global statements. */
  154. 150|         while ((str = getline(infile)) != NULL) {
  155. 151|             if (strncmp(str, "%%", 2) == 0)
  156. 152|                 llp = &testl;           /* Found end of global section. */
  157. 153|             else if (*str == '%')
  158. 154|                 lladd(&locall, str+1);  /* This is a local declaration. */
  159. 155|             else lladd(llp, str);
  160. 156|         }
  161. 157|         if (ferror(infile)) {   /* Getline returns NULL on error or EOF. */
  162. 158|             perror(argv[optind]);
  163. 159|             fprintf(stderr, "Read error\n");
  164. 160|             exit(1);
  165. 161|         }
  166. 162| 
  167. 163|         if (fclose(infile)) {
  168. 164|             perror(argv[optind]);
  169. 165|             fprintf(stderr, "Error closing input file!\n");
  170. 166|             exit(1);
  171. 167|         }
  172. 168|     } while (++optind < argc);
  173. 169|     
  174. 170|     /* Done with input, begin output phase. */
  175. 171|     if ((outfile = fopen(options.outfname, "w")) == NULL) {
  176. 172|         perror(options.outfname);
  177. 173|         fprintf(stderr, "Can't create output file\n");
  178. 174|         exit(1);
  179. 175|     }
  180. 176| 
  181. 177|     /* Select and write the pieces of the generated program. */
  182. 178|     if (fprintf(outfile, "%s", pgmincl) < 0) outerr();
  183. 179|     writelines(&globall, outfile);      /* Write global lines. */
  184. 180|     
  185. 181|     if (fprintf(outfile, "%s", pgmhdr) < 0) outerr();  /* Main program. */
  186. 182|     writelines(&locall, outfile);       /* Write local lines. */
  187. 183|     
  188. 184|     /* Write code to initialize variables. */
  189. 185|     if (fprintf(outfile, pgminit, options.ntimes) < 0) outerr();
  190. 186| 
  191. 187|     /* Write code to time execution of an empty expression. */
  192. 188|     if (fprintf(outfile, "%s", pgmstart) < 0) outerr();
  193. 189| 
  194. 190|     if (options.ntimes > 1) {        /* Need looping code? */
  195. 191|         if (fprintf(outfile, "%s", pgmloop) < 0) outerr();
  196. 192|     }
  197. 193|     else {
  198. 194|         if (fprintf(outfile, "%s", pgmnoloop) < 0) outerr();
  199. 195|     }
  200. 196|     if (fprintf(outfile, "%s", pgmempty) < 0) outerr();
  201. 197| 
  202. 198|     /* Write code to time execution of statements. */
  203. 199|     for (lep = testl.head; lep; lep = lep->next) {
  204. 200|         if (fprintf(outfile, "%s", pgmstart) < 0) outerr();
  205. 201|         if (options.ntimes > 1) {       /* Need looping code? */
  206. 202|             if (fprintf(outfile, "%s", pgmloop) < 0) outerr();
  207. 203|         }
  208. 204|         else {
  209. 205|             if (fprintf(outfile, "%s", pgmnoloop) < 0) outerr();
  210. 206|         }
  211. 207|         /* Here is where the expression is written into the program. */
  212. 208|         if (fprintf(outfile, "%s", lep->line) < 0) outerr();
  213. 209| 
  214. 210|         if (fprintf(outfile, "%s", pgmstop) < 0) outerr();   /* Output */
  215. 211|     }
  216. 212|     if (fprintf(outfile, "%s", pgmend) < 0) outerr();     /* Wrap up. */
  217. 213|     if (fclose(outfile)) outerr();
  218. 214| 
  219. 215|     if (options.compiler != NULL) {
  220. 216|         /* Compile and execute test program. */
  221. 217|         sprintf(cmdbuf,"%s %s %s %s", options.compiler->cmd,
  222. 218|          options.doopt ? options.compiler->optimize : "",
  223. 219|          options.outfname, options.compiler->lib);
  224. 220|         if (system(cmdbuf)) {     /* MS-DOS doesn't return error codes. */
  225. 221|             fprintf(stderr, "Compilation error\n");
  226. 222|             exit(1);
  227. 223|         }
  228. 224|         *strchr(options.outfname, '.') = '\0';    /* Chop off ".exe" */
  229. 225|         system(options.outfname);
  230. 226|     }
  231. 227|     return 0;
  232. 228| }
  233. 229| 
  234. 230| /* lladd -- Add a new line to the tail of a linked list. */
  235. 231| void
  236. 232| lladd(struct llist *list, char *str) {
  237. 233|     struct listel *lep;
  238. 234| 
  239. 235|     /* Create a new list structure. */
  240. 236|     if ((lep = (struct listel *)malloc(sizeof(struct listel))) == NULL) {
  241. 237|         fprintf(stderr, "Not enough memory\n");
  242. 238|         exit(1);
  243. 239|     }
  244. 240|     lep->line = str;        /* Add the line to it */
  245. 241|     lep->next = NULL;       /* and mark it as the tail. */
  246. 242|     if (list->tail != NULL)
  247. 243|         list->tail->next = lep;     /* Link it to the old tail. */
  248. 244|     list->tail = lep;               /* Make it the new tail. */
  249. 245|     if (list->head == NULL)
  250. 246|         list->head = lep;           /* First element is head. */
  251. 247|     return;
  252. 248| }
  253. 249| 
  254. 250| /* docmdline -- Extract options from command line. */
  255. 251| void
  256. 252| docmdline(int argc, char **argv, struct cmdoptns *optptr) {
  257. 253|     int c, i;
  258. 254|     enum cctag tag;
  259. 255| 
  260. 256|     while ((c = getopt(argc, argv, "c:f:n:og")) != EOF) {
  261. 257|         switch(c) {
  262. 258|         case 'c':       /* Select compiler. */
  263. 259|             tag = tolower(*optarg);
  264. 260|             for (i = 0; i < sizeof(compilers)/sizeof(compilers[0]); ++i) {
  265. 261|                 if (tag == compilers[i].tag) {    /* Is this the one? */
  266. 262|                     optptr->compiler = &compilers[i];
  267. 263|                     break;
  268. 264|                 }
  269. 265|             }
  270. 266|             if (i >= sizeof(compilers)/sizeof(compilers[0])) {
  271. 267|                 /* Didn't find compiler. */
  272. 268|                 fprintf(stderr, "Unknown compiler: %s\n", optarg);
  273. 269|                 usage();
  274. 270|             }
  275. 271|             break;
  276. 272|         case 'f':       /* Name of generated program from command line. */
  277. 273|             if (NULL == (optptr->outfname = malloc(strlen(optarg)+1))) {
  278. 274|                 fprintf(stderr, "Not enough memory\n");
  279. 275|                 exit(1);
  280. 276|             }
  281. 277|             strcpy(optptr->outfname, optarg);
  282. 278|             break;
  283. 279|         case 'g':       /* Don't compile. */
  284. 280|             optptr->compiler = NULL;
  285. 281|             break;
  286. 282|         case 'n':       /* Execute statement n times. */
  287. 283|             optptr->ntimes = strtol(optarg, NULL, 0);
  288. 284|             break;
  289. 285|         case 'o':       /* Use optimizer when compiling benchmark. */
  290. 286|             optptr->doopt = 1;
  291. 287|             break;
  292. 288|         default:
  293. 289|             usage();
  294. 290|         }
  295. 291|     }
  296. 292| }
  297. 293| 
  298. 294| void
  299. 295| usage(void) {      /* Print help message and exit. */
  300. 296|     fprintf(stderr, "Usage: sbench [ options ] [ files ... ]\n"
  301. 297|      " Available options are:\n"
  302. 298|      "  -c x     Select compiler: x=a Aztec, x=d Datalight,\n"
  303. 299|      "                 x=e Ecosoft, x=t Turbo, x=z Zortech\n"
  304. 300|      "  -f name  Write generated program to file name.\n"
  305. 301|      "  -n xx    Execute each statement xx times.\n"
  306. 302|      "  -o       Optimize when compiling benchmark.\n"
  307. 303|      "  -g       Generate test program only, do not try to compile.\n");
  308. 304|     exit(1);
  309. 305| }
  310. 306| 
  311. 307| /* writelines -- Output all lines in a list. */
  312. 308| void
  313. 309| writelines(struct llist *list, FILE *outfile) {
  314. 310|     struct listel *lep;
  315. 311| 
  316. 312|     for (lep = list->head; lep != NULL; lep = lep->next) {
  317. 313|         if (fprintf(outfile, "%s\n", lep->line) < 0) outerr();
  318. 314|     }
  319. 315|     return;
  320. 316| }
  321. 317| 
  322. 318| /* outerr -- Display a message and abort following an output error. */
  323. 319| void
  324. 320| outerr(void) {
  325. 321|     perror(options.outfname);
  326. 322|     fprintf(stderr, "Error writing output file");
  327. 323|     exit(1);
  328. 324| }
  329.  
  330.  
  331.        
  332.  
  333. [LISTING TWO]
  334.  
  335.   1| /* getline.c -- Read a line from a stream. */
  336.   2| #include <stdio.h>
  337.   3| #include <stdlib.h>
  338.   4| #include <string.h>
  339.   5| 
  340.   6| #define MEMINCR 256      /* Size of memory block used for (m|re)alloc. */
  341.   7| /* getline -- Read one line from file infile into a malloc'ed string.
  342.   8|        Lines ending with \ are combined with the following line.
  343.   9|        Return NULL on error or EOF, otherwise a pointer to the string. */
  344.  10| char *
  345.  11| getline(FILE *infile)
  346.  12| {    char *p, *q;
  347.  13|     int c;
  348.  14|     unsigned avail;
  349.  15| 
  350.  16|     p = q = malloc((unsigned)MEMINCR);
  351.  17|     avail = MEMINCR - 1;
  352.  18|     for (;;) {
  353.  19|         if ((c = getc(infile)) == EOF) {
  354.  20|             *p = '\0';
  355.  21|             if (p > q) return q;
  356.  22|             else return NULL;
  357.  23|         }
  358.  24|         if ((*p++ = c) == '\n') {
  359.  25|             if (p <= q+1 || p[-2] != '\\') {
  360.  26|                 *p = '\0';
  361.  27|                 return q;
  362.  28|             }    /* else Continued line. */
  363.  29|         }
  364.  30|         if (--avail == 0) {
  365.  31|             /* Need more memory. */
  366.  32|             *p = '\0';
  367.  33|             if ((q = realloc(q, (size_t)(p-q + MEMINCR + 1))) == NULL)
  368.  34|                 return NULL;
  369.  35|             avail = MEMINCR;
  370.  36|             p = strchr(q, '\0');    /* Find end of string, in case it moved. */
  371.  37|         }
  372.  38|     }
  373.  39| }   
  374.  
  375.  
  376.  
  377. [LISTING THREE]
  378.  
  379.   1| /* getopt.c -- UNIX-like command line option parser. */
  380.   2| #include <stdio.h>
  381.   3| #include <string.h>
  382.   4| int optind;          /* Index of next argument in argv[]. */
  383.   5| char *optarg;        /* Pointer to option argument. */
  384.   6| 
  385.   7| /* getopt -- Returns option letters one at a time,
  386.   8|       EOF when no more options remain, and ? for unknown option.
  387.   9|       Optstr contains legal option letters.  A colon following a
  388.  10|       letter indicates that option requires an argument. */
  389.  11| int
  390.  12| getopt(int argc, char *argv[], char *optstr)
  391.  13| {   static char *cp;
  392.  14|     char *p;
  393.  15| 
  394.  16|     if(optind == 0)
  395.  17|         cp = argv[++optind] + 1;    /* First call */
  396.  18|     if(*argv[optind] != '-' || optind >= argc)
  397.  19|         return EOF;        /* No more options. */
  398.  20|     if(*cp == '-')
  399.  21|     {   ++optind;
  400.  22|         return EOF;        /* -- indicates end of options */
  401.  23|     }
  402.  24|     if((p = strchr(optstr, *cp++)) == NULL)
  403.  25|     {   fputs("unknown option: ", stderr);
  404.  26|         putc(*(cp-1), stderr);
  405.  27|         putc('\n', stderr);
  406.  28|         if(*cp == '\0')
  407.  29|             cp = argv[++optind] + 1;
  408.  30|         return '?';
  409.  31|     }
  410.  32|     if(*(p+1) == ':')
  411.  33|     {   if(*cp == '\0')        /* Get argument. */
  412.  34|             optarg = argv[++optind];
  413.  35|         else
  414.  36|             optarg = cp;
  415.  37|         cp = argv[++optind] + 1;
  416.  38|     }
  417.  39|     else if(*cp == '\0')
  418.  40|         cp = argv[++optind] + 1;    /* Set up for next argv. */
  419.  41|     return *p;
  420.  42| }
  421.  
  422.  
  423.  
  424. [LISTING FOUR]
  425.  
  426.   1| /* clock.c -- Microsecond resolution clock routine.      */
  427.   2| /*  Implements in C the timer chip tweaking described by */
  428.   3| /*  Byron Sheppard, _Byte_, Jan 1987, p 157-164.         */
  429.   4| /*  Replaces standard clock() from the library.          */
  430.   5| /*  The definition of CLK_TCK in time.h may have to      */
  431.   6| /*  be changed to 1000000L.                              */
  432.   7| /*  Does not correctly handle intervals spanning         */
  433.   8| /*  midnight or intervals greater than about 6 hrs.      */
  434.   9| #include    <time.h>
  435.  10| 
  436.  11| /* Interrupt handling and i/o ports are compiler dependent.  */
  437.  12| /* The following set of preprocessor directives selects the  */
  438.  13| /* correct include files and macros for various compilers.   */
  439.  14| #ifdef      __ZTC__
  440.  15| #include    <dos.h>
  441.  16| #include    <int.h>
  442.  17| #define     inportb     inp
  443.  18| #define     outportb    outp
  444.  19| #else
  445.  20| #ifdef      __TURBOC__
  446.  21| #include    <dos.h>
  447.  22| #define     int_off     disable
  448.  23| #define     int_on      enable
  449.  24| #else
  450.  25| #error Unknown compiler
  451.  26| #endif
  452.  27| #endif
  453.  28| 
  454.  29| /* Constants */
  455.  30| #define CONTVAL   0x34   /* == 00110100 Control byte for 8253 timer. */
  456.  31|                     /* Sets timer 0 to 2-byte read/write, mode 2, binary. */
  457.  32| #define T0DATA    0x40    /* Timer 0 data port address. */
  458.  33| #define TMODE     0x43    /* Timer mode port address. */
  459.  34| #define BIOS_DS   0x40    /* BIOS data segment. */
  460.  35| #define B_TIKP    0x6c    /* Address of BIOS (18.2/s) tick count. */
  461.  36| #define SCALE    10000    /* Scale factor for timer ticks. */
  462.  37| /* The following values assume 18.2 BIOS ticks per second resulting from
  463.  38|  the 8253 being clocked at 1.19 MHz. */
  464.  39| #define us_BTIK  54925    /* Micro sec per BIOS clock tick. */
  465.  40| #define f_BTIK    4595    /* Fractional part of micro sec per BIOS tick. */
  466.  41| #define us_TTIK   8381    /* Micro sec per timer tick * SCALE. (4/4.77 MHz) */
  467.  42| 
  468.  43| clock_t
  469.  44| clock(void) {
  470.  45|     unsigned char msb, lsb;
  471.  46|     unsigned int tim_ticks;
  472.  47|     static int init = 0;
  473.  48|     unsigned long count, us_tmp;
  474.  49|     static unsigned long init_count;
  475.  50| 
  476.  51|     if (0 == init) {
  477.  52|         init = 1;     /* This is the first call, have to set up timer. */
  478.  53|         int_off();
  479.  54|         outportb(TMODE, CONTVAL);   /* Write new control byte to timer. */
  480.  55|         outportb(T0DATA, 0);        /* Initial count = 0 = 65636. */
  481.  56|         outportb(T0DATA, 0);
  482.  57|         init_count = *(unsigned long int far *)MK_FP(BIOS_DS, B_TIKP);
  483.  58|         int_on();
  484.  59|         return 0;                   /* First call returns zero. */
  485.  60|     }
  486.  61|     int_off();    /* Don't want an interrupt while getting time. */
  487.  62|     outportb(TMODE, 0);               /* Latch count. */
  488.  63|     lsb = inportb(T0DATA);            /* Read count. */
  489.  64|     msb = inportb(T0DATA);
  490.  65|     /* Get BIOS tick count (read BIOS ram directly for speed and
  491.  66|         to avoid turning on interrupts). */
  492.  67|     count =  *(unsigned long far *)MK_FP(BIOS_DS, B_TIKP) - init_count;
  493.  68|     int_on();                   /* Interrupts back on. */
  494.  69|     tim_ticks = (unsigned)-1 - ((msb << 8) | lsb);
  495.  70|     us_tmp = count*us_BTIK;
  496.  71|     return us_tmp + ((long)tim_ticks*us_TTIK + us_tmp%SCALE)/SCALE;
  497.  72| }
  498.  
  499.  
  500.  
  501. [LISTING FIVE]
  502.  
  503.   1| /* Test data for statement benchmark generator. */
  504.   2| %%
  505.   3| %float f, g = 10., h = 20.;
  506.   4| %double c, d = 10., e = 20.;
  507.   5| %int i = 10, j, *p, *q;
  508.   6| %int array[50], another[50];
  509.   7| f = g+h;                /* Float addition. */
  510.   8| c = d+e;                /* Double addition */
  511.   9| /* Initialize an array using subscripting. */\
  512.  10| for (i=0; i < 50; ++i)\
  513.  11|         array[i] = 0;
  514.  12| /* Initialize an array using pointer. */\
  515.  13| for (p = array; p < array + 50; ++p)\
  516.  14|         *p = 0;
  517.  15| /* Copy using array subscripts. */\
  518.  16| for (i=0; i < 50; ++i)\
  519.  17|         array[i] = another[i];
  520.  18| /* Copy using pointers. */\
  521.  19| for (p = array, q=another; p < array + 50; ++p, ++q)\
  522.  20|         *p++ = *q++;
  523.  21|                              (a) 
  524.  22|                           Test input 
  525.  23|    
  526.  24| Statement 1 required 1215.0 microseconds to execute, 1 iteration timed.
  527.  25| Statement 2 required  560.0 microseconds to execute, 1 iteration timed.
  528.  26| Statement 3 required 1671.0 microseconds to execute, 1 iteration timed.
  529.  27| Statement 4 required 1606.0 microseconds to execute, 1 iteration timed.
  530.  28| Statement 5 required 1820.0 microseconds to execute, 1 iteration timed.
  531.  29| Statement 6 required 1794.0 microseconds to execute, 1 iteration timed.
  532.  30|                              (b) 
  533.  31|                            Results 
  534.  32|    
  535.  33| Statement 1 required    2.0 microseconds to execute, 1 iteration timed.
  536.  34| Statement 2 required    1.0 microseconds to execute, 1 iteration timed.
  537.  35| Statement 3 required  813.0 microseconds to execute, 1 iteration timed.
  538.  36| Statement 4 required  813.0 microseconds to execute, 1 iteration timed.
  539.  37| Statement 5 required 1112.0 microseconds to execute, 1 iteration timed.
  540.  38| Statement 6 required  777.0 microseconds to execute, 1 iteration timed.
  541.  39|                              (c) 
  542.  40|                    Results with optimizer on 
  543.  
  544.  
  545.  
  546.  
  547.