Document:         BusSpeed.txt
File Group:       Classic Benchmarks       
Creation Date:    30 October 1997
Revision Date:    26 November 1997

Title:            Memory Bus Speed Test
Keywords:         BENCHMARK PERFORMANCE MEMORY BUS  

Abstract:         This document contains details of a program
                  designed to measure data transfer rates of memory
                  busses and associated CPU speeds. Versions are
                  supplied to run via DOS, Windows 95 or NT and OS/2.
                  Besides measuring performance, the program can be
                  used for reliability testing. 

Note:             The program is still under test and should be
                  treated as beta test software.  Please submit
                  feedback directly to Roy, or as a posting in
                  Section 12 message board.

Contributor:      Roy_Longbottom@compuserve.com (101323,2241)


Latest Revision:  BAT files modifies to use 256 KB memory. See
                  README.TXT for other revisions.

MEMORY BUS SPEED TEST

1. INTRODUCTION

This benchmark program is based on work by Verne Tice and suggestions 
from Scott Taylor. It loads data from an array via L1 cache, L2 cache
or RAM using quad words (4 bytes). 

The high data transfer speeds of the program are produced via 
assembly language instructions that just move data from memory to CPU
registers. The first test only loads the first four bytes out of 32,
where it can normally be assumed that this will cause a burst read
from memory of all 32 bytes.

As the concept of loading data and doing nothing with it is a 
completely artificial situation and can produce misleading 
performance comparisons, further tests have been included to load all
data and process it. Some routines are designed to give an indication
of peak performance where more than one integer arithmetic unit is
provided within the CPU. These features were added, particularly to
help in identifying reasons for performance differences when running
the Classic Benchmarks.   

Versions of the program are supplied to run via DOS, Windows 95 or NT
and OS/2 using Watcom C/C++ Version 11 compiler. The programs can be
run simply by clicking on an icon or entering the program name at a
command line prompt to run the 32 byte test. Run time parameters can
also be included to run extended sequences of more complex tests.
 
Facilities provided via the run time parameters are:

    Running time up to 600 seconds, with automatic calibration,
    default 5 seconds.

    Volume of data to use, 2KB to 4096KB, defaults 4, 64, 2048.

    Address increment of 32 bytes (default). With the first 4 bytes
    loaded to a CPU register, on loading from L2 cache or RAM, 32
    bytes are likely to be passed via the connecting bus. 

    Address increment of 4 bytes to load all data to registers.

    Address offset of 0, 1, 2, 3, 4 to 64 bytes to show effects
    of data not aligned to 32 byte boundary.

    Loading to 1 register (default) or 2 registers.

    User defined alternating data pattern, default A5A5A5A5 and
    5A5A5A5A (binary 1010... and 0101...). Alternates every 32 bytes.

    User defined data pattern, same pattern to all bytes.

    Checking data via AND or AND/XOR as opposed to loading via
    MOV instruction, using 1 or 2 registers. These combinations
    identify significant performance variations between different
    CPUs.

    Results appended to log file (BUSREAD.TXT or user defined file)
    with option to omit headings on running a series of tests.

Programs BUSNT95.EXE, BUSDOS.EXE and BUSOS2.EXE are supplied to run
via Windows 95 or NT, MS DOS and OS/2. W32BUSRD.BAT, DOSBUSRD.BAT and
OS2BUSRD.CMD, corresponding batch files, are provided to run a series
of tests. Other batch files with a TXT extension are also supplied to
run other tests - see README.TXT.

Result are calculated in terms of millions of load instructions per
second (MIPS) and millions of bytes loaded to registers per second
(MB/Sec).


2. PROGRAM DETAILS

The same C++ program (BUSSPEED.CPP) was compiled for all versions.
This includes assembly language used via #pragmas, each of which
contains a sequence of 64 instructions to load data. 


a. LOADING WITH 32 BYTE INCREMENTS

Executed via function readmem32(x, mempasses, offset)

Register edx is loaded with the start address of a data array
int x[1048640] (>4MB), eax with a pass count and ecx with an
address byte offset (0 to 64).

Each mov translates to a single machine code instruction, the address
addition being carried out during instruction decoding. Each mov can
be expected to complete within 1 CPU clock cycle but some CPUs can
produce two results per clock, MIPS results approaching 2 x CPU MHz
on testing via L1 cache.

  #pragma aux  readmem32  =  \
       "add     edx,ecx"     \
   "lp: mov     ebx,[edx]"   \
       "mov     ebx,[edx+32]"   \
       "mov     ebx,[edx+64]"   \
       "mov     ebx,[edx+96]"   \
       "mov     ebx,[edx+128]"   \
       "mov     ebx,[edx+160]"   \
       "mov     ebx,[edx+192]"   \
       "mov     ebx,[edx+224]"   \
       "mov     ebx,[edx+256]"   \
       "mov     ebx,[edx+288]"   \
       "mov     ebx,[edx+320]"   \
       "mov     ebx,[edx+352]"   \
       "mov     ebx,[edx+384]"   \
       "mov     ebx,[edx+416]"   \
       "mov     ebx,[edx+448]"   \
       "mov     ebx,[edx+480]"   \
       "mov     ebx,[edx+512]"   \
       "mov     ebx,[edx+544]"   \
       "mov     ebx,[edx+576]"   \
       "mov     ebx,[edx+608]"   \
       "mov     ebx,[edx+640]"   \
       "mov     ebx,[edx+672]"   \
       "mov     ebx,[edx+704]"   \
       "mov     ebx,[edx+736]"   \
       "mov     ebx,[edx+768]"   \
       "mov     ebx,[edx+800]"   \
       "mov     ebx,[edx+832]"   \
       "mov     ebx,[edx+864]"   \
       "mov     ebx,[edx+896]"   \
       "mov     ebx,[edx+928]"   \
       "mov     ebx,[edx+960]"   \
       "mov     ebx,[edx+992]"   \
       "mov     ebx,[edx+1024]"   \
       "mov     ebx,[edx+1056]"   \
       "mov     ebx,[edx+1088]"   \
       "mov     ebx,[edx+1120]"   \
       "mov     ebx,[edx+1152]"   \
       "mov     ebx,[edx+1184]"   \
       "mov     ebx,[edx+1216]"   \
       "mov     ebx,[edx+1248]"   \
       "mov     ebx,[edx+1280]"   \
       "mov     ebx,[edx+1312]"   \
       "mov     ebx,[edx+1344]"   \
       "mov     ebx,[edx+1376]"   \
       "mov     ebx,[edx+1408]"   \
       "mov     ebx,[edx+1440]"   \
       "mov     ebx,[edx+1472]"   \
       "mov     ebx,[edx+1504]"   \
       "mov     ebx,[edx+1536]"   \
       "mov     ebx,[edx+1568]"   \
       "mov     ebx,[edx+1600]"   \
       "mov     ebx,[edx+1632]"   \
       "mov     ebx,[edx+1664]"   \
       "mov     ebx,[edx+1696]"   \
       "mov     ebx,[edx+1728]"   \
       "mov     ebx,[edx+1760]"   \
       "mov     ebx,[edx+1792]"   \
       "mov     ebx,[edx+1824]"   \
       "mov     ebx,[edx+1856]"   \
       "mov     ebx,[edx+1888]"   \
       "mov     ebx,[edx+1920]"   \
       "mov     ebx,[edx+1952]"   \
       "mov     ebx,[edx+1984]"   \
       "mov     ebx,[edx+2016]"   \
       "add     edx,2048"     \
       "dec     eax"         \
       "jnz     lp"          \             
        parm [edx] [eax] [ecx] \
        modify [ebx];
 
Before the timed run, a calibration phase could be expected to pre-
load data into L1 or L2 cache, if it will fit.

The volume of data covered by the test is determined by a variable 
loaded into register eax, for example 2, 32 and 1024 for 4KB, 64KB
and 2048KB. These values are used by the default version as they
currently provide measurements via L1 cache, L2 cache and RAM.


b. LOADING DATA WITH 4 BYTE INCREMENTS

#pragma aux  readmem4  =   \
       "add     edx,ecx"   \
   "lp: mov     ebx,[edx]"   \
       "mov     ebx,[edx+4]"   \
       "mov     ebx,[edx+8]"   \
       .
       .
       .
       "mov     ebx,[edx+248]"   \
       "mov     ebx,[edx+252]"   \
       "add     edx,256"     \
       "dec     eax"         \
       "jnz     lp"          \             
        parm [edx]  [eax] [ecx] \
        modify [ebx];

Register eax values are, for example, 16, 256 and 8192 for 4KB, 64KB
and 2048KB.


c. LOADING DATA WITH 4 BYTE INCREMENTS TO 2 REGISTERS

#pragma aux  readmem4b  =  \
       "add     edx,ecx"   \
   "lp: mov     ebx,[edx]"   \
       "mov     ecx,[edx+4]"   \
       "mov     ebx,[edx+8]"   \
       "mov     ecx,[edx+12]"   \
       .
       .
       .
       "mov     ebx,[edx+248]"   \
       "mov     ecx,[edx+252]"   \
       "add     edx,256"     \
       "dec     eax"         \
       "jnz     lp"          \             
        parm [edx]  [eax] [ecx] \
        modify [ebx];


d. LOADING DATA WITH 4 BYTE INCREMENTS AND CHECKING  

Function checkmem1(x, mempasses, offset, result) is used for tests
that check the data. For the first of these, the data is identical
in all words loaded. The result parameter provides the address of
the number used. This address is loaded to register edi and the
value into ebx. The AND instruction is used with all data loaded.
Assuming no data has been corrupted, ebx will contain the same number
at the end and this is returned to the result variable where it is
checked by the C++ code.

#pragma aux  checkmem1  =   \
       "add     edx,ecx"     \
       "mov     ebx,[edi]"   \
   "lp: and     ebx,[edx]"   \
       "and     ebx,[edx+4]"   \
       "and     ebx,[edx+8]"   \
       .
       .
       .
       "and     ebx,[edx+244]"   \
       "and     ebx,[edx+248]"   \
       "and     ebx,[edx+252]"   \
       "add     edx,256"     \
       "dec     eax"         \
       "jnz     lp"          \
       "mov     [edi],ebx"     \             
        parm [edx] [eax] [ecx] [edi] \
        modify [ebx];


e. LOADING DATA WITH 4 BYTE INCREMENTS AND CHECKING, 2 REGISTERS  

This stores the number in ebx and ecx, ANDing them at the end before
returning the result.

#pragma aux  checkmem1b  =   \
       "add     edx,ecx"     \
       "mov     ebx,[edi]"   \
       "mov     ecx,ebx"     \
   "lp: and     ebx,[edx]"   \
       "and     ecx,[edx+4]"   \
       "and     ebx,[edx+8]"   \
       .
       .
       .
       "and     ecx,[edx+244]"   \
       "and     ebx,[edx+248]"   \
       "and     ecx,[edx+252]"   \
       "add     edx,256"     \
       "dec     eax"         \
       "jnz     lp"          \
       "and     ebx,ecx"     \
       "mov     [edi],ebx"     \             
        parm [edx] [eax] [ecx] [edi] \
        modify [ebx];


f. CHECKING DATA ALTERNATING PATTERNS  

For these, data is inverted every 32 bytes e.g. FFFF000 to 0000FFFF.
AND and XOR are used to collect the result.

#pragma aux  checkmem2  =   \
       "add     edx,ecx"     \
       "mov     ebx,[edi]"   \
   "lp: and     ebx,[edx]"   \
       "and     ebx,[edx+4]"   \
       "and     ebx,[edx+8]"   \
       "and     ebx,[edx+12]"   \
       "and     ebx,[edx+16]"   \
       "and     ebx,[edx+20]"   \
       "and     ebx,[edx+24]"   \
       "and     ebx,[edx+28]"   \
       "xor     ebx,[edx+32]"   \
       "xor     ebx,[edx+36]"   \
       .
       .
       .
       "and     ebx,[edx+216]"   \
       "and     ebx,[edx+220]"   \
       "xor     ebx,[edx+224]"   \
       "xor     ebx,[edx+228]"   \
       "xor     ebx,[edx+232]"   \
       "xor     ebx,[edx+236]"   \
       "xor     ebx,[edx+240]"   \
       "xor     ebx,[edx+244]"   \
       "xor     ebx,[edx+248]"   \
       "xor     ebx,[edx+252]"   \
       "add     edx,256"     \
       "dec     eax"         \
       "jnz     lp"          \
       "mov     [edi],ebx"     \             
        parm [edx] [eax] [ecx] [edi] \
        modify [ebx];


g. CHECKING DATA ALTERNATING PATTERNS, 2 REGISTERS  

#pragma aux  checkmem2b  =   \
       "add     edx,ecx"     \
       "mov     ebx,[edi]"   \
       "mov     ecx,ebx"     \
   "lp: and     ebx,[edx]"   \
       "and     ecx,[edx+4]"   \
       "and     ebx,[edx+8]"   \
       "and     ecx,[edx+12]"   \
       "and     ebx,[edx+16]"   \
       "and     ecx,[edx+20]"   \
       "and     ebx,[edx+24]"   \
       "and     ecx,[edx+28]"   \
       "xor     ebx,[edx+32]"   \
       "xor     ecx,[edx+36]"   \
       .
       .
       .
       "xor     ebx,[edx+248]"   \
       "xor     ecx,[edx+252]"   \
       "add     edx,256"     \
       "dec     eax"         \
       "jnz     lp"          \
       "and     ebx,ecx"     \
       "mov     [edi],ebx"     \             
        parm [edx] [eax] [ecx] [edi] \
        modify [ebx];


h.  C PROGRAM 

The C program has a longhand structure to avoid unexpected timing 
overheads, for example:


        if (increment == 4)
         {
             if (check == 0)
              { 
                if (reg == 2)
                 { 
                    timea = millisecs();        
                    for (j=0; j<loopj; j++)
                      { 
                        for (i=0; i<loops; i++)
                          {
                              readmem4b(x, mempasses, offset);             
                          }
                      }            
                    timeb = millisecs() - timea;
                 }
                else
                 {
                    timea = millisecs();        
                    for (j=0; j<loopj; j++)
                      { 
                        for (i=0; i<loops; i++)
                          {
                              readmem4(x, mempasses, offset);             
                          }
                      }            
                    timeb = millisecs() - timea;
                 }

The number of loop passes is determined via the same sort of 
structure in a calibration phase with increasing loop counts that
might take 3 seconds. Timing is via the standard C clock() function.
As the PC clock can be expected to be updated at around 50 ms 
intervals, timing should not be carried out over less than 5 seconds
as used with default parameters.


3. RUN TIME PARAMETERS AND HELP

In the event of unacceptable parameters being used, generally the
following HELP will be displayed (example invalid as can only check
results with Offset 0):

COMMAND  Secs 10, KB 4096, Inc 4, Offset 1, Alt F0F0F0F0, Check 1

The program can have up to 9 run time parameters with the format

                                                         default

Secs x     or S x   - Run time seconds,      x = 1-600     5
KB x       or K x   - Memory KBytes to use,  x = 2-4096  4,64,2048
Offset x   or O x   - Offset data address,   x = 0 -64     0
Inc x      or I x   - Loop increment         x = 4 or 32  32
Reg x      or R x   - Registers to load to   x = 1 or 2  1 Inc 4 only
Pattern H  or P H   - Data pattern to use    H = hex no. A5A5A5A5
Alt     H  or A H   - H and H XOR FFFFFFFF   H = hex no. 5A5A5A5A
Log nn     or L nn  - User defined log file nn = name    busread.txt
Check 1    or C 1   - Validate results         - Inc 4 Offset 0 only
NoHeadings or N     - Do not save headings     - one line results
 
Examples commands to run for 20 seconds, 32KB and 1024KB, offset 4
and read pattern from RAM for 10 minutes, loading all bytes/checking

    BUSvvv Secs 20, KB 32,   O 4            - vvv is program version
    BUSvvv Secs 20, KB 1024, O 4, NoHeadings
    BUSvvv Secs 600, KB 4096, Inc 4, Pattern A5A5A5A5, C 1
       
Press any key to end

Note: for a command defining a log file, do not add a comma after the
file name e.g. the following is correct:

   BUSNT95 Secs 180, KB 4096, Inc 4, Log BusLog1.txt Check 1

Commas are optional following number parameters.

For further example commands, see the BAT files (list given below).
For example, DOSBUSRD.BAT is:

REM  Various Tests using 1 or 2 registers
REM
REM  Tests are for 4 KB to fit in L1 cache, 64 KB and 256 KB
REM  for L2 cache and 2048 KB to test via RAM. All run for
REM  5 seconds (+ 2 or 3 for calibration).
REM
REM  Results are added to file BUSREAD.TXT
REM
REM  See BUSSPEED.TXT for program details 
 
REM  Test 1 - 32 byte increments
REM 
REM  Loading  4 bytes with 32 byte address increments
REM  using MOV instruction and 1 register.
 
BUSDOS KB    4
BUSDOS KB   64, N
BUSDOS KB  256, N
BUSDOS KB 2048, N


REM  Test 2 - Loading every byte
REM
REM   Loading every byte (4 byte address increments),
REM   using MOV instruction to 1 and 2 registers, no headings

BUSDOS KB    4, Inc 4, N 
BUSDOS KB   64, Inc 4, N 
BUSDOS KB  256, Inc 4, N 
BUSDOS KB 2048, Inc 4, N

BUSDOS KB    4, Inc 4, Reg 2, N
BUSDOS KB   64, Inc 4, Reg 2, N
BUSDOS KB  256, Inc 4, Reg 2, N
BUSDOS KB 2048, Inc 4, Reg 2, N

REM  Test 3 - Checking data
REM
REM  Default version uses data patterns A5A5A5A5 and
REM  and 5A5A5A5A alternating every 32 bytes. The
REM  program uses AND and XOR instructions to produce
REM  one result, 1 and 2 registers.

BUSDOS KB    4, Inc 4, Check 1
BUSDOS KB   64, Inc 4, Check 1, N
BUSDOS KB  256, Inc 4, Check 1, N
BUSDOS KB 2048, Inc 4, Check 1, N

BUSDOS KB    4, Inc 4, Reg 2, Check 1, N
BUSDOS KB   64, Inc 4, Reg 2, Check 1, N 
BUSDOS KB  256, Inc 4, Reg 2, Check 1, N 
BUSDOS KB 2048, Inc 4, Reg 2, Check 1, N

REM  Above is same as using parameter Alt for user
REM  defined pattern - BUSDOS Inc 4, Alt A5A5A5A5, Check 1

REM  Test 4 - Loading every byte, checking, same data
REM
REM  This test uses the same pattern in every word
REM  and uses AND instructions to produce one result.
REM  Note pattern could be any 8 digit hex number.

BUSDOS KB    4, Inc 4, Pattern A5A5A5A5, Check 1, N
BUSDOS KB   64, Inc 4, Pattern A5A5A5A5, Check 1, N 
BUSDOS KB  256, Inc 4, Pattern A5A5A5A5, Check 1, N 
BUSDOS KB 2048, Inc 4, Pattern A5A5A5A5, Check 1, N

BUSDOS KB    4, Inc 4, Reg 2, Pattern A5A5A5A5, Check 1, N
BUSDOS KB   64, Inc 4, Reg 2, Pattern A5A5A5A5, Check 1, N
BUSDOS KB  256, Inc 4, Reg 2, Pattern A5A5A5A5, Check 1, N
BUSDOS KB 2048, Inc 4, Reg 2, Pattern A5A5A5A5, Check 1, N


4.  MEMORY BUS SPEED TEST CONTENTS OF ZIP FILE

The following is given in README.TXT

README.TXT 

BUSSPEED.TXT  - Description of benchmark
RESULTS.TXT   - Results on 200 MHz Pentium Pro, 200 MHz Pentium
                MMX and 100 MHz Pentium. Examples given via DOS,
                Windows 95, Windows NT and OS/2 Warp 3.

BUSNT95.EXE   - Version of benchmark to run via Windows 95 and NT
BUSDOS.EXE    - Version of benchmark to run via DOS. This requires
                DOS4GW to run
BUSOS2.EXE    - Version of benchmark to run via OS/2

       These can be run by clicking on icon or via command line
       prompt. Default parameters will apply, using 4KB, 64KB and
       2048KB memory and loading 4 bytes to a register with 32
       byte increments to next load.

DOS4GW.EXE    - Protected run time program

W32BUSRD.BAT  - BAT file to carry out series of tests with BUSNT95
DOSBUSRD.BAT  - BAT file to carry out series of tests with BUSDOS
OS2BUSRD.CMD  - CMD file to carry out series of tests with BUSOS2

     Tests use 4KB, 64KB, 256 KB and 2048KB. Tests 2 to 7 load all
     data using address increment of 4. Tests 4 and 5 have different
     hex numbers alternating every 32 bytes. Tests 6 and 7 use the
     same data in all words.

      1. Default test using MOV instruction
      2. Loading to 1 register,  MOV instruction
      3. Loading to 2 registers, MOV instruction
      4. Checking results, 1 register,  AND + XOR instructions
      5. Checking results, 2 registers, AND + XOR instructions
      6. Checking results, 1 register,  AND instructions
      7. Checking results, 2 registers, AND instructions

W32BATx.TXT   - BAT files for extra tests with BUSNT95
DOSBATx.TXT   - BAT files for extra tests with BUSDOS
OS2CMDx.TXT   - CMD files for extra tests with BUSOS2

     These carry out a series of tests at 4KB, 64KB and 2048KB,
     starting at addresses (offset) 0, 1, 2, 3 etc., x indicates: 
 
      x=2     - 32 byte increments, address offset 0 to 31
      x=3     -  4 byte increments, address offset 0 to 16
      x=4     -  as 3 but loading to 2 registers


5.  RESULTS

Results are displayed as the tests are completed and appended to file 
BUSREAD.TXT. The following is an example on running DOSBUSRD.BAT on a
200 MHz Pentium MMX with SDRAM.

Bus Read Test DOS Version 1.2, Tue Nov 25 13:17:55 1997
            Copyright (C) 1997, Roy Longbottom

        Via Watcom Version 11, log file Busread.txt

  One or two registers loaded from data address 0055cd40 plus offset
  then with 32 or 4 byte increments. Test 1 running time 5 seconds.
  Data patterns 0xa5a5a5a5 and 0x5a5a5a5a alternating every 32 bytes
  Millions of load instructions per second are shown under MIPS. Each
  instruction loads 4 bytes at millions of bytes per second 4 Byte.
  If 32 byte increments are used, on loading from L2 cache or RAM, 32
  bytes are likely to be transferred with each load so multiply MB/S
  by 8 for data transfer rate (16 bytes on 486 so x 4).

  DWORDS   KB Loops*Loops Reg Inc Off   Secs    MIPS  MB/Sec
                                  set                 4 Byte

    1024    4 1032204   7   1  32   0    4.9   189.1     757
   16384   64   32467   1   1  32   0    5.0    13.2      53
   65536  256    8116   1   1  32   0    5.0    13.3      53
  524288 2048     555   1   1  32   0    5.0     7.3      29
    1024    4  946969   1   1   4   0    5.0   193.9     776
   16384   64   18063   1   1   4   0    5.1    58.5     234
   65536  256    4562   1   1   4   0    5.1    59.1     236
  524288 2048     337   1   1   4   0    5.0    35.3     141
    1024    4 1806358   1   2   4   0    5.1   365.6    1462
   16384   64   17857   1   2   4   0    4.9    59.2     237
   65536  256    4562   1   2   4   0    5.1    59.1     236
  524288 2048     337   1   2   4   0    5.1    34.9     140


   Bus Read Test DOS Version 1.2, Tue Nov 25 13:20:10 1997
            Copyright (C) 1997, Roy Longbottom

        Via Watcom Version 11, log file Busread.txt

  One or two registers loaded from data address 0055cd40 plus offset
  then with 32 or 4 byte increments. Test 1 running time 5 seconds.
  Data patterns 0xa5a5a5a5 and 0x5a5a5a5a alternating every 32 bytes
  Millions of load instructions per second are shown under MIPS. Each
  instruction loads 4 bytes at millions of bytes per second 4 Byte.
  If 32 byte increments are used, on loading from L2 cache or RAM, 32
  bytes are likely to be transferred with each load so multiply MB/S
  by 8 for data transfer rate (16 bytes on 486 so x 4).

  DWORDS   KB Loops*Loops Reg Inc Off   Secs    MIPS  MB/Sec Check No
                                  set                 4 Byte a5a5a5a5

    1024    4  484496   1   1   4   0    5.0    98.2     393  OK A+X
   16384   64   14925   1   1   4   0    5.1    47.9     191  OK A+X
   65536  256    3731   1   1   4   0    5.0    48.4     194  OK A+X
  524288 2048     298   1   1   4   0    5.0    31.2     125  OK A+X
    1024    4  929368   1   2   4   0    4.9   192.6     771  OK A+X
   16384   64   17630   1   2   4   0    4.9    58.5     234  OK A+X
   65536  256    4370   1   2   4   0    4.9    58.7     235  OK A+X
  524288 2048     334   1   2   4   0    5.0    35.1     140  OK A+X
    1024    4  473484   1   1   4   0    4.9    99.2     397  OK AND
   16384   64   14662   1   1   4   0    4.9    48.6     195  OK AND
   65536  256    3665   1   1   4   0    4.9    48.6     194  OK AND
  524288 2048     298   1   1   4   0    5.0    31.3     125  OK AND
    1024    4  929368   1   2   4   0    4.9   194.6     778  OK AND
   16384   64   17655   1   2   4   0    5.0    58.4     234  OK AND
   65536  256    4464   1   2   4   0    5.0    58.5     234  OK AND
  524288 2048     332   1   2   4   0    4.9    35.2     141  OK AND


The following is a summary of results, millions of bytes per second
figures with 32 byte address increments being derived by multiplying
MIPS by 32 for L2 cache and RAM. What do the results tell us?


BUS CLOCKS

The bus connecting RAM and L2 cache to the CPU is 8 bytes wide and
running at 66.67 MHz, so a maximum throughput of 533 MB/Sec could be
expected. Transfer time would be 15 ns per 8 bytes.

Considering burst transfers over a bus, it is usual to express the
loading as four numbers representing bus clocks such as 5-2-2-2, 
where the first 8 bytes requires 5 clocks and subsequent transfers
2 clocks each.

With L2 transfer rate of 429 MB/S gives 2.33 ns per byte or 74.6 ns
for 32 bytes. This could be said to have a 2-1-1-1 profile.

Similarly, SDRAM transfer time is 137 ns per 32 bytes, or about 9 
bus clock cycles. This suggests a 3-2-2-2 or 6-1-1-1 profile. I have
seen a quote that SDRAM would have a 5-1-1-1 profile, EDO at 5-2-2-2
and 60 ns DRAM 5-3-3-3.

Note that 15.15 ns might be suggested as the bus clock time to be 
used as clock speeds vary with temperature.

                              
                                 L1    L2    RAM   L1    L2    RAM
                                MIPS  MIPS  MIPS  MB/S  MB/S  MB/S

Increment 32                   188.2  13.4   7.3   753   429*  234*   
Inc 4, 1 register  MOV         193.9  59.2  35.1   776   237   141
Inc 4, 2 registers MOV         366.3  59.1  35.3  1465   236   141
Inc 4, 1 register  AND/XOR      98.2  48.1  31.2   393   193   125
Inc 4, 2 registers AND/XOR     191.9  58.1  35.0   768   232   140
Inc 4, 1 register  AND          98.3  48.2  31.2   393   193   125
Inc 4, 2 registers AND         190.7  58.3  35.0   763   233   140

                                                      * MIPS x 32

CPU

The results clearly demonstrate that the CPU can load two registers 
per clock cycle but, using these particular instructions, the two
integer pipelines only produce one arithmetic result per clock.


BUS SPEED WITH PROCESSING

On loading all data to registers (Inc 4), best data transfer rates  
obtained are similar to those on loading 8 bytes at a time in the MMX
benchmark MMXMAX (in MMXSPEED.ZIP, results in MMX&MEM.ZIP).

The data transfer rates over the bus appear to be affected by the 
rate that the data can be absorbed by the processor. Note that 
transfer rates of 237/141 and 193/125 equate to 9/15 and 11/17 bus 
clock cycles per 32 bytes. With the 32 byte increment giving 5/9 
cycles, this represents 4/6 and 6/8 bus cycles missed due to 
processing. Remember that this is for 8 instructions, where results
are produced at intervals of 0.5, 1 or 2 per 5 ns per instruction or
80, 40 or 20 ns for 8 operations.


6.  RESULTS WITH OFFSET

The supplied files DOSBAT2.TXT, DOSBAT3.TXT and DOSBAT4.TXT (and
W32BAT and OS2CMD equivalents) can be renamed with .BAT extensions 
(or .CMD for OS/2) and run.

DOSBAT2 uses default 32 byte address increments completing a 5 second
test with offsets  0 to 31 on 4 KB, 64 KB, 256 KB and 2048 KB memory.
(Test 1 starts with first byte in data array and test 2 at the second
byte). The BAT command sequence is:

BUSDOS Secs 5 KB 4 Offset 0
BUSDOS Secs 5 KB 4 Offset 1, N
BUSDOS Secs 5 KB 4 Offset 2, N
.
.
BUSDOS Secs 5 KB 4 Offset 31, N
BUSDOS Secs 5 KB 64 Offset 0, N
BUSDOS Secs 5 KB 64 Offset 1, N
.
.
BUSDOS Secs 5 KB 64 Offset 31, N
BUSDOS Secs 5 KB 256 Offset 0, N
BUSDOS Secs 5 KB 256 Offset 1, N
.
.
BUSDOS Secs 5 KB 256 Offset 31, N

BUSDOS Secs 5 KB 2048 Offset 0, N
BUSDOS Secs 5 KB 2048 Offset 1, N
.
.
BUSDOS Secs 5 KB 2048 Offset 31, N


DOSBAT3 uses 4 byte address increments with the same memory demands 
and offsets 0 to 16, loading data to 1 register. Example commands 
are:


BUSDOS Secs 5, KB 4, Inc 4, Offset 0
BUSDOS Secs 5, KB 4, Inc 4, Offset 1, N
BUSDOS Secs 5, KB 4, Inc 4, Offset 2, N
.
.
BUSDOS Secs 5, KB 2048, Inc 4, Offset 15, N
BUSDOS Secs 5, KB 2048, Inc 4, Offset 16, N


DOSBAT4 runs the same tests as DOSBAT3 but using 2 registers:

BUSDOS Secs 5, KB 4, Inc 4, Reg 2, Offset 0
BUSDOS Secs 5, KB 4, Inc 4, Reg 2, Offset 1, N
BUSDOS Secs 5, KB 4, Inc 4, Reg 2, Offset 2, N
.
.
BUSDOS Secs 5, KB 2048, Inc 4, Reg 2, Offset 15, N
BUSDOS Secs 5, KB 2048, Inc 4, Reg 2, Offset 16, N


The format of the output is as given earlier, for example, on the 
same 200 MHz Pentium MMX as above:

  DWORDS   KB Loops*Loops Reg Inc Off   Secs    MIPS  MB/Sec
                                  set                 4 Byte

    1024    4 1047339   7   1  32   0    5.0   187.7     751
    1024    4 1901140   1   1  32   1    5.0    49.2     197
    1024    4 1893939   1   1  32   2    4.9    49.6     198
    1024    4 1929012   1   1  32   3    5.0    48.9     196
    1024    4 1050420   7   1  32   4    5.0   188.2     753
    1024    4 1937984   1   1  32   5    5.0    49.1     196
    1024    4 1937984   1   1  32   6    5.1    49.0     196
    1024    4 1911314   1   1  32   7    4.9    50.0     200
    1024    4 1047339   7   1  32   8    5.0   188.1     752
   .
   .
   16384   64   31948   1   1  32   0    4.9    13.4      54
   16384   64   27173   1   1  32   1    5.1    11.0      44
   16384   64   27173   1   1  32   2    5.0    11.0      44
   16384   64   27114   1   1  32   3    5.0    11.1      44
   16384   64   32467   1   1  32   4    5.0    13.3      53
   .
   .
  524288 2048     549   1   1  32  24    5.0     7.3      29
  524288 2048     506   1   1  32  25    5.1     6.5      26
  524288 2048     500   1   1  32  26    5.0     6.6      26
  524288 2048     500   1   1  32  27    5.1     6.5      26
  524288 2048     554   1   1  32  28    5.0     7.3      29
  524288 2048     554   1   1  32  29    5.0     7.3      29
  524288 2048     554   1   1  32  30    5.0     7.2      29
  524288 2048     555   1   1  32  31    5.0     7.3      29


The three tests produce the following pattern of results for byte 
offsets of 0 to 16 (I4R1 and I4R2 are for 4 byte address increments 
and 1 or 2 registers. Note that these are from a different run of the
tests to the example above.

Advice to programmers is normally to ensure that data is aligned on a
32 byte boundary (0 in this case) and not 4, 8, 16 bytes. At least 
for these tests, boundary alignment on any 4 byte boundary makes 
little difference.


L1 Cache                 L2 Cache                 RAM
        
Inc32    I4R1    I4R2   Inc32    I4R1    I4R2   Inc32    I4R1    I4R2
MIPS     MIPS    MIPS   MIPS*    MIPS    MIPS   MIPS*    MIPS    MIPS

189.5   196.3   370.2    13.3    59.1    60.1<    7.2    35.2    35.3
 49.1    49.6    65.8    11.0    33.2    38.1     6.6    24.1    26.5
 49.5    49.4    65.6    11.0    33.2    37.9     6.5    24.1    26.4
 48.8    49.6    66.3    11.0    33.2    37.7     6.6    24.1    26.4
189.5   194.7   370.2    13.2    59.2    65.4<    7.3    35.3    35.3
 49.1    49.6    65.6    11.1    33.1    38.1     6.5    24.1    26.5
 49.5    49.6    65.6    11.1    33.1    37.7     6.5    24.1    26.5
 48.8    49.2    65.6    11.1    33.2    37.9     6.5    24.0    26.5
188.2   194.7   370.2    13.3    59.0    59.1<    7.3    35.2    35.2
 49.6    49.6    65.6    11.0    33.2    37.7     6.6    24.1    26.5
 49.5    49.6    65.6    11.0    33.2    37.9     6.5    24.0    26.5
 49.2    49.6    65.8    11.0    33.6    38.1     6.6    24.4    26.5
189.5   194.7   369.4    13.2    59.1    65.7<    7.3    35.3    35.3
 48.9    49.5    65.6     7.3    33.2    38.1     4.4    24.2    26.5
 49.1    49.6    65.8     7.4    33.2    37.9     4.4    24.1    26.6
 48.9    49.2    65.4     7.3    33.2    38.1     4.4    23.9    26.7
189.1   194.7   370.2    13.3    59.2    59.0<    7.3    35.3    35.4

MIPS* multiply by 32 for MB/Sec, others multiply by 4.

L2 and RAM results - MIPS* divide into 66.6 for bus clock cycles per 
32 bytes, others into 533.

      Examples MIPS*     4.4   6.6   7.4  11.0  13.3
      Bus clock cycles   15    10     9     6     5

      Examples other    24.2  26.6  33.3  35.3  38.1  59.1  
      Bus clock cycles   22    20    16    15    14     9


7.  OTHER TESTS

The supplied run time parameters allow various types of test to be 
run, including for stress testing. The following would run for 10
minutes, driving the bus pretty fast, with a constant data pattern:

     BUSDOS Secs 600, KB 64, Pattern FFFFFFFF

A test for a 512 KB cache for half an hour could be carried out with
the following in a BAT file:

     BUSDOS Secs 600, KB 512, Inc 4, Alt A5A5A5A5, Check 1
     BUSDOS Secs 600, KB 512, Inc 4, Alt A5A5A5A5, Check 1, N
     BUSDOS Secs 600, KB 512, Inc 4, Alt A5A5A5A5, Check 1, N


8.  MULTITASKING

The default version does not work with multitasking, second and 
subsequent copies of the program indicating that they cannot open the 
results file. Other programs compiled with an earlier version of the 
Watcom compiler have worked with a common log file when multitasking. 
However, a user defined log file can be used for each task.

Multitasking can be used to run multiple copies of the program via an
Operating system if memory problems are suspected. The following is 
an example BAT file that runs via Windows 95 or NT to test 9 KB of 
memory (use BUSOS2 for OS/2). This uses the default alternating data
pattern and checks the result to see if any bits have been dropped or
gained.

START BUSNT95 Secs 180, KB 4096, Inc 4, Log BusLog1.txt Check 1
START BUSNT95 Secs 180, KB 4096, Inc 4, Log Buslog3.txt Check 1
START BUSNT95 Secs 180, KB 1024, Inc 4, Log BusLog2.txt Check 1

As the program is self calibrating and this process can be upset when
the system is loading other programs, some experimentation is 
required to select suitable running times. These procedures obtained
the following results on a 200 MHz Pentium Pro with NT 4 and a 200 
MHz Pentium MMX with Windows 95, the figures being extracted from 
the three logs produced by each run:

Windows NT

  DWORDS   KB Loops*Loops Reg Inc Off   Secs    MIPS  MB/Sec Check No
                                  set                 4 Byte a5a5a5a5

 1048576 4096    3384   1   1   4   0  173.9    20.4      82  OK A+X
 1048576 4096    3273   1   1   4   0  170.0    20.2      81  OK A+X
  262144 1024   13595   1   1   4   0  172.4    20.7      83  OK A+X

Windows 95

  DWORDS   KB Loops*Loops Reg Inc Off   Secs    MIPS  MB/Sec Check No
                                  set                 4 Byte a5a5a5a5

 1048576 4096    5202   1   1   4   0  317.1    17.2      69  OK A+X
 1048576 4096    2227   1   1   4   0  208.8    11.2      45  OK A+X
  262144 1024    6844   1   1   4   0  171.8    10.4      42  OK A+X

Further experimentation is also required on the amount of memory 
used. With too much memory specified, the procedure will become more
of a disk test, via the paging software.


9. SUBMITTING RESULTS

Results should be sent to Roy_Longbottom@compuserve.com and the 
following  information on the system under test should be included.

               PC Supplier/model 
               CPU chip           
               Clock MHz              (including bus MHz)
               Cache size           
               Chipset & H/W Options  (including RAM type)
               OS/DOS version       
               Run by (name)        
               Company/Location 
               E-Mail address 

The configuration details can be provided via program SYSTEMxx.EXE as 
supplied with the Classic Benchmarks.


