// ============================================================================================= // Utility functions for Chapel implementation of the STREAM benchmark. // // 1) InitializeArrays : pretty simple now, but may become more involved. // 2) ReportHeader : write header data to stdout. // 3) CheckAnswer : attempt to verify correctness of timed operations. // 4) ReportResults : write specified test results to stdout. // 5) ReportFooter : write footer to stdout. // 6) SeparatorLine : formatting convenience. // ============================================================================================= use stream_params; // ============================================================================================= def InitializeArrays ( B, C ) { forall i in ArrayShape do { B(i) = initBval; C(i) = initCval; } if ( Debug ) { writeln ( " B = [", B, "]" ); writeln ( ); writeln ( " C = [", C, "]" ); } } // ============================================================================================= def ReportHeader ( ) { writeln ( ); SeparatorLine ( ); writeln ( ); writeln ( " STREAM benchmark testing. " ); writeln ( ); writeln ( " Chapel programming language, data parallel model. " ); writeln ( ); writeln ( " Test details: " ); writeln ( ); writeln ( " Number of threads : ", NumThreads ); writeln ( ); writeln ( " Datatype : ", Datatype ); writeln ( " Bytes per array element : ", numBytes ( elemType ) ); writeln ( " Array dimension : ", N, "." ); writeln ( " Total memory requirement : ", 3 * N * numBytes ( elemType ) / GIGABYTE, " GBytes." ); writeln ( ); writeln ( " Number of iterations : ", NumIter ); } // ======================================== Verify results ===================================== def CheckAnswer ( test, A, B, C ) { select ( test ) { when "COPY" do { const infNormA = max reduce [ i in ArrayShape ] abs ( A ( i ) ); const infNormB = max reduce [ i in ArrayShape ] abs ( B ( i ) ); return ( infNormA - infNormB <= Tolerance ); } when "SCALE" do { const infNorm = max reduce [ i in ArrayShape ] abs ( A ( i ) - ( alpha * B ( i ) ) ); return ( infNorm <= Tolerance ); } when "<<" do { writeln ( " Gotta write a checker for shift." ); return ( true ); } when "SUM" do { const infNorm = max reduce [ i in ArrayShape ] abs ( A ( i ) - ( B ( i ) + C ( i ) ) ); return ( infNorm <= Tolerance ); } when "TRIAD" do { const infNorm = max reduce [ i in ArrayShape ] abs ( A ( i ) - ( B ( i ) + alpha * C ( i ) ) ); return ( infNorm <= Tolerance ); } } // End select ( test ). writeln ( " Unknown test. \n " ); return ( false ); // If we get this far, its a bug. } // ======================================== Print results ====================================== def ReportResults ( test, ierr, TimeWall ) { // Time stats: const TimeTotal = + reduce TimeWall; const TimeMean = TimeTotal / NumIter; const TimeMax = max reduce TimeWall; const TimeMin = min reduce TimeWall; const TimeSquareOfTheSum = TimeTotal**2; var TimeSumOfTheSquares = 0.0; for i in 1..NumIter do { TimeSumOfTheSquares += TimeWall ( i )**2; } var TimeDiffSquared = 0.0; for i in 1..NumIter do { TimeDiffSquared += ( TimeWall ( i ) - TimeMean )**2; } // const TimeStdDev = sqrt ( TimeSumOfTheSquares - TimeSquareOfTheSum ); const TimeStdDev = sqrt ( TimeDiffSquared / NumIter ); // Determine volume of data. var NumVectors = -1; select ( test ) { when "COPY" do { NumVectors = 2; } when "SCALE" do { NumVectors = 2; } when "<<" do { NumVectors = 2; } when "SUM" do { NumVectors = 2; } when "TRIAD" do { NumVectors = 3; } } // End select ( test ). // Performance stats (bandwidth): const PerfMax = NumVectors * numBytes ( elemType ) * ( N / TimeMin ) / GIGABYTE; const PerfMin = NumVectors * numBytes ( elemType ) * ( N / TimeMax ) / GIGABYTE; const PerfMean = NumVectors * numBytes ( elemType ) * ( N / TimeMean ) / GIGABYTE; const PerfStdDev = TimeStdDev * PerfMean; writeln ( ); SeparatorLine ( ); writeln ( ); writeln ( " ", test, " results :" ); writeln ( ); if ierr then { if ( NumThreads == 1 ) { writeln ( " [1 thread] Test passed." ); } else { writeln ( " [", NumThreads, " threads] Test passed." ); } } else { if ( NumThreads == 1 ) { writeln ( " [1 thread] Test failed." ); } else { writeln ( " [", NumThreads, " threads] Test failed." ); } } writeln ( ); writeln ( " Execution statistics (per iteration): " ); writeln ( ); writeln ( " Time (secs): ( Min, Mean, Max ) = (", TimeMin, ", ", TimeMean, ", ", TimeMax, ")" ); writeln ( ); writeln ( " StdDev = ", TimeStdDev, " Total : ", TimeTotal ); writeln ( ); writeln ( " Performance: GB/sec ( Min, Mean, Max ) = (", PerfMin, ", ", PerfMean, ", ", PerfMax, ")" ); writeln ( ); writeln ( " StdDev = ", PerfStdDev ); writeln ( ); writeln ( " STREAM ", test, " number is ", PerfMax, " GBytes/sec." ); writeln ( ); return ( PerfMax ); } // ============================================================================================= def ReportFooter ( Answers, Perf ) { SeparatorLine ( ); writeln ( ); var NumFailed = 0; for i in 1..NumTests { if ( Answers ( i ) == false ) { NumFailed = NumFailed + 1; writeln ( " ** Test ", i, " failed. " ); } } if ( NumFailed == 0 ) { writeln ( " All tests passed." ); writeln ( ); } // Write stream performance in column format for easy paste into Excel or other. SeparatorLine ( ); writeln ( " Stream performance numbers : " ); writeln ( ); for i in 1..NumTests { writeln ( Perf ( i ) ); } writeln ( ); writeln ( " End STREAM test." ); SeparatorLine ( ); writeln ( ); } // ============================================================================================= def SeparatorLine ( ) { writeln ( " =================================================================================== " ); } // End utils.chpl. // =============================================================================================