home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / at / atperf.arc / ATPERF.C next >
Encoding:
C/C++ Source or Header  |  1988-04-07  |  29.9 KB  |  1,375 lines

  1. /*
  2.  * ATPERF -- PC Tech Journal AT Hardware Performance Test
  3.  *
  4.  * Version 2.03
  5.  * Originally written 05/17/86
  6.  * Last modified 03/24/87
  7.  * Changes:
  8.  *    1. First release (1.00).
  9.  *    2. Correct to work with zero-wait state memory (1.01).
  10.  *    3. Detects an unsupported processor (1.01).
  11.  *    4. Change to support 8088, 8086, and 80386 (2.00).
  12.  *    5. Add support for 80188 and 80186 (2.01)
  13.  *    6. Add support for 80387 (2.01)
  14.  *    7. Added tests to measure low wait state 386 reads (2.02)
  15.  *    8. Added support for pipelined writes (2.02)
  16.  *    9. Added cache detection (2.03)
  17.  *
  18.  * Copyright (c) 1986, 1987, 1988, Ziff Communications Company
  19.  * Program by: Ted Forgeron, Paul Pierce
  20.  *
  21.  * Measures clock rates and memory speeds
  22.  * of PC and AT compatible computers.
  23.  */
  24.  
  25. /*
  26.  * Measurements are accumulated in the acctime array.  Each
  27.  * element is identified by one of these constants.
  28.  *  IRB Instruction fetch, byte
  29.  *  IRW Instruction fetch, word
  30.  *  IRD Instruction fetch, dword
  31.  *  IRX Instruction fetch, slow byte
  32.  *  MRB RAM read byte
  33.  *  MRW RAM read word
  34.  *  MRD RAM read dword
  35.  *  MWB RAM write byte
  36.  *  MWW RAM write word
  37.  *  MWD RAM write dword
  38.  *  RRB ROM read byte
  39.  *  RRW ROM read word
  40.  *  RRD ROM read dword
  41.  *  ERB EMM read byte
  42.  *  ERW EMM read word
  43.  *  ERD EMM read dword
  44.  *  EWB EMM write byte
  45.  *  EWW EMM write word
  46.  *  EWD EMM write dword
  47.  *  VWB Video write byte
  48.  *  VWW Video write word
  49.  *  VWD Video write dword
  50.  *  CRB Cache read byte
  51.  *  CRW Cache read word
  52.  *  CRD Cache read dword
  53.  */
  54.  
  55. #define IRB    0
  56. #define IRW    1
  57. #define IRX    2
  58. #define MRB    3
  59. #define MWB    4
  60. #define RRB    5
  61. #define ERB    6
  62. #define EWB    7
  63. #define VWB    8
  64. #define MRW    9
  65. #define MWW    10
  66. #define RRW    11
  67. #define ERW    12
  68. #define EWW    13
  69. #define VWW    14
  70. #define IRD    15
  71. #define MRD    16
  72. #define MWD    17
  73. #define RRD    18
  74. #define ERD    19
  75. #define EWD    20
  76. #define VWD    21
  77. #define CRB    22
  78. #define CRW    23
  79. #define CRD    24
  80.  
  81. #define VARS88     3
  82. #define VARS186  3
  83. #define VARS286 15
  84. #define VARS386 25
  85.  
  86. /* Measurement procedures */
  87. extern unsigned multime();
  88. extern unsigned bclctime();
  89. extern unsigned wmovtime();
  90. extern unsigned dmovtime();
  91. extern unsigned dlodtime();
  92. extern unsigned dramtime();
  93. extern unsigned dimmtime();
  94. extern unsigned bdaatime();
  95. extern unsigned bmvstime();
  96. extern unsigned wmvstime();
  97. extern unsigned dmvstime();
  98. extern unsigned bromtime();
  99. extern unsigned wromtime();
  100. extern unsigned dromtime();
  101. extern unsigned wpshtime();
  102. extern unsigned dpshtime();
  103. extern unsigned bemmtime();
  104. extern unsigned wemptime();
  105. extern unsigned demptime();
  106. extern unsigned wemmtime();
  107. extern unsigned demmtime();
  108. extern unsigned bvidtime();
  109. extern unsigned wvidtime();
  110. extern unsigned dvidtime();
  111. extern unsigned fptime();
  112.  
  113. /* Timer rate in MHz */
  114. #define TIMER2_RATE 1.193180
  115.  
  116. /* Number of processor clocks in a multiply instruction */
  117. #define MULCLKS88 118
  118. /* #define MULCLKS186 36.5 */
  119. #define MULCLKS186 36
  120. #define MULCLKS286 21
  121. #define MULCLKS386 25
  122.  
  123. /* Overhead in the multiply test */
  124. #define MULOVH88 (11 + 22*count/100 )
  125. #define MULOVH186 (8 + 21*count/100 )
  126. #define MULOVH286 (15 + 14*count/100 )
  127. #define MULOVH386 (15 +  14*count/100 )
  128.  
  129. /* Overhead in the mov instruction test */
  130. #define MOVOVH88 ( clktime * (31 + 22*count/100) )
  131. #define MOVOVH186 ( clktime * (30 + 20*count/100) )
  132. #define MOVOVH286 ( clktime * (15 + 14*count/100) )
  133. #define MOVOVH386 ( clktime * (15 + 14*count/100) )
  134.  
  135. /* Overhead in pusha instruction test */
  136. #define WPOVH ( clktime * (15 + 9*count/200) )
  137. #define DPOVH ( clktime * (15 + 9*count/200) )
  138.  
  139. /* Number of numeric processor clocks in a FP divide */
  140. #define FPCLKS88 197
  141. #define FPCLKS186 197
  142. #define FPCLKS286 203
  143. #define FPCLKS386 200
  144. #define FPCLKS387  98
  145.  
  146. /* Processor overhead in the FP divide test */
  147. #define FPOVH88 ( clktime * 2 * FPCOUNT )
  148. #define FPOVH186 ( clktime * 2 * FPCOUNT )
  149. #define FPOVH286 ( clktime * 9 * FPCOUNT )
  150. #define FPOVH386 ( clktime * 7.5 * FPCOUNT )
  151.  
  152. /* Count for most tests */
  153. #define COUNT 1000
  154.  
  155. /* Count for the f. p. divide test */
  156. #define FPCOUNT 100
  157.  
  158. /* Number of trials for each test */
  159. #define TRIALS 100
  160.  
  161. /* Variables which hold constants selected by cpu type */
  162. int access_clks;
  163.  
  164. int cpu;    /* CPU type: 0=86/88,1=80186,2=80286,3=80386 */
  165. double clkrate; /* Processor clock rate, MHz */
  166. double clktime; /* Processor clock period, usec */
  167. double fprate;    /* FP processor clock rate, MHz */
  168. double fpacc;    /* FP processor clock period accumulator */
  169. int fastmath;    /* Set for 80387 */
  170. int emmok;    /* Set if extended memory is present */
  171. int ndpok;    /* Set if math coprocessor is present */
  172. int six;    /* Set if cpu is 8086 or 80186 */
  173. int mw_pipe;    /* Set if there is a write pipeline register */
  174. int ew_pipe;    /* Set for EMM pipeline register */
  175. int cache;    /* Set if there is a cache */
  176.  
  177. double raw;    /* Variable for raw data */
  178. double acctime[VARS386];   /* Accumulators for speeds */
  179. int count;        /* Number of ops per trial */
  180. int trials;        /* Number of repetitions */
  181.  
  182.  
  183. /*
  184.  * Main program.
  185.  */
  186.  
  187. main(argc, argv)
  188.     int    argc;
  189.     char    **argv;
  190. {
  191.  
  192.     measure();
  193.     display();
  194. }
  195.  
  196. measure()
  197. {
  198.     register int i;
  199.  
  200.     count = COUNT;
  201.     trials = TRIALS;
  202.  
  203.     /*
  204.      * Determine whether there a math coprocessor
  205.      * in the system.
  206.      */
  207.  
  208.     ndpok = ndp_present();
  209.  
  210.     /*
  211.      * Determine whether there is extended memory in the
  212.      * system and allocate a piece of it for testing.
  213.      */
  214.  
  215.     emmok = (setup_emm() == 0);
  216.  
  217.     /*
  218.      * Detect the type of video card and save the
  219.      * information for the video measurements.
  220.      */
  221.  
  222.     setup_video();
  223.  
  224.     /*
  225.      * Find out the CPU type and set
  226.      * parameters accordingly.
  227.      */
  228.  
  229.     cpu = cpu_type();
  230.     six = 0;
  231.     cache = 0;
  232.     mw_pipe = 0;
  233.     ew_pipe = 0;
  234.  
  235.     switch (cpu) {
  236.  
  237.     case 0:
  238.         access_clks = 4;
  239.         measure88();
  240.         break;
  241.  
  242.     case 1:
  243.         access_clks = 4;
  244.         measure186();
  245.         break;
  246.  
  247.     case 2:
  248.         access_clks = 2;
  249.         measure286();
  250.         break;
  251.  
  252.     case 3:
  253.         access_clks = 2;
  254.         measure386();
  255.         adjust386();
  256.         break;
  257.  
  258.     default:
  259.         printf("\nThis version of ATPERF is for ");
  260.         printf("8088/86/188/186/286/386");
  261.         printf("-based machines only.\n");
  262.         exit(1);
  263.     }
  264.  
  265.     /*
  266.      * Release EMM memory page.
  267.      */
  268.  
  269.     if (emmok)
  270.         finish_emm();
  271. }
  272.  
  273. display()
  274. {
  275.     register int i;
  276.  
  277.  
  278.     /*
  279.      * Display the basic measurement results and
  280.      * performance index relative to a 8 MHz AT.
  281.      */
  282.  
  283.     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
  284.     printf("ATPERF -- PC Tech Journal AT Hardware ");
  285.     printf("Performance Test\n");
  286.     printf("Version 2.03, Copyright (c) 1986, 1987, 1988, ");
  287.     printf("Ziff Communications Co.\n");
  288.     printf("Written by Ted Forgeron and Paul Pierce\n");
  289.     printf("IBM PC/AT model 339 (8 MHz) = 1.00 for relative ");
  290.     printf("measurements.\n");
  291.     if (cpu < 2)
  292.         printf("\n");
  293.     printf("                            ");
  294.     printf("    Byte         Word         ");
  295.     if (cpu > 2)
  296.         printf("Dword    ");
  297.     printf("Relative\n");
  298.  
  299.     printf("Average instruction fetch:");
  300.     printf("%#10.2g uS", acctime[IRB]);
  301.     printf("%#10.2g uS", acctime[IRW]);
  302.     if (cpu > 2)
  303.         printf("%#10.2g uS", acctime[IRD]);
  304.     printf("%#10.2g\n", 0.403/acctime[IRW]);
  305.  
  306.     if (cpu < 2) {
  307.         printf("\n");
  308.     } else {
  309.         if (cache) {
  310.             printf("Average Cache hit time:   ");
  311.             printf("%#10.2g uS", acctime[MRB]);
  312.             printf("%#10.2g uS", acctime[MRW]);
  313.             if (cpu > 2)
  314.                 printf("%#10.2g uS", acctime[MRD]);
  315.             printf("%#10.2g\n", 0.401/acctime[MRW]);
  316.  
  317.             printf("Average Cache miss time:  ");
  318.             printf("%#10.2g uS", acctime[CRB]);
  319.             printf("%#10.2g uS", acctime[CRW]);
  320.             if (cpu > 2)
  321.                 printf("%#10.2g uS", acctime[CRD]);
  322.             printf("%#10.2g\n", 0.401/acctime[CRW]);
  323.         } else {
  324.             printf("Average RAM read time:    ");
  325.             printf("%#10.2g uS", acctime[MRB]);
  326.             printf("%#10.2g uS", acctime[MRW]);
  327.             if (cpu > 2)
  328.                 printf("%#10.2g uS", acctime[MRD]);
  329.             printf("%#10.2g\n", 0.401/acctime[MRW]);
  330.         }
  331.  
  332.         printf("Average RAM write time:   ");
  333.         printf("%#10.2g uS", acctime[MWB]);
  334.         printf("%#10.2g uS", acctime[MWW]);
  335.         if (cpu > 2)
  336.             printf("%#10.2g uS", acctime[MWD]);
  337.         printf("%#10.2g\n", 0.401/acctime[MWW]);
  338.  
  339.         if (emmok) {
  340.             printf("Average EMM read time:    ");
  341.             printf("%#10.2g uS", acctime[ERB]);
  342.             printf("%#10.2g uS", acctime[ERW]);
  343.             if (cpu > 2)
  344.                 printf("%#10.2g uS", acctime[ERD]);
  345.             printf("%#10.2g\n", 0.402/acctime[ERW]);
  346.  
  347.             printf("Average EMM write time:   ");
  348.             printf("%#10.2g uS", acctime[EWB]);
  349.             printf("%#10.2g uS", acctime[EWW]);
  350.             if (cpu > 2)
  351.                 printf("%#10.2g uS", acctime[EWD]);
  352.             printf("%#10.2g\n", 0.402/acctime[EWW]);
  353.         }
  354.         printf("Average ROM read time:    ");
  355.         printf("%#10.2g uS", acctime[RRB]);
  356.         printf("%#10.2g uS", acctime[RRW]);
  357.         if (cpu > 2)
  358.             printf("%#10.2g uS", acctime[RRD]);
  359.         printf("%#10.2g\n", 0.401/acctime[RRW]);
  360.  
  361.         printf("Average Video write time: ");
  362.         printf("%#10.2g uS", acctime[VWB]);
  363.         printf("%#10.2g uS", acctime[VWW]);
  364.         if (cpu > 2)
  365.             printf("%#10.2g uS", acctime[VWD]);
  366.         printf("%#10.2g\n", 2.415/acctime[VWW]);
  367.     }
  368.  
  369.     switch (cpu) {
  370.  
  371.     case 0:
  372.         if (six)
  373.             printf(" 8086");
  374.         else
  375.             printf(" 8088");
  376.         break;
  377.  
  378.     case 1:
  379.         if (six)
  380.             printf("80186");
  381.         else
  382.             printf("80188");
  383.         break;
  384.  
  385.     case 2:
  386.         printf("80286");
  387.         break;
  388.  
  389.     case 3:
  390.         printf("80386");
  391.         break;
  392.     }
  393.     printf(" CPU clock rate:         ");
  394.     printf("%#4.1g MHz", clkrate);
  395.     printf("  Relative: %#4.2g\n", clkrate/8.0);
  396.  
  397.     if (ndpok) {
  398.         switch(cpu) {
  399.  
  400.         case 0:
  401.         case 1:
  402.             printf(" 8087");
  403.             break;
  404.  
  405.         case 2:
  406.             printf("80287");
  407.             break;
  408.  
  409.         case 3:
  410.             if (fastmath)
  411.                 printf("80387");
  412.             else
  413.                 printf("80287");
  414.             break;
  415.         }
  416.         printf(" Coprocessor clock rate: ");
  417.         printf("%#4.1g MHz", fprate);
  418.         printf("  Relative: %#4.2g\n", fprate/5.33);
  419.     }
  420.  
  421.     /*
  422.      * Calculate refresh overhead from instruction
  423.      * fetch time by assuming that each fetch takes
  424.      * an exact multiple of the clock period.  The
  425.      * difference between average time and the time
  426.      * for an individual fetch is due to memory
  427.      * refresh cycles.
  428.      */
  429.  
  430.     if (cpu == 3)
  431.         raw = acctime[MRD] / clktime;
  432.     else
  433.         raw = acctime[IRW] / clktime;
  434.  
  435.     printf("Refresh overhead:            %#2.1g%%\n",
  436.         ( (raw - (int)raw) / (int)raw ) * 100);
  437.  
  438.     /*
  439.      * Print information about the memory based
  440.      * on the speed measurements.
  441.      */
  442.  
  443.     printf("\nMemory   ");
  444.     printf("       Access width          Wait states\n");
  445.     if (cpu < 2) {
  446.         if (six)
  447.             analyze("Fetch", acctime[IRW],
  448.                 acctime[IRW], 2.0*acctime[IRW], "");
  449.         else
  450.             analyze("Fetch", acctime[IRB],
  451.                 acctime[IRW], 2.0*acctime[IRW], "");
  452.     } else {
  453.         if (cache) {
  454.             analyze("Cache hit",
  455.                   acctime[MRB], acctime[MRW],
  456.                    acctime[MRD], "cache");
  457.             analyze("Cache miss",
  458.                   acctime[CRB], acctime[CRW],
  459.                    acctime[CRD], "");
  460.         } else {
  461.             analyze("RAM read",
  462.              acctime[MRB], acctime[MRW], acctime[MRD], "");
  463.         }
  464.         analyze("RAM write",
  465.               acctime[MWB], acctime[MWW], acctime[MWD],
  466.               mw_pipe? "pipelined" : "");
  467.         if (emmok) {
  468.             analyze("EMM read",
  469.              acctime[ERB], acctime[ERW], acctime[ERD],
  470.              cache && acctime[ERD] < acctime[MRD] + 0.5*clktime?
  471.               "cache" : "");
  472.             analyze("EMM write",
  473.              acctime[EWB], acctime[EWW], acctime[EWD],
  474.              ew_pipe? "pipelined" : "");
  475.         }
  476.         analyze("ROM read",
  477.                acctime[RRB], acctime[RRW], acctime[RRD],
  478.             cache && acctime[ERD] < acctime[MRD] + 0.5*clktime?
  479.              "cache" : "");
  480.         analyze("Video write",
  481.                acctime[VWB], acctime[VWW], acctime[VWD], "");
  482.     }
  483. }
  484.  
  485. measure88()
  486. {
  487.     register int i;
  488.  
  489.     /*
  490.      * Measure the clock rate by executing
  491.      * multiply instructions.  Each multiply
  492.      * takes a fixed number of clock cycles.
  493.      */
  494.  
  495.     clktime = 0;
  496.     for (i = 0; i < trials; i++) {
  497.  
  498.         /*
  499.          * Obtain the number of clock ticks for
  500.          * "count" multiplies.
  501.          */
  502.  
  503.         raw = multime(count);
  504.  
  505.         /*
  506.          * Accumulate the clock time in microseconds
  507.          * by adjusting for the timer rate,
  508.          * number of clocks per multiply,
  509.          * instruction count, and test overhead.
  510.          */
  511.  
  512.         clktime +=  raw / (TIMER2_RATE *
  513.             ((double)MULCLKS88*count + MULOVH88));
  514.     }
  515.  
  516.     /*
  517.      * Calculate the average clock period by dividing by
  518.      * the number of trials.  The clock rate is the
  519.      * inverse of the clock period.
  520.      */
  521.  
  522.     clktime /= trials;
  523.     clkrate = 1.0/clktime;
  524.  
  525.     /*
  526.      * Clear all of the memory speed accumulators.
  527.      */
  528.  
  529.     for (i = 0; i < VARS88; i++)
  530.         acctime[i] = 0;
  531.  
  532.     /*
  533.      * Do the memory speed tests.
  534.      */
  535.  
  536.     for (i = 0; i < trials; i++) {
  537.  
  538.         /*
  539.          * Obtain the number of timer ticks for
  540.          * "count" clc instructions, which are
  541.          * limited by memory fetch time.
  542.          */
  543.  
  544.         raw = bclctime(count);
  545.  
  546.         /*
  547.          * Accumulate the number of microseconds
  548.          * per instruction fetch by adjusting for
  549.          * the timer rate, test overhead, and
  550.          * instruction count.
  551.          */
  552.  
  553.         acctime[IRB] +=
  554.             (raw / TIMER2_RATE - MOVOVH88) / count;
  555.  
  556.         /*
  557.          * Make a similar measurement for the
  558.          * two byte "mov" instruction.
  559.          */
  560.  
  561.         raw = wmovtime(count);
  562.         acctime[IRW] +=
  563.             (raw / TIMER2_RATE - MOVOVH88) / count;
  564.  
  565.         /*
  566.          * Make a similar measurement for the
  567.          * 4 clock "daa" instruction.
  568.          */
  569.  
  570.         raw = bdaatime(count);
  571.         acctime[IRX] +=
  572.             (raw / TIMER2_RATE - MOVOVH88) / count;
  573.     }
  574.  
  575.     /*
  576.      * Calculate averages for all measurements.
  577.      */
  578.  
  579.     for (i = 0; i < VARS88; i++)
  580.         acctime[i] /= trials;
  581.  
  582.     /*
  583.      * Calculate numeric processor clock
  584.      * rate using floating point divide
  585.      * instructions, using the same
  586.      * technique as was used to measure
  587.      * the processor clock rate.
  588.      */
  589.     if (ndpok) {
  590.  
  591.         fprate = 0;
  592.         for (i = 0; i < trials; i++) {
  593.             raw = fptime(FPCOUNT);
  594.             fpacc +=  (raw / TIMER2_RATE - FPOVH88) /
  595.                 FPCLKS88 / FPCOUNT;
  596.         }
  597.         fpacc /= trials;
  598.         fprate = 1.0/fpacc;
  599.     }
  600.  
  601.     /*
  602.      * Set 86 flag if 2 clock byte instructions
  603.      * execute faster than 4 clock instructions
  604.      * due to being fetched two to a word.
  605.      */
  606.  
  607.     six = acctime[IRB] < 0.9*acctime[IRX];
  608. }
  609.  
  610. measure186()
  611. {
  612.     register int i;
  613.  
  614.     /*
  615.      * Measure the clock rate by executing
  616.      * multiply instructions.  Each multiply
  617.      * takes a fixed number of clock cycles.
  618.      */
  619.  
  620.     clktime = 0;
  621.     for (i = 0; i < trials; i++) {
  622.  
  623.         /*
  624.          * Obtain the number of clock ticks for
  625.          * "count" multiplies.
  626.          */
  627.  
  628.         raw = multime(count);
  629.  
  630.         /*
  631.          * Accumulate the clock time in microseconds
  632.          * by adjusting for the timer rate,
  633.          * number of clocks per multiply,
  634.          * instruction count, and test overhead.
  635.          */
  636.  
  637.         clktime +=  raw / (TIMER2_RATE *
  638.             ((double)MULCLKS186*count + MULOVH186));
  639.     }
  640.  
  641.     /*
  642.      * Calculate the average clock period by dividing by
  643.      * the number of trials.  The clock rate is the
  644.      * inverse of the clock period.
  645.      */
  646.  
  647.     clktime /= trials;
  648.     clkrate = 1.0/clktime;
  649.  
  650.     /*
  651.      * Clear all of the memory speed accumulators.
  652.      */
  653.  
  654.     for (i = 0; i < VARS186; i++)
  655.         acctime[i] = 0;
  656.  
  657.     /*
  658.      * Do the memory speed tests.
  659.      */
  660.  
  661.     for (i = 0; i < trials; i++) {
  662.  
  663.         /*
  664.          * Obtain the number of timer ticks for
  665.          * "count" clc instructions, which are
  666.          * limited by memory fetch time.
  667.          */
  668.  
  669.         raw = bclctime(count);
  670.  
  671.         /*
  672.          * Accumulate the number of microseconds
  673.          * per instruction fetch by adjusting for
  674.          * the timer rate, test overhead, and
  675.          * instruction count.
  676.          */
  677.  
  678.         acctime[IRB] +=
  679.             (raw / TIMER2_RATE - MOVOVH186) / count;
  680.  
  681.         /*
  682.          * Make a similar measurement for the
  683.          * two byte "mov" instruction.
  684.          */
  685.  
  686.         raw = wmovtime(count);
  687.         acctime[IRW] +=
  688.             (raw / TIMER2_RATE - MOVOVH186) / count;
  689.  
  690.         /*
  691.          * Make a similar measurement for the
  692.          * 4 clock "daa" instruction.
  693.          */
  694.  
  695.         raw = bdaatime(count);
  696.         acctime[IRX] +=
  697.             (raw / TIMER2_RATE - MOVOVH186) / count;
  698.     }
  699.  
  700.     /*
  701.      * Calculate averages for all measurements.
  702.      */
  703.  
  704.     for (i = 0; i < VARS186; i++)
  705.         acctime[i] /= trials;
  706.  
  707.     /*
  708.      * Calculate numeric processor clock
  709.      * rate using floating point divide
  710.      * instructions, using the same
  711.      * technique as was used to measure
  712.      * the processor clock rate.
  713.      */
  714.     if (ndpok) {
  715.  
  716.         fprate = 0;
  717.         for (i = 0; i < trials; i++) {
  718.             raw = fptime(FPCOUNT);
  719.             fpacc +=  (raw / TIMER2_RATE - FPOVH186) /
  720.                 FPCLKS186 / FPCOUNT;
  721.         }
  722.         fpacc /= trials;
  723.         fprate = 1.0/fpacc;
  724.     }
  725.  
  726.     /*
  727.      * Set 86 flag if 2 clock byte instructions
  728.      * execute faster than 4 clock instructions
  729.      * due to being fetched two to a word.
  730.      */
  731.  
  732.     six = acctime[IRB] < 0.9*acctime[IRX];
  733. }
  734.  
  735. measure286()
  736. {
  737.     register int i;
  738.  
  739.     /*
  740.      * Measure the clock rate by executing
  741.      * multiply instructions.  Each multiply
  742.      * takes a fixed number of clock cycles.
  743.      */
  744.  
  745.     clktime = 0;
  746.     for (i = 0; i < trials; i++) {
  747.  
  748.         /*
  749.          * Obtain the number of clock ticks for
  750.          * "count" multiplies.
  751.          */
  752.  
  753.         raw = multime(count);
  754.  
  755.         /*
  756.          * Accumulate the clock time in microseconds
  757.          * by adjusting for the timer rate,
  758.          * number of clocks per multiply,
  759.          * instruction count, and test overhead.
  760.          */
  761.  
  762.         clktime +=  raw / (TIMER2_RATE *
  763.             ((double)MULCLKS286*count + MULOVH286));
  764.  
  765.     }
  766.  
  767.     /*
  768.      * Calculate the average clock period by dividing by
  769.      * the number of trials.  The clock rate is the
  770.      * inverse of the clock period.
  771.      */
  772.  
  773.     clktime /= trials;
  774.     clkrate = 1.0/clktime;
  775.  
  776.     /*
  777.      * Clear all of the memory speed accumulators.
  778.      */
  779.  
  780.     for (i = 0; i < VARS286; i++)
  781.         acctime[i] = 0;
  782.  
  783.     /*
  784.      * Do the memory speed tests.
  785.      */
  786.  
  787.     for (i = 0; i < trials; i++) {
  788.  
  789.         /*
  790.          * Obtain the number of timer ticks for
  791.          * "count" clc instructions, which are
  792.          * limited by memory fetch time.
  793.          */
  794.  
  795.         raw = bclctime(count);
  796.  
  797.         /*
  798.          * Accumulate the number of microseconds
  799.          * per instruction fetch by adjusting for
  800.          * the timer rate, test overhead, and
  801.          * instruction count.
  802.          */
  803.  
  804.         acctime[IRB] +=
  805.             (raw / TIMER2_RATE - MOVOVH286) / count;
  806.  
  807.         /*
  808.          * Make a similar measurement for the
  809.          * two byte "mov" instruction.
  810.          */
  811.  
  812.         raw = wmovtime(count);
  813.         acctime[IRW] +=
  814.             (raw / TIMER2_RATE - MOVOVH286) / count;
  815.  
  816.  
  817.         /*
  818.          * Measure byte read+write time
  819.          * measuring movs instructions.
  820.          */
  821.  
  822.         raw = bmvstime(count);
  823.         acctime[MRB] += raw/(TIMER2_RATE*count);
  824.  
  825.         /*
  826.          * Calculate ROM read time by
  827.          * measuring movs from ROM to RAM.
  828.          */
  829.  
  830.         raw = bromtime(count);
  831.         acctime[RRB] += raw/(TIMER2_RATE*count);
  832.  
  833.         /*
  834.          * Measure word write using the
  835.          * pusha instruction.
  836.          */
  837.  
  838.         raw = wpshtime(count) - WPOVH;
  839.         acctime[MWW] += raw/(TIMER2_RATE*count);
  840.  
  841.         /*
  842.          * Measure movs (read+write) time.
  843.          */
  844.  
  845.         raw = wmvstime(count);
  846.         acctime[MRW] += raw/(TIMER2_RATE*count);
  847.         raw = wromtime(count);
  848.         acctime[RRW] += raw/(TIMER2_RATE*count);
  849.  
  850.         /*
  851.          * If EMM is present, do measurements
  852.          * on it using the same techniques.
  853.          */
  854.  
  855.         if (emmok) {
  856.  
  857.             /*
  858.              * Measure byte mov in EMM.
  859.              */
  860.  
  861.             raw = bemmtime(count);
  862.             acctime[ERB] += raw/(TIMER2_RATE*count);
  863.  
  864.             /*
  865.              * Measure word write,
  866.              * calculate word read.
  867.              */
  868.  
  869.             raw = wemptime(count) - WPOVH;
  870.             acctime[EWW] += raw/(TIMER2_RATE*count);
  871.             raw = wemmtime(count);
  872.             acctime[ERW] += raw/(TIMER2_RATE*count);
  873.         }
  874.  
  875.         /*
  876.          * Measure byte and word writes
  877.          * into video RAM.
  878.          */
  879.  
  880.         raw = bvidtime(count);
  881.         acctime[VWB] += raw/(TIMER2_RATE*count);
  882.         raw = wvidtime(count);
  883.         acctime[VWW] += raw/(TIMER2_RATE*count);
  884.     }
  885.  
  886.     /*
  887.      * Calculate averages for all measurements.
  888.      */
  889.  
  890.     for (i = 0; i < VARS286; i++)
  891.         acctime[i] /= trials;
  892.  
  893.     /*
  894.      * Adjust word write times by subtracting
  895.      * the instruction fetch time.
  896.      */
  897.  
  898.     acctime[MWW] -= acctime[IRW]/16;
  899.     if (emmok)
  900.         acctime[EWW] -= acctime[IRW]/16;
  901.  
  902.     /*
  903.      * Adjust for extra time per instruction when
  904.      * measuring zero wait state memory.
  905.      */
  906.  
  907.     if (acctime[MWW] < 3.375*clktime)
  908.         acctime[MWW] -= clktime/8;
  909.     if (emmok)
  910.         if (acctime[EWW] < 3.375*clktime)
  911.             acctime[EWW] -= clktime/8;
  912.  
  913.     /*
  914.      * Calculate byte write time by assuming the same
  915.      * ratio between read and write as for word access.
  916.      */
  917.  
  918.     acctime[MWB] = acctime[MRB] * acctime[MWW] /
  919.                acctime[MRW];
  920.     if (emmok)
  921.         acctime[EWB] = acctime[ERB] * acctime[EWW] /
  922.                    acctime[ERW];
  923.  
  924.     /*
  925.      * Calculate read times by subtracting write time from
  926.      * mov (read+write) time.
  927.      */
  928.  
  929.     acctime[MRB] = acctime[MRB] - acctime[MWB];
  930.     acctime[MRW] = acctime[MRW] - acctime[MWW];
  931.     acctime[RRB] = acctime[RRB] - acctime[MWB];
  932.     acctime[RRW] = acctime[RRW] - acctime[MWW];
  933.     if (emmok) {
  934.         acctime[ERB] = acctime[ERB] - acctime[EWB];
  935.         acctime[ERW] = acctime[ERW] - acctime[EWW];
  936.     }
  937.  
  938.     /*
  939.      * Calculate numeric processor clock
  940.      * rate using floating point divide
  941.      * instructions, using the same
  942.      * technique as was used to measure
  943.      * the processor clock rate.
  944.      */
  945.     if (ndpok) {
  946.  
  947.         fprate = 0;
  948.         for (i = 0; i < trials; i++) {
  949.             raw = fptime(FPCOUNT);
  950.             fpacc +=  (raw / TIMER2_RATE - FPOVH286) /
  951.                 FPCLKS286 / FPCOUNT;
  952.         }
  953.         fpacc /= trials;
  954.         fprate = 1.0/fpacc;
  955.     }
  956.  
  957.     /*
  958.      * Fill in dword variables to
  959.      * provide complete input to
  960.      * analyze.
  961.      */
  962.  
  963.     acctime[MRD] = 2.0 * acctime[MRW];
  964.     acctime[MWD] = 2.0 * acctime[MWW];
  965.     acctime[ERD] = 2.0 * acctime[ERW];
  966.     acctime[EWD] = 2.0 * acctime[EWW];
  967.     acctime[RRD] = 2.0 * acctime[RRW];
  968.     acctime[VWD] = 2.0 * acctime[VWW];
  969. }
  970.  
  971. double accrd1, accrd2;
  972. measure386()
  973. {
  974.     register int i;
  975.     double pfetch;
  976.  
  977.     /*
  978.      * Make a preliminary measurement of fetch time to
  979.      * use in fine-tuning the clock measurement.
  980.      */
  981.  
  982.     raw = dmovtime(count);
  983.     pfetch = raw / TIMER2_RATE / count / 14;
  984.  
  985.     /*
  986.      * Measure the clock rate by executing
  987.      * multiply instructions.  Each multiply
  988.      * takes a fixed number of clock cycles.
  989.      */
  990.  
  991.     clktime = 0;
  992.     for (i = 0; i < trials; i++) {
  993.  
  994.         /*
  995.          * Obtain the number of clock ticks for
  996.          * "count" multiplies.
  997.          */
  998.  
  999.         raw = multime(count);
  1000.  
  1001.         /*
  1002.          * Accumulate the clock time in microseconds
  1003.          * by adjusting for the timer rate,
  1004.          * number of clocks per multiply,
  1005.          * instruction count, and test overhead.
  1006.          */
  1007.  
  1008.         clktime +=  raw / (TIMER2_RATE *
  1009.             ((double)MULCLKS386*count + MULOVH386));
  1010.  
  1011.     }
  1012.  
  1013.     /*
  1014.      * Calculate the average clock period by dividing by
  1015.      * the number of trials.  The clock rate is the
  1016.      * inverse of the clock period.
  1017.      */
  1018.  
  1019.     clktime /= trials;
  1020.     clkrate = 1.0/clktime;
  1021.  
  1022.     /*
  1023.      * Clear all of the memory speed accumulators.
  1024.      */
  1025.  
  1026.     for (i = 0; i < VARS386; i++)
  1027.         acctime[i] = 0;
  1028.     accrd1 = 0;
  1029.     accrd2 = 0;
  1030.  
  1031.     /*
  1032.      * Do the memory speed tests.
  1033.      */
  1034.  
  1035.     for (i = 0; i < trials; i++) {
  1036.  
  1037.         /*
  1038.          * Obtain the number of timer ticks for
  1039.          * "count" clc instructions, which are
  1040.          * limited by memory fetch time.
  1041.          */
  1042.  
  1043.         raw = bclctime(count);
  1044.  
  1045.         /*
  1046.          * Accumulate the number of microseconds
  1047.          * per instruction fetch by adjusting for
  1048.          * the timer rate, test overhead, and
  1049.          * instruction count.
  1050.          */
  1051.  
  1052.         acctime[IRB] +=
  1053.             (raw / TIMER2_RATE - MOVOVH386) / count;
  1054.  
  1055.         /*
  1056.          * Make a similar measurement for the
  1057.          * two byte and four byte "mov" instruction.
  1058.          */
  1059.  
  1060.         raw = wmovtime(count);
  1061.         acctime[IRW] +=
  1062.             (raw / TIMER2_RATE - MOVOVH386) / count;
  1063.  
  1064.         raw = dimmtime(count);
  1065.         acctime[IRD] +=
  1066.             (raw / TIMER2_RATE / 14 - MOVOVH386) / count;
  1067.  
  1068.  
  1069.         /*
  1070.          * Measure byte read+write time
  1071.          * measuring movs instructions.
  1072.          */
  1073.  
  1074.         raw = bmvstime(count);
  1075.         acctime[MRB] += raw/(TIMER2_RATE*count);
  1076.  
  1077.         /*
  1078.          * Calculate ROM read time by
  1079.          * measuring movs from ROM to RAM.
  1080.          */
  1081.  
  1082.         bromtime(count); /* To prime a cache */
  1083.         raw = bromtime(count);
  1084.         acctime[RRB] += raw/(TIMER2_RATE*count);
  1085.  
  1086.         /*
  1087.          * Measure word and dword write using the
  1088.          * pusha instruction.
  1089.          */
  1090.  
  1091.         raw = wpshtime(count) - WPOVH;
  1092.         acctime[MWW] += raw/(TIMER2_RATE*count);
  1093.  
  1094.         raw = dpshtime(count) - DPOVH;
  1095.         acctime[MWD] += raw/(TIMER2_RATE*count);
  1096.  
  1097.         /*
  1098.          * Measure word and dword
  1099.          * movs (read+write) time.
  1100.          */
  1101.  
  1102.         raw = wmvstime(count);
  1103.         acctime[MRW] += raw/(TIMER2_RATE*count);
  1104.         wromtime(count);
  1105.         raw = wromtime(count);
  1106.         acctime[RRW] += raw/(TIMER2_RATE*count);
  1107.  
  1108.         raw = dmvstime(count);
  1109.         acctime[MRD] += raw/(TIMER2_RATE*count);
  1110.         dromtime(count);
  1111.         raw = dromtime(count);
  1112.         acctime[RRD] += raw/(TIMER2_RATE*count);
  1113.  
  1114.         /*
  1115.          * Use some alternate methods to measure read time.
  1116.          */
  1117.  
  1118.         raw = dimmtime(count);
  1119.         accrd1 += raw/(TIMER2_RATE*count*14);
  1120.  
  1121.         raw = dlodtime(count);
  1122.         accrd2 += raw/(TIMER2_RATE*count*2);
  1123.  
  1124.         raw = dramtime(count);
  1125.         acctime[CRD] += raw/(TIMER2_RATE*count);
  1126.  
  1127.         /*
  1128. 54rr         * If EMM is present, do measurements
  1129.          * on it using the same techniques.
  1130.          */
  1131.  
  1132.         if (emmok) {
  1133.  
  1134.             bemmtime(count);
  1135.             raw = bemmtime(count);
  1136.             acctime[ERB] += raw/(TIMER2_RATE*count);
  1137.  
  1138.             raw = wemptime(count) - WPOVH;
  1139.             acctime[EWW] += raw/(TIMER2_RATE*count);
  1140.             wemmtime(count);
  1141.             raw = wemmtime(count);
  1142.             acctime[ERW] += raw/(TIMER2_RATE*count);
  1143.  
  1144.             raw = demptime(count) - DPOVH;
  1145.             acctime[EWD] += raw/(TIMER2_RATE*count);
  1146.             demmtime(count);
  1147.             raw = demmtime(count);
  1148.             acctime[ERD] += raw/(TIMER2_RATE*count);
  1149.         }
  1150.  
  1151.         /*
  1152.          * Measure writes
  1153.          * into video RAM.
  1154.          */
  1155.  
  1156.         raw = bvidtime(count);
  1157.         acctime[VWB] += raw/(TIMER2_RATE*count);
  1158.         raw = wvidtime(count);
  1159.         acctime[VWW] += raw/(TIMER2_RATE*count);
  1160.         raw = dvidtime(count);
  1161.         acctime[VWD] += raw/(TIMER2_RATE*count);
  1162.     }
  1163.  
  1164.     /*
  1165.      * Calculate averages for all measurements.
  1166.      */
  1167.  
  1168.     for (i = 0; i < VARS386; i++)
  1169.         acctime[i] /= trials;
  1170.     accrd1 /= trials;
  1171.     accrd2 /= trials;
  1172. }
  1173.  
  1174. adjust386()
  1175. {
  1176.     register int i;
  1177.     double fpclks;
  1178.  
  1179.     /*
  1180.      * Adjust word write times by subtracting
  1181.      * the instruction fetch time.
  1182.      */
  1183.  
  1184.     acctime[MWW] -= acctime[IRW]/16;
  1185.     acctime[MWD] -= acctime[IRW]/8;
  1186.     if (emmok) {
  1187.         acctime[EWW] -= acctime[IRW]/16;
  1188.         acctime[EWD] -= acctime[IRW]/8;
  1189.     }
  1190.  
  1191.     /*
  1192.      * Adjust for extra time per instruction when
  1193.      * measuring zero wait state memory.
  1194.      */
  1195.  
  1196.     if (acctime[MWW] < 3.375*clktime)
  1197.         acctime[MWW] -= clktime;
  1198.     if (acctime[MWD] < 3.375*clktime)
  1199.         acctime[MWD] -= clktime;
  1200.     if (emmok) {
  1201.         if (acctime[EWW] < 3.375*clktime)
  1202.             acctime[EWW] -= clktime;
  1203.         if (acctime[EWD] < 3.375*clktime)
  1204.             acctime[EWD] -= clktime;
  1205.     }
  1206.  
  1207.     /*
  1208.      * Calculate byte write time by assuming the same
  1209.      * ratio between read and write as for word access.
  1210.      */
  1211.  
  1212.     acctime[MWB] = acctime[MRB] * acctime[MWW] /
  1213.                acctime[MRW];
  1214.     if (emmok)
  1215.         acctime[EWB] = acctime[ERB] * acctime[EWW] /
  1216.                    acctime[ERW];
  1217.  
  1218.     /*
  1219.      * Calculate read times by subtracting write time from
  1220.      * mov (read+write) time.
  1221.      */
  1222.  
  1223.     acctime[MRB] = acctime[MRB] - acctime[MWB];
  1224.     acctime[MRW] = acctime[MRW] - acctime[MWW];
  1225.     acctime[MRD] = acctime[MRD] - acctime[MWD];
  1226.  
  1227.     /*
  1228.      * Don't believe read time if less than 2 clocks
  1229.      */
  1230.  
  1231.     if (acctime[MRD] < 1.75*clktime) {
  1232.         mw_pipe = 1;
  1233.     }
  1234.  
  1235.     /*
  1236.      * Use alternate read times for double, if better.
  1237.      */
  1238.  
  1239.     if (accrd1 < acctime[MRD] || mw_pipe) {
  1240.         acctime[MRB] = accrd1;
  1241.         acctime[MRW] = accrd1;
  1242.         acctime[MRD] = accrd1;
  1243.     }
  1244.     if (accrd2 < acctime[MRD]) {
  1245.         acctime[MRB] = accrd2;
  1246.         acctime[MRW] = accrd2;
  1247.         acctime[MRD] = accrd2;
  1248.     }
  1249.  
  1250.     acctime[RRB] = acctime[RRB] - acctime[MWB];
  1251.     acctime[RRW] = acctime[RRW] - acctime[MWW];
  1252.     acctime[RRD] = acctime[RRD] - acctime[MWD];
  1253.     if (mw_pipe) {
  1254.         acctime[RRB] += acctime[MRD];
  1255.         acctime[RRW] += acctime[MRD];
  1256.         acctime[RRD] += acctime[MRD];
  1257.     }
  1258.     if (emmok) {
  1259.         acctime[ERB] = acctime[ERB] - acctime[EWB];
  1260.         acctime[ERW] = acctime[ERW] - acctime[EWW];
  1261.         acctime[ERD] = acctime[ERD] - acctime[EWD];
  1262.         if (acctime[ERD] < 1.75*clktime) {
  1263.             ew_pipe = 1;
  1264.             acctime[ERB] = acctime[MRD];
  1265.             acctime[ERW] = acctime[MRD];
  1266.             acctime[ERD] = acctime[MRD];
  1267.         }
  1268.     }
  1269.  
  1270.     if (acctime[CRD] - accrd2 > accrd2 + 0.5*clktime) {
  1271.         cache = 1;
  1272.         acctime[CRD] -= accrd2;
  1273.         acctime[CRW] = acctime[CRD];
  1274.         acctime[CRB] = acctime[CRD];
  1275.     }
  1276.  
  1277.     /*
  1278.      * Calculate numeric processor clock
  1279.      * rate using floating point divide
  1280.      * instructions, using the same
  1281.      * technique as was used to measure
  1282.      * the processor clock rate.
  1283.      */
  1284.  
  1285.     if (ndpok) {
  1286.  
  1287.         fastmath = detect_387();
  1288.         if (fastmath)
  1289.             fpclks = FPCLKS387;
  1290.         else
  1291.             fpclks = FPCLKS386;
  1292.         fprate = 0;
  1293.         for (i = 0; i < trials; i++) {
  1294.             raw = fptime(count);
  1295.             fpacc +=  (raw / TIMER2_RATE - MULOVH386) / count;
  1296.         }
  1297.         fpacc = (fpacc / trials - 1.5*acctime[IRD]) / fpclks;
  1298.         fprate = 1.0/fpacc;
  1299.     }
  1300. }
  1301.  
  1302. /*
  1303.  * analyze
  1304.  *
  1305.  * This procedure deduces information about the memory based on
  1306.  * the measured times.
  1307.  * If byte (8 bits) and word (16 bits) times are different then
  1308.  * the memory is byte oriented since each word operation takes
  1309.  * two byte operations.  Otherwise, if the byte and word
  1310.  * times are about the same, the memory is word oriented and can
  1311.  * access either a word or a byte in a single memory cycle.
  1312.  * Similar arguments can be made about 32 bit accesses.
  1313.  *
  1314.  * Each memory access takes an exact number of processor clock
  1315.  * cycles.  The first two are required by the processor, but
  1316.  * any additional cycles are determined by the memory and are
  1317.  * called wait states (because the processor is waiting for
  1318.  * the memory.)
  1319.  */
  1320.  
  1321. analyze(name, btime, wtime, dtime, notes)
  1322.     char    *name;
  1323.     double    btime;
  1324.     double    wtime;
  1325.     double    dtime;
  1326.     char    *notes;
  1327. {
  1328.     double    t;
  1329.  
  1330.     /*
  1331.      * Print the heading
  1332.      */
  1333.  
  1334.     printf("%-12s", name);
  1335.  
  1336.     /*
  1337.      * Determine whether the memory is byte
  1338.      * oriented, word oriented, dword oriented, or other.
  1339.      * (If other, the data are suspect.)
  1340.      */
  1341.  
  1342.     if (wtime > dtime*0.66 &&
  1343.         wtime < dtime*1.33) {
  1344.         printf("        Dword ");
  1345.         t = dtime;
  1346.     } else if (wtime*2 > dtime*0.66 &&
  1347.            wtime*2 < dtime*1.33 &&
  1348.            btime > wtime*0.66 &&
  1349.            btime < wtime*1.33) {
  1350.         printf("        Word  ");
  1351.         t = wtime;
  1352.     } else if (btime*2 > wtime*0.66 &&
  1353.            btime*2 < wtime*1.33) {
  1354.         printf("        Byte  ");
  1355.         t = btime;
  1356.     } else {
  1357.         printf("       Strange");
  1358.         t = btime;
  1359.     }
  1360.  
  1361.     /*
  1362.      * Determine the number of wait states
  1363.      * by dividing by the clock period,
  1364.      * subtracting two processor clock times,
  1365.      * and rounding down to an integer.
  1366.      */
  1367.  
  1368.     t = t / clktime - access_clks;
  1369.     if (t < 0.0)
  1370.         t = 0.0;
  1371. /****** printf("              %6d", (unsigned)t); ******/
  1372.     printf("              %6.1g", t);
  1373.     printf(" %s\n", notes);
  1374. }
  1375.