Skip to content

Commit

Permalink
Many code style fixes (most often the mixing of C- and C++-style prin…
Browse files Browse the repository at this point in the history
…touts), fix missing dense decriptors, fix error detection logic, add more clarifying comments, improve output printouts, lower auto-detected number of inner repetitions from matching 1 second to 100 milliseconds, fix initialisation error detection (posix_memalign return codes may not be checked previously)
  • Loading branch information
anyzelman committed Jan 11, 2025
1 parent 6d75e2f commit bbdaab9
Showing 1 changed file with 93 additions and 59 deletions.
152 changes: 93 additions & 59 deletions tests/performance/dot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* limitations under the License.
*/

#include <cstdio>
#include <cstdlib>

#include <assert.h>
Expand Down Expand Up @@ -115,32 +114,34 @@ void functional_test( const struct test_input &in, struct test_output &out ) {
const RC rc = grb::dot( alpha, xv, yv, reals );
out.time = timer.time();
if( rc != SUCCESS ) {
(void) fprintf( stderr, "Call to grb::dot failed with exit code %d.\n",
(int)rc );
std::cerr << "Call to grb::dot failed with error " << grb::toString( rc )
<< std::endl;
out.error_code = 200;
}

// compiler result
double beta = 0.0;
for( size_t i = 0; i < n; ++i ) {
beta += xr[ i ] * yr[ i ];
}
if( out.error_code ) {
// compiler result
double beta = 0.0;
for( size_t i = 0; i < n; ++i ) {
beta += xr[ i ] * yr[ i ];
}

// now check result
if( ! grb::utils::equals( check, alpha, 2 * n ) ) {
(void) printf( "%lf (templated) does not equal %lf (sequential).\n", alpha,
check );
out.error_code = 300;
}
if( ! grb::utils::equals( check, beta, 2 * n ) ) {
(void) printf( "%lf (compiler) does not equal %lf (sequential).\n", beta,
check );
out.error_code = 301;
}
if( ! grb::utils::equals( alpha, beta, 2 * n ) ) {
(void) printf( "%lf (templated) does not equal %lf (compiler).\n", alpha,
beta );
out.error_code = 302;
// now check result
if( !grb::utils::equals( check, alpha, 2 * n ) ) {
std::cerr << "Checksum error (alpha): " << alpha << " does not equal "
<< check << std::endl;
out.error_code = 300;
}
if( !grb::utils::equals( check, beta, 2 * n ) ) {
std::cerr << "Checksum error (beta): " << beta << " does not equal "
<< check << std::endl;
out.error_code = 301;
}
if( !grb::utils::equals( alpha, beta, 2 * n ) ) {
std::cerr << "Checksum error (cross-check): " << alpha << " does not equal "
<< beta << std::endl;
out.error_code = 302;
}
}

// free memory
Expand All @@ -157,7 +158,7 @@ void bench_templated( const struct bench_input &in, struct bench_output &out ) {

// declare graphBLAS data structures
typedef grb::Vector< double > vector;
const size_t & n = in.n;
const size_t &n = in.n;
vector xv( n ), yv( n );

// set input
Expand All @@ -167,18 +168,24 @@ void bench_templated( const struct bench_input &in, struct bench_output &out ) {
if( grb::set< grb::descriptors::use_index >( xv, 0 ) != grb::SUCCESS ) {
out.error_code = 103;
}
if( out.error_code ) {
out.times.preamble = timer.time();
return;
}

// first do a cold run
typename grb::Semiring<
grb::operators::add< double >, grb::operators::mul< double >,
grb::identities::zero, grb::identities::one
> reals;
double alpha = 0.0;
const enum RC rc = grb::dot( alpha, xv, yv, reals );
const enum RC rc = grb::dot< grb::descriptors::dense >( alpha, xv, yv, reals );
if( rc != SUCCESS ) {
(void) fprintf( stderr, "Call to grb::dot failed with exit code %d.\n",
(int)rc );
std::cerr << "Call to grb::dot failed with error " << grb::toString( rc )
<< std::endl;
out.error_code = 201;
out.times.preamble = timer.time();
return;
}

// done with preamble, start useful work
Expand All @@ -190,19 +197,26 @@ void bench_templated( const struct bench_input &in, struct bench_output &out ) {
for( size_t i = 0; i < in.rep; ++i ) {
timer.reset();
alpha = 0.0;
const enum RC grc = grb::dot( alpha, xv, yv, reals );
const enum RC grc = grb::dot< grb::descriptors::dense >( alpha, xv, yv,
reals );
ttime += timer.time() / static_cast< double >( in.rep );

// sanity checks
bool sane = true;
if( !grb::utils::equals( in.check, alpha, 2 * n ) ) {
(void) printf( "%lf (templated, re-entrant) does not equal %lf "
"(sequential).\n", alpha, in.check );
std::cerr << "Checksum error (templated, re-entrant, alpha): " << alpha
<< " does not equal " << in.check << " (sequentia)." << std::endl;
out.error_code = 304;
sane = false;
}
if( grc != SUCCESS ) {
(void) printf( "Call to grb::dot failed (re-entrant) with exit code %d.\n",
(int)grc );
std::cerr << "Call to grb::dot(re-entrant) FAILED with error "
<< grb::toString( grc ) << std::endl;
out.error_code = 202;
sane = false;
}
if( !sane ) {
break;
}
}

Expand All @@ -224,9 +238,15 @@ void bench_lambda( const struct bench_input &in, struct bench_output &out ) {
// set input
if( grb::set< grb::descriptors::no_operation >( yv, 0.5 ) != grb::SUCCESS ) {
out.error_code = 104;
return;
}
if( grb::set< grb::descriptors::use_index >( xv, 0 ) != grb::SUCCESS ) {
out.error_code = 105;
return;
}
if( out.error_code ) {
out.times.preamble = timer.time();
return;
}

// first do a cold run
Expand All @@ -235,7 +255,7 @@ void bench_lambda( const struct bench_input &in, struct bench_output &out ) {
grb::identities::zero, grb::identities::one
> reals;
double alpha = reals.template getZero< double >();
const RC rc = grb::eWiseLambda(
const RC rc = grb::eWiseLambda< grb::descriptors::dense >(
[ &xv, &yv, &alpha, &reals ]( const size_t i ) {
double temp = 0.0;
const auto mul_op = reals.getMultiplicativeOperator();
Expand All @@ -246,9 +266,11 @@ void bench_lambda( const struct bench_input &in, struct bench_output &out ) {
xv
);
if( rc != SUCCESS ) {
(void) fprintf( stderr, "Error in call to grb::eWiseLambda, non-SUCCESS "
"return code %d.\n", (int)rc );
std::cerr << "Error during call to grb::eWiseLambda, error: "
<< grb::toString( rc ) << std::endl;
out.times.preamble = timer.time();
out.error_code = 203;
return;
}

// done with preamble, start useful work
Expand All @@ -271,24 +293,28 @@ void bench_lambda( const struct bench_input &in, struct bench_output &out ) {
// grb::foldl< grb::operators::add< double > >( alpha, temp ); // fast as the below two lines
(void) grb::foldl( temp, yv[ i ], mul_op ); // note: these two lines are about equally
(void) grb::foldl( alpha, temp, add_op ); // fast as the below one. This is the
// recommended GraphBLAS call. The
// performance difference vs grb::dot
// is due to vectorisation.
// alpha += xv[ i ] * yv[ i ];
// recommended ALP-style call.
// alpha += xv[ i ] * yv[ i ]; // note: this line is about equally fast as the above two
},
xv
);
ltime += timer.time() / static_cast< double >( in.rep );

bool sane = true;
if( !grb::utils::equals( in.check, alpha, 2 * n ) ) {
(void) printf( "%lf (eWiseLambda, re-entrant) does not equal %lf "
"(sequential).\n", alpha, in.check );
std::cerr << "Checksum error (eWiseLambda, re-entrant): " << alpha
<< " does not equal " << in.check << " (sequential)." << std::endl;
out.error_code = 305;
sane = false;
}
if( grc != SUCCESS ) {
(void) printf( "Call to grb::eWiseLambda failed (re-entrant) with exit code "
"%d.\n", (int)grc );
std::cerr << "Call to grb::eWiseLambda failed (re-entrant) with error "
<< grb::toString( grc ) << std::endl;
out.error_code = 204;
sane = false;
}
if( !sane ) {
break;
}
}

Expand All @@ -311,20 +337,20 @@ void bench_raw( const struct bench_input &in, struct bench_output &out ) {
grb::config::CACHE_LINE_SIZE::value(),
n * sizeof( double )
);
assert( prc == 0 );
prc = posix_memalign(
prc = prc ? prc : posix_memalign(
(void **)&yr,
grb::config::CACHE_LINE_SIZE::value(),
n * sizeof( double )
);
assert( prc == 0 );
#ifdef NDEBUG
(void) prc;
#endif
if( prc != 0 ) {
std::cerr << "Error initialising test (I)" << std::endl;
out.error_code = 106;
return;
}

// set input
for( size_t i = 0; i < n; ++i ) {
xr[ i ] = (double)i;
xr[ i ] = static_cast< double >( i );
yr[ i ] = 0.5;
}

Expand All @@ -343,10 +369,11 @@ void bench_raw( const struct bench_input &in, struct bench_output &out ) {
bench_kernels_dot( &alpha, xr, yr, n );
ctime += timer.time() / static_cast< double >( in.rep );

if( ! grb::utils::equals( in.check, alpha, 2 * n ) ) {
(void) printf( "%lf (compiler, re-entrant) does not equal %lf "
"(sequential).\n", alpha, in.check );
if( !grb::utils::equals( in.check, alpha, 2 * n ) ) {
std::cerr << "Checksum error (compiler, re-entrant): " << alpha
<< " does not equal " << in.check << " (sequential).\n";
out.error_code = 306;
break;
}
}

Expand Down Expand Up @@ -428,10 +455,11 @@ int main( int argc, char ** argv ) {
// set remaining input fields for benchmarks
in.check = test_out.check; // pass through checksum value to benchmarks
if( in.rep == 0 ) {
in.rep = static_cast< size_t >( 1000.0 / test_out.time ) + 1;
in.rep = static_cast< size_t >( 100.0 / test_out.time ) + 1;
std::cout << "Auto-selected number of inner repetitions is " << in.rep
<< " (at an estimated time of " << test_out.time
<< " ms. of useful work per benchmark).\n";
<< " ms. of useful work per benchmark, making for approximately 100 ms. "
<< "inner experiment time).\n";
}

// start benchmark test 1
Expand All @@ -448,7 +476,9 @@ int main( int argc, char ** argv ) {
}

// start benchmark test 2
std::cout << "\nBenchmark label: grb::dot of size " << in.n << std::endl;
std::cout << "\nBenchmark label: grb::dot ("
<< grb::toString( grb::config::default_backend ) << ") of size " << in.n
<< std::endl;
if( bench.exec( &bench_templated, in, out, 1, outer, true ) != SUCCESS ) {
std::cerr << "Error launching templated benchmark test.\n Test FAILED."
<< std::endl;
Expand All @@ -462,7 +492,8 @@ int main( int argc, char ** argv ) {

// start benchmark test 3
if( grb::Properties<>::writableCaptured ) {
std::cout << "\nBenchmark label: grb::eWiseLambda (dot) of size " << in.n
std::cout << "\nBenchmark label: grb::eWiseLambda (dot, "
<< grb::toString( grb::config::default_backend ) << ") of size " << in.n
<< std::endl;
if( bench.exec( &bench_lambda, in, out, 1, outer, true ) != SUCCESS ) {
std::cerr << "Error launching lambda benchmark test.\nTest FAILED."
Expand All @@ -476,11 +507,14 @@ int main( int argc, char ** argv ) {
}
} else {
std::cout << "\nBackend does not support writing to captured scalars, "
<< "skipping benchmark of lambda-based dot product...\n\n";
<< "skipping benchmark of lambda-based dot product.\n";
}

std::cout << "\nNOTE: please check the above performance figures manually-- the "
"timings should approximately match.\n\n";

// done
std::cout << "Test OK.\n\n";
std::cout << "Test OK\n\n";
return EXIT_SUCCESS;
}

0 comments on commit bbdaab9

Please sign in to comment.