137 lines
4.3 KiB
C++
137 lines
4.3 KiB
C++
// Copyright (c) 2013, Peter Pettersson
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
// list of conditions and the following disclaimer.
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// The views and conclusions contained in the software and documentation are those
|
|
// of the authors and should not be interpreted as representing official policies,
|
|
// either expressed or implied, of the FreeBSD Project.
|
|
|
|
#include "Timer.h"
|
|
#include "RandomWELL512a.h"
|
|
#include "RandomWELL512a_SSE2.h"
|
|
#include "WELL512a.h"
|
|
#include <string.h> // Needed for memcmp().
|
|
|
|
void Benchmark()
|
|
{
|
|
const unsigned kSeed = 123;
|
|
const unsigned kNumLoops = 5;
|
|
const unsigned kNumIterations = 40000000;
|
|
double *result0 = new double [kNumIterations];
|
|
double *result1 = new double [kNumIterations];
|
|
double *result2 = new double [kNumIterations];
|
|
double *result3 = new double [kNumIterations];
|
|
|
|
srand(kSeed);
|
|
unsigned seed[16];
|
|
for (unsigned i = 0; i < 16; ++i)
|
|
seed[i] = rand();
|
|
|
|
for (unsigned loop = 0; loop < kNumLoops; ++loop)
|
|
{
|
|
// RAND implementation.
|
|
srand(kSeed);
|
|
Timer timer0;
|
|
for (unsigned i = 0; i < kNumIterations; ++i)
|
|
result0[0] = rand() / (double)RAND_MAX;
|
|
timer0.Report("Rand(): ");
|
|
|
|
// WELL512 C++ implementation.
|
|
RandomWELL512a random(kSeed);
|
|
Timer timer1;
|
|
for (unsigned i = 0; i < kNumIterations; ++i)
|
|
result1[i] = random.GetDouble();
|
|
timer1.Report("WELL512 C++: ");
|
|
|
|
// WELL512 SSE2 implementation.
|
|
RandomWELL512a_SSE2 randomSSE2(kSeed);
|
|
Timer timer2;
|
|
for (unsigned i = 0; i < kNumIterations; i += 4)
|
|
randomSSE2.GetDouble4(result2 + i);
|
|
timer2.Report("WELL512 SSE2: ");
|
|
|
|
// WELL512 C implementation.
|
|
InitWELLRNG512a(seed);
|
|
Timer timer3;
|
|
for (unsigned i = 0; i < kNumIterations; ++i)
|
|
result3[i] = WELLRNG512a();
|
|
timer3.Report("WELL512 C: ");
|
|
|
|
std::cout << "---" << std::endl;
|
|
}
|
|
|
|
delete [] result0;
|
|
delete [] result1;
|
|
delete [] result2;
|
|
delete [] result3;
|
|
}
|
|
|
|
// Verify that the SIMD implementation returns the same values as the original
|
|
// algorithm would.
|
|
void Test()
|
|
{
|
|
const int kSeed = 123;
|
|
const unsigned kNumIterations = 4 * 1024;
|
|
|
|
double *result0 = new double [kNumIterations];
|
|
double *result1 = new double [kNumIterations];
|
|
|
|
srand(kSeed);
|
|
unsigned seed[4 * 16];
|
|
for (unsigned i = 0; i < 4 * 16; ++i)
|
|
seed[i] = rand();
|
|
RandomWELL512a randomWell0(seed + 0 * 16);
|
|
RandomWELL512a randomWell1(seed + 1 * 16);
|
|
RandomWELL512a randomWell2(seed + 2 * 16);
|
|
RandomWELL512a randomWell3(seed + 3 * 16);
|
|
|
|
RandomWELL512a_SSE2 randomWellSSE2(seed);
|
|
|
|
for (unsigned i = 0; i < kNumIterations; i += 4)
|
|
{
|
|
result0[i + 0] = randomWell0.GetDouble();
|
|
result0[i + 1] = randomWell1.GetDouble();
|
|
result0[i + 2] = randomWell2.GetDouble();
|
|
result0[i + 3] = randomWell3.GetDouble();
|
|
|
|
result1[i + 0] = randomWellSSE2.GetDouble();
|
|
result1[i + 1] = randomWellSSE2.GetDouble();
|
|
result1[i + 2] = randomWellSSE2.GetDouble();
|
|
result1[i + 3] = randomWellSSE2.GetDouble();
|
|
}
|
|
|
|
if (memcmp(result0, result1, kNumIterations * sizeof(double)))
|
|
std::cout << "ERROR: C++ vs SSE2: The results don't match!" << std::endl;
|
|
else
|
|
std::cout << "C++ vs SSE2: Results match" << std::endl;
|
|
|
|
delete [] result0;
|
|
delete [] result1;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
Benchmark();
|
|
Test();
|
|
return 0;
|
|
}
|