blob: 90f7e87e6402d64b31139783022ebc30404edd85 [file] [log] [blame]
// Copyright 2013 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
/* 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(const 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(const 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;
}