623 строки
15 KiB
C++
623 строки
15 KiB
C++
/* gcc whets.c cpuidc64.o cpuida64.o -m64 -lrt -lc -lm -o whet
|
|
*
|
|
* XXX modified by emscripten to be slower, to not slow down test runner
|
|
*
|
|
* Document: Whets.c
|
|
* File Group: Classic Benchmarks
|
|
* Creation Date: 6 November 1996
|
|
* Revision Date: 6 November 2010 Ubuntu Version for PCs
|
|
*
|
|
* Title: Whetstone Benchmark in C/C++
|
|
* Keywords: WHETSTONE BENCHMARK PERFORMANCE MIPS
|
|
* MWIPS MFLOPS
|
|
*
|
|
* Abstract: C or C++ version of Whetstone one of the
|
|
* Classic Numeric Benchmarks with example
|
|
* results on P3 to P6 based PCs.
|
|
*
|
|
* Contributor: roy@roylongbottom.org.uk
|
|
*
|
|
************************************************************
|
|
*
|
|
* C/C++ Whetstone Benchmark Single or Double Precision
|
|
*
|
|
* Original concept Brian Wichmann NPL 1960's
|
|
* Original author Harold Curnow CCTA 1972
|
|
* Self timing versions Roy Longbottom CCTA 1978/87
|
|
* Optimisation control Bangor University 1987/90
|
|
* C/C++ Version Roy Longbottom 1996
|
|
* Compatibility & timers Al Aburto 1996
|
|
*
|
|
************************************************************
|
|
*
|
|
* Official version approved by:
|
|
*
|
|
* Harold Curnow 100421.1615@compuserve.com
|
|
*
|
|
* Happy 25th birthday Whetstone, 21 November 1997
|
|
*
|
|
************************************************************
|
|
*
|
|
* The program normally runs for about 100 seconds
|
|
* (adjustable in main - variable duration). This time
|
|
* is necessary because of poor PC clock resolution.
|
|
* The original concept included such things as a given
|
|
* number of subroutine calls and divides which may be
|
|
* changed by optimisation. For comparison purposes the
|
|
* compiler and level of optimisation should be identified.
|
|
*
|
|
* This version is set to run for 10 seconds using high
|
|
* resolution timer.
|
|
*
|
|
************************************************************
|
|
*
|
|
* The original benchmark had a single variable I which
|
|
* controlled the running time. Constants with values up
|
|
* to 899 were multiplied by I to control the number
|
|
* passes for each loop. It was found that large values
|
|
* of I could overflow index registers so an extra outer
|
|
* loop with a second variable J was added.
|
|
*
|
|
* Self timing versions were produced during the early
|
|
* days. The 1978 changes supplied timings of individual
|
|
* loops and these were used later to produce MFLOPS and
|
|
* MOPS ratings.
|
|
*
|
|
* 1987 changes converted the benchmark to Fortran 77
|
|
* standards and removed redundant IF statements and
|
|
* loops to leave the 8 active loops N1 to N8. Procedure
|
|
* P3 was changed to use global variables to avoid over-
|
|
* optimisation with the first two statements changed from
|
|
* X1=X and Y1=Y to X=Y and Y=Z. A self time calibrating
|
|
* version for PCs was also produced, the facility being
|
|
* incorporated in this version.
|
|
*
|
|
* This version has changes to avoid worse than expected
|
|
* speed ratings, due to underflow, and facilities to show
|
|
* that consistent numeric output is produced with varying
|
|
* optimisation levels or versions in different languages.
|
|
*
|
|
* Some of the procedures produce ever decreasing numbers.
|
|
* To avoid problems, variables T and T1 have been changed
|
|
* from 0.499975 and 0.50025 to 0.49999975 and 0.50000025.
|
|
*
|
|
* Each section now has its own double loop. Inner loops
|
|
* are run 100 times the loop constants. Calibration
|
|
* determines the number of outer loop passes. The
|
|
* numeric results produced in the main output are for
|
|
* one pass on the outer loop. As underflow problems were
|
|
* still likely on a processor 100 times faster than a 100
|
|
* MHz Pentium, three sections have T=1.0-T inserted in the
|
|
* outer loop to avoid the problem. The two loops avoid
|
|
* index register overflows.
|
|
*
|
|
* The first section is run ten times longer than required
|
|
* for accuracy in calculating MFLOPS. This time is divided
|
|
* by ten for inclusion in the MWIPS calculations.
|
|
*
|
|
* Early version has facilities for typing in details of
|
|
* the particular run, appended to file whets.txt along
|
|
* with the results. This version attemps to obtain these
|
|
* automatically.
|
|
*
|
|
* 2010 Section 4 modified slightly to avoid over optimisation
|
|
* by GCC compiler
|
|
*
|
|
* Roy Longbottom roy@roylongbottom.org.uk
|
|
*
|
|
************************************************************
|
|
*
|
|
* Whetstone benchmark results, further details of the
|
|
* benchmarks and history are available from:
|
|
*
|
|
* http://www.roylongbottom.org.uk/whetstone%20results.htm
|
|
* http://www.roylongbottom.org.uk/whetstone.htm
|
|
*
|
|
************************************************************
|
|
*
|
|
* Source code is available in C/C++, Fortran, Basic and
|
|
* Visual Basic in the same format as this version. Pre-
|
|
* compiled versions for PCs are also available via C++.
|
|
* These comprise optimised and non-optimised versions
|
|
* for DOS, Windows and NT. See:
|
|
*
|
|
* http://www.roylongbottom.org.uk/whetstone%20results.htm
|
|
*
|
|
************************************************************
|
|
*
|
|
* Example of initial calibration display (Pentium 100 MHz)
|
|
*
|
|
* Single Precision C/C++ Whetstone Benchmark
|
|
*
|
|
* Calibrate
|
|
* 0.17 Seconds 1 Passes (x 100)
|
|
* 0.77 Seconds 5 Passes (x 100)
|
|
* 3.70 Seconds 25 Passes (x 100)
|
|
*
|
|
* Use 676 passes (x 100)
|
|
*
|
|
* 676 passes are used for an approximate duration of 100
|
|
* seconds, providing an initial estimate of a speed rating
|
|
* of 67.6 MWIPS.
|
|
*
|
|
* This is followed by the table of results as below.
|
|
|
|
* Whetstone Single Precision Benchmark in C/C++
|
|
*
|
|
* Loop content Result MFLOPS MOPS Seconds
|
|
*
|
|
* N1 floating point -1.12475025653839100 19.971 0.274
|
|
* N2 floating point -1.12274754047393800 11.822 3.240
|
|
* N3 if then else 1.00000000000000000 11.659 2.530
|
|
* N4 fixed point 12.00000000000000000 13.962 6.430
|
|
* N5 sin,cos etc. 0.49904659390449520 2.097 11.310
|
|
* N6 floating point 0.99999988079071040 3.360 45.750
|
|
* N7 assignments 3.00000000000000000 2.415 21.810
|
|
* N8 exp,sqrt etc. 0.75110864639282230 1.206 8.790
|
|
*
|
|
* MWIPS 28.462 100.134
|
|
*
|
|
* Note different numeric results to single precision. Slight variations
|
|
* are normal with different compilers and sometimes optimisation levels.
|
|
*
|
|
**************************************************************************/
|
|
|
|
#define _CRT_SECURE_NO_WARNINGS 1
|
|
#ifdef WIN32
|
|
#include <Windows.h>
|
|
#else
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include <math.h> /* for sin, exp etc. */
|
|
#include <stdio.h> /* standard I/O */
|
|
#include <string.h> /* for strcpy - 3 occurrences */
|
|
#include <stdlib.h> /* for exit - 1 occurrence */
|
|
#include <time.h>
|
|
|
|
/* #include "cpuidh.h" */
|
|
|
|
/*PRECISION PRECISION PRECISION PRECISION PRECISION PRECISION PRECISION*/
|
|
|
|
/* #define DP */
|
|
|
|
#ifdef DP
|
|
#define SPDP double
|
|
#define Precision "Double"
|
|
#else
|
|
#define SPDP float
|
|
#define Precision "Single"
|
|
#endif
|
|
|
|
#define opt "Opt 3 64 Bit"
|
|
|
|
void whetstones(long xtra, long x100, int calibrate);
|
|
void pa(SPDP e[4], SPDP t, SPDP t2);
|
|
void po(SPDP e1[4], long j, long k, long l);
|
|
void p3(SPDP *x, SPDP *y, SPDP *z, SPDP t, SPDP t1, SPDP t2);
|
|
void pout(char title[22], float ops, int type, SPDP checknum,
|
|
SPDP time, int calibrate, int section);
|
|
|
|
|
|
static SPDP loop_time[9];
|
|
static SPDP loop_mops[9];
|
|
static SPDP loop_mflops[9];
|
|
static SPDP TimeUsed;
|
|
static SPDP mwips;
|
|
static char headings[9][18];
|
|
static SPDP Check;
|
|
static SPDP results[9];
|
|
|
|
/* this is truly rank, but it's minimally invasive, and lifted in part from the STREAM scores */
|
|
|
|
static double secs;
|
|
|
|
#ifndef WIN32
|
|
|
|
double mysecond()
|
|
{
|
|
struct timeval tp;
|
|
struct timezone tzp;
|
|
int i;
|
|
|
|
i = gettimeofday(&tp,&tzp);
|
|
return ( (double) tp.tv_sec + (double) tp.tv_usec * 1.e-6 );
|
|
}
|
|
#else
|
|
|
|
double mysecond()
|
|
{
|
|
static LARGE_INTEGER freq = {0};
|
|
LARGE_INTEGER count = {0};
|
|
if(freq.QuadPart == 0LL) {
|
|
QueryPerformanceFrequency(&freq);
|
|
}
|
|
QueryPerformanceCounter(&count);
|
|
return (double)count.QuadPart / (double)freq.QuadPart;
|
|
}
|
|
|
|
#endif
|
|
|
|
void start_time()
|
|
{
|
|
secs = mysecond();
|
|
}
|
|
|
|
void end_time()
|
|
{
|
|
secs = mysecond() - secs;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int count = 1, calibrate = 1;
|
|
long xtra = 1;
|
|
int section;
|
|
long x100 = 1;
|
|
int duration = 1;
|
|
char compiler[80], options[256], general[10][80] = {" "};
|
|
char endit[80];
|
|
int i;
|
|
|
|
printf("\n");
|
|
printf("##########################################\n");
|
|
{
|
|
time_t t;
|
|
char timeday[30];
|
|
t = time(NULL);
|
|
sprintf(timeday, "%s", asctime(localtime(&t)));
|
|
|
|
printf("%s Precision C Whetstone Benchmark %s, %s\n", Precision, opt, timeday);
|
|
}
|
|
|
|
printf("Calibrate\n");
|
|
do
|
|
{
|
|
TimeUsed=0;
|
|
|
|
whetstones(xtra,x100,calibrate);
|
|
|
|
printf("%11.2f Seconds %10.0lf Passes (x 100)\n",
|
|
TimeUsed,(SPDP)(xtra));
|
|
calibrate++;
|
|
count--;
|
|
|
|
if (TimeUsed > 2.0)
|
|
{
|
|
count = 0;
|
|
}
|
|
else
|
|
{
|
|
xtra = xtra * 5;
|
|
}
|
|
}
|
|
|
|
while (count > 0);
|
|
|
|
if (TimeUsed > 0) xtra = (long)((SPDP)(duration * xtra) / TimeUsed);
|
|
if (xtra < 1) xtra = 1;
|
|
|
|
calibrate = 0;
|
|
|
|
printf("\nUse %d passes (x 100)\n", (int)xtra);
|
|
|
|
printf("\n %s Precision C/C++ Whetstone Benchmark",Precision);
|
|
|
|
#ifdef PRECOMP
|
|
printf("\n Compiler %s", precompiler);
|
|
printf("\n Options %s\n", preoptions);
|
|
#else
|
|
printf("\n");
|
|
#endif
|
|
|
|
printf("\nLoop content Result MFLOPS "
|
|
" MOPS Seconds\n\n");
|
|
|
|
TimeUsed=0;
|
|
whetstones(xtra,x100,calibrate);
|
|
|
|
printf("\nMWIPS ");
|
|
if (TimeUsed>0)
|
|
{
|
|
mwips=(float)(xtra) * (float)(x100) / (10 * TimeUsed);
|
|
}
|
|
else
|
|
{
|
|
mwips = 0;
|
|
}
|
|
|
|
printf("%39.3f%19.3f\n\n",mwips,TimeUsed);
|
|
|
|
if (Check == 0) printf("Wrong answer ");
|
|
|
|
printf ("\n");
|
|
printf ("A new results file, whets.txt, will have been created in the same\n");
|
|
printf ("directory as the .EXE files, if one did not already exist.\n\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
void whetstones(long xtra, long x100, int calibrate)
|
|
{
|
|
|
|
long n1,n2,n3,n4,n5,n6,n7,n8,i,ix,n1mult;
|
|
SPDP x,y,z;
|
|
long j,k,l;
|
|
SPDP e1[4];
|
|
|
|
SPDP t = 0.49999975;
|
|
SPDP t0 = t;
|
|
SPDP t1 = 0.50000025;
|
|
SPDP t2 = 2.0;
|
|
|
|
Check=0.0;
|
|
|
|
n1 = 1*x100;
|
|
n2 = 1*x100;
|
|
n3 = 3*x100;
|
|
n4 = 2*x100;
|
|
n5 = 3*x100;
|
|
n6 = 8*x100;
|
|
n7 = 6*x100;
|
|
n8 = 9*x100;
|
|
n1mult = 1;
|
|
|
|
/* Section 1, Array elements */
|
|
|
|
e1[0] = 1.0;
|
|
e1[1] = -1.0;
|
|
e1[2] = -1.0;
|
|
e1[3] = -1.0;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0; i<n1*n1mult; i++)
|
|
{
|
|
e1[0] = (e1[0] + e1[1] + e1[2] - e1[3]) * t;
|
|
e1[1] = (e1[0] + e1[1] - e1[2] + e1[3]) * t;
|
|
e1[2] = (e1[0] - e1[1] + e1[2] + e1[3]) * t;
|
|
e1[3] = (-e1[0] + e1[1] + e1[2] + e1[3]) * t;
|
|
}
|
|
t = 1.0 - t;
|
|
}
|
|
t = t0;
|
|
}
|
|
end_time();
|
|
secs = secs/(SPDP)(n1mult);
|
|
pout("N1 floating point\0",(float)(n1*16)*(float)(xtra),
|
|
1,e1[3],secs,calibrate,1);
|
|
|
|
/* Section 2, Array as parameter */
|
|
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0; i<n2; i++)
|
|
{
|
|
pa(e1,t,t2);
|
|
}
|
|
t = 1.0 - t;
|
|
}
|
|
t = t0;
|
|
}
|
|
end_time();
|
|
pout("N2 floating point\0",(float)(n2*96)*(float)(xtra),
|
|
1,e1[3],secs,calibrate,2);
|
|
|
|
/* Section 3, Conditional jumps */
|
|
j = 1;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0; i<n3; i++)
|
|
{
|
|
if(j==1) j = 2;
|
|
else j = 3;
|
|
if(j>2) j = 0;
|
|
else j = 1;
|
|
if(j<1) j = 1;
|
|
else j = 0;
|
|
}
|
|
}
|
|
}
|
|
end_time();
|
|
pout("N3 if then else \0",(float)(n3*3)*(float)(xtra),
|
|
2,(SPDP)(j),secs,calibrate,3);
|
|
|
|
/* Section 4, Integer arithmetic */
|
|
j = 1;
|
|
k = 2;
|
|
l = 3;
|
|
e1[0] = 0.0;
|
|
e1[1] = 0.0;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0; i<n4; i++)
|
|
{
|
|
j = j *(k-j)*(l-k);
|
|
k = l * k - (l-j) * k;
|
|
l = (l-k) * (k+j);
|
|
e1[l-2] = e1[l-2] + j + k + l;
|
|
e1[k-2] = e1[k-2] + j * k * l;
|
|
// was e1[l-2] = j + k + l; and e1[k-2] = j * k * l;
|
|
}
|
|
}
|
|
}
|
|
end_time();
|
|
x = (e1[0]+e1[1])/(SPDP)n4/(SPDP)xtra; // was x = e1[0]+e1[1];
|
|
pout("N4 fixed point \0",(float)(n4*15)*(float)(xtra),
|
|
2,x,secs,calibrate,4);
|
|
|
|
/* Section 5, Trig functions */
|
|
x = 0.5;
|
|
y = 0.5;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=1; i<n5; i++)
|
|
{
|
|
x = t*atan(t2*sin(x)*cos(x)/(cos(x+y)+cos(x-y)-1.0));
|
|
y = t*atan(t2*sin(y)*cos(y)/(cos(x+y)+cos(x-y)-1.0));
|
|
}
|
|
t = 1.0 - t;
|
|
}
|
|
t = t0;
|
|
}
|
|
end_time();
|
|
pout("N5 sin,cos etc. \0",(float)(n5*26)*(float)(xtra),
|
|
2,y,secs,calibrate,5);
|
|
|
|
|
|
/* Section 6, Procedure calls */
|
|
x = 1.0;
|
|
|
|
y = 1.0;
|
|
z = 1.0;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0; i<n6; i++)
|
|
{
|
|
p3(&x,&y,&z,t,t1,t2);
|
|
}
|
|
}
|
|
}
|
|
end_time();
|
|
pout("N6 floating point\0",(float)(n6*6)*(float)(xtra),
|
|
1,z,secs,calibrate,6);
|
|
|
|
/* Section 7, Array refrences */
|
|
j = 0;
|
|
k = 1;
|
|
l = 2;
|
|
e1[0] = 1.0;
|
|
e1[1] = 2.0;
|
|
e1[2] = 3.0;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0;i<n7;i++)
|
|
{
|
|
po(e1,j,k,l);
|
|
}
|
|
}
|
|
}
|
|
end_time();
|
|
pout("N7 assignments \0",(float)(n7*3)*(float)(xtra),
|
|
2,e1[2],secs,calibrate,7);
|
|
|
|
/* Section 8, Standard functions */
|
|
x = 0.75;
|
|
start_time();
|
|
{
|
|
for (ix=0; ix<xtra; ix++)
|
|
{
|
|
for(i=0; i<n8; i++)
|
|
{
|
|
x = sqrt(exp(log(x)/t1));
|
|
}
|
|
}
|
|
}
|
|
end_time();
|
|
pout("N8 exp,sqrt etc. \0",(float)(n8*4)*(float)(xtra),
|
|
2,x,secs,calibrate,8);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void pa(SPDP e[4], SPDP t, SPDP t2)
|
|
{
|
|
long j;
|
|
for(j=0;j<6;j++)
|
|
{
|
|
e[0] = (e[0]+e[1]+e[2]-e[3])*t;
|
|
e[1] = (e[0]+e[1]-e[2]+e[3])*t;
|
|
e[2] = (e[0]-e[1]+e[2]+e[3])*t;
|
|
e[3] = (-e[0]+e[1]+e[2]+e[3])/t2;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void po(SPDP e1[4], long j, long k, long l)
|
|
{
|
|
e1[j] = e1[k];
|
|
e1[k] = e1[l];
|
|
e1[l] = e1[j];
|
|
return;
|
|
}
|
|
|
|
void p3(SPDP *x, SPDP *y, SPDP *z, SPDP t, SPDP t1, SPDP t2)
|
|
{
|
|
*x = *y;
|
|
*y = *z;
|
|
*x = t * (*x + *y);
|
|
*y = t1 * (*x + *y);
|
|
*z = (*x + *y)/t2;
|
|
return;
|
|
}
|
|
|
|
|
|
void pout(char title[18], float ops, int type, SPDP checknum,
|
|
SPDP time, int calibrate, int section)
|
|
{
|
|
SPDP mops,mflops;
|
|
|
|
Check = Check + checknum;
|
|
loop_time[section] = time;
|
|
strcpy (headings[section],title);
|
|
TimeUsed = TimeUsed + time;
|
|
if (calibrate == 1)
|
|
|
|
{
|
|
results[section] = checknum;
|
|
}
|
|
if (calibrate == 0)
|
|
{
|
|
printf("%s %24.17f ",headings[section],results[section]);
|
|
|
|
if (type == 1)
|
|
{
|
|
if (time>0)
|
|
{
|
|
mflops = ops/(1000000L*time);
|
|
}
|
|
else
|
|
{
|
|
mflops = 0;
|
|
}
|
|
loop_mops[section] = 99999;
|
|
loop_mflops[section] = mflops;
|
|
printf(" %9.3f %9.3f\n",
|
|
loop_mflops[section], loop_time[section]);
|
|
}
|
|
else
|
|
{
|
|
if (time>0)
|
|
{
|
|
mops = ops/(1000000L*time);
|
|
}
|
|
else
|
|
{
|
|
mops = 0;
|
|
}
|
|
loop_mops[section] = mops;
|
|
loop_mflops[section] = 0;
|
|
printf(" %9.3f%9.3f\n",
|
|
loop_mops[section], loop_time[section]);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|