boinc/client/whetstone.cpp

296 lines
6.3 KiB
C++

/*
* 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
*/
// Modified a little to work with BOINC
//
#include "cpp.h"
#ifdef _WIN32
#include "boinc_win.h"
#else
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <time.h>
#endif
#include "util.h"
#include "cpu_benchmark.h"
#ifndef SPDP
#define SPDP double
#endif
#ifdef ANDROID
#ifdef ANDROID_NEON
namespace android_neon {
#else
#ifdef ANDROID_VFP
namespace android_vfp {
#endif
#endif
#endif
// External array; store results here so that optimizing compilers
// don't do away with their computation.
// suggested by Ben Herndon
//
double extern_array[12];
// #pragma intrinsic (sin, cos, tan, atan, sqrt, exp, log)
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;
}
// return an error if CPU time is less than min_cpu_time
//
int whetstone(double& flops, double& cpu_time, double min_cpu_time) {
long n1,n2,n3,n4,n5,n6,n7,n8,i,ix,n1mult;
SPDP x,y,z;
long j,k,l, jjj;
SPDP e1[4];
double startsec = 0.0, finisec = 0.0;
double KIPS;
int xtra, ii;
int x100 = 1000; // chosen to make each pass take about 0.1 sec
// on my current computer (2.2 GHz celeron)
// This must be small enough that one loop finishes
// in 10 sec on the slowest CPU
extern_array[11] = 1;
benchmark_wait_to_start(BM_TYPE_FP);
boinc_calling_thread_cpu_time(startsec);
SPDP t = 0.49999975;
SPDP t0 = t;
SPDP t1 = 0.50000025;
SPDP t2 = 2.0;
n1 = 12*x100;
n2 = 14*x100;
n3 = 345*x100;
n4 = 210*x100;
n5 = 32*x100;
n6 = 899*x100;
n7 = 616*x100;
n8 = 93*x100;
xtra = 1;
n1mult = 10;
ii = 0;
do {
/* Section 1, Array elements */
e1[0] = 1.0;
e1[1] = -1.0;
e1[2] = -1.0;
e1[3] = -1.0;
{
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;
}
extern_array[0] = e1[0];
extern_array[1] = e1[1];
extern_array[2] = e1[2];
extern_array[3] = e1[3];
/* Section 2, Array as parameter */
{
for (ix=0; ix<xtra; ix++)
{
for(i=0; i<n2; i++)
{
pa(e1,t,t2);
}
t = 1.0 - t;
}
t = t0;
}
extern_array[4] = e1[0];
/* Section 3, Conditional jumps */
jjj = (long) extern_array[11];
j = k = jjj;
{
for (ix=0; ix<xtra; ix++) {
for(i=0; i<n3; i++) {
if(j==1) l = jjj;
else l = k;
if(k>2) j = jjj;
else j = 1;
if(l<1) k = 1;
else k = jjj;
}
}
}
extern_array[5] = (double)j;
/* Section 4, Integer arithmetic */
j = long(e1[0]);
k = 2;
l = 3;
{
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&3] = j + k + l;
e1[k&3] = j * k * l;
}
}
}
extern_array[6] = e1[0];
/* Section 5, Trig functions */
x = 0.5;
y = 0.5;
{
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;
}
extern_array[7] = x;
/* Section 6, Procedure calls */
x = 1.0;
y = 1.0;
z = 1.0;
{
for (ix=0; ix<xtra; ix++)
{
for(i=0; i<n6; i++)
{
p3(&x,&y,&z,t,t1,t2);
}
}
}
extern_array[8] = x;
/* Section 7, Array references */
j = 0;
k = 1;
l = 2;
e1[0] = 1.0;
e1[1] = 2.0;
e1[2] = 3.0;
{
for (ix=0; ix<xtra; ix++)
{
for(i=0;i<n7;i++)
{
po(e1,j,k,l);
}
}
}
extern_array[9] = e1[0];
/* Section 8, Standard functions */
x = 0.75;
for (ix=0; ix<xtra; ix++) {
for(i=0; i<n8; i++) {
x = sqrt(exp(log(x)/t1));
}
}
extern_array[10] = x;
ii++;
}
while (!benchmark_time_to_stop(BM_TYPE_FP));
boinc_calling_thread_cpu_time(finisec);
double diff = finisec - startsec;
cpu_time = diff;
if (diff < min_cpu_time) {
return -1;
}
KIPS = (100.0*x100*ii)/diff;
#if 0
if (KIPS >= 1000.0)
printf("C Converted Double Precision Whetstones: %.1f MIPS\n", KIPS/1000.0);
else
printf("C Converted Double Precision Whetstones: %.1f KIPS\n", KIPS);
#endif
// convert from thousands of instructions a second to instructions a second.
flops = KIPS*1000.0;
return 0;
}
#if defined(ANDROID_NEON) || defined(ANDROID_VFP)
}
#endif // namespace closure