|
PAPI
5.0.1.0
|
00001 /* 00002 Calibrate.c 00003 A program to perform one or all of three tests to count flops. 00004 Test 1. Inner Product: 2*n operations 00005 for i = 1:n; a = a + x(i)*y(i); end 00006 Test 2. Matrix Vector Product: 2*n^2 operations 00007 for i = 1:n; for j = 1:n; x(i) = x(i) + a(i,j)*y(j); end; end; 00008 Test 3. Matrix Matrix Multiply: 2*n^3 operations 00009 for i = 1:n; for j = 1:n; for k = 1:n; c(i,j) = c(i,j) + a(i,k)*b(k,j); end; end; end; 00010 00011 Supply a command line argument of 1, 2, or 3 to perform each test, or 00012 no argument to perform all three. 00013 00014 Each test initializes PAPI and presents a header with processor information. 00015 Then it performs 500 iterations, printing result lines containing: 00016 n, measured counts, theoretical counts, (measured - theory), % error 00017 */ 00018 00019 #include "papi_test.h" 00020 00021 static void resultline( int i, int j, int EventSet, int fail ); 00022 static void headerlines( char *title, int TESTS_QUIET ); 00023 00024 #define INDEX1 100 00025 #define INDEX5 500 00026 00027 #define MAX_WARN 10 00028 #define MAX_ERROR 80 00029 #define MAX_DIFF 14 00030 00031 extern int TESTS_QUIET; 00032 00033 static void 00034 print_help( char **argv ) 00035 { 00036 printf( "Usage: %s [-ivmdh] [-e event]\n", argv[0] ); 00037 printf( "Options:\n\n" ); 00038 printf( "\t-i Inner Product test.\n" ); 00039 printf( "\t-v Matrix-Vector multiply test.\n" ); 00040 printf( "\t-m Matrix-Matrix multiply test.\n" ); 00041 printf( "\t-d Double precision data. Default is float.\n" ); 00042 printf 00043 ( "\t-e event Use <event> as PAPI event instead of PAPI_FP_OPS\n" ); 00044 printf( "\t-f Suppress failures\n" ); 00045 printf( "\t-h Print this help message\n" ); 00046 printf( "\n" ); 00047 printf 00048 ( "This test measures floating point operations for the specified test.\n" ); 00049 printf( "Operations can be performed in single or double precision.\n" ); 00050 printf( "Default operation is all three tests in single precision.\n" ); 00051 } 00052 00053 static float 00054 inner_single( int n, float *x, float *y ) 00055 { 00056 float aa = 0.0; 00057 int i; 00058 00059 for ( i = 0; i <= n; i++ ) 00060 aa = aa + x[i] * y[i]; 00061 return ( aa ); 00062 } 00063 00064 static double 00065 inner_double( int n, double *x, double *y ) 00066 { 00067 double aa = 0.0; 00068 int i; 00069 00070 for ( i = 0; i <= n; i++ ) 00071 aa = aa + x[i] * y[i]; 00072 return ( aa ); 00073 } 00074 00075 static void 00076 vector_single( int n, float *a, float *x, float *y ) 00077 { 00078 int i, j; 00079 00080 for ( i = 0; i <= n; i++ ) 00081 for ( j = 0; j <= n; j++ ) 00082 y[i] = y[i] + a[i * n + j] * x[i]; 00083 } 00084 00085 static void 00086 vector_double( int n, double *a, double *x, double *y ) 00087 { 00088 int i, j; 00089 00090 for ( i = 0; i <= n; i++ ) 00091 for ( j = 0; j <= n; j++ ) 00092 y[i] = y[i] + a[i * n + j] * x[i]; 00093 } 00094 00095 static void 00096 matrix_single( int n, float *c, float *a, float *b ) 00097 { 00098 int i, j, k; 00099 00100 for ( i = 0; i <= n; i++ ) 00101 for ( j = 0; j <= n; j++ ) 00102 for ( k = 0; k <= n; k++ ) 00103 c[i * n + j] = c[i * n + j] + a[i * n + k] * b[k * n + j]; 00104 } 00105 00106 static void 00107 matrix_double( int n, double *c, double *a, double *b ) 00108 { 00109 int i, j, k; 00110 00111 for ( i = 0; i <= n; i++ ) 00112 for ( j = 0; j <= n; j++ ) 00113 for ( k = 0; k <= n; k++ ) 00114 c[i * n + j] = c[i * n + j] + a[i * n + k] * b[k * n + j]; 00115 } 00116 00117 static void 00118 reset_flops( char *title, int EventSet ) 00119 { 00120 int retval; 00121 char err_str[PAPI_MAX_STR_LEN]; 00122 00123 retval = PAPI_start( EventSet ); 00124 if ( retval != PAPI_OK ) { 00125 sprintf( err_str, "%s: PAPI_start", title ); 00126 test_fail( __FILE__, __LINE__, err_str, retval ); 00127 } 00128 } 00129 00130 int 00131 main( int argc, char *argv[] ) 00132 { 00133 extern void dummy( void * ); 00134 00135 float aa, *a, *b, *c, *x, *y; 00136 double aad, *ad, *bd, *cd, *xd, *yd; 00137 int i, j, n; 00138 int inner = 0; 00139 int vector = 0; 00140 int matrix = 0; 00141 int double_precision = 0; 00142 int fail = 1; 00143 int retval = PAPI_OK; 00144 char papi_event_str[PAPI_MIN_STR_LEN] = "PAPI_FP_OPS"; 00145 int papi_event; 00146 int EventSet = PAPI_NULL; 00147 00148 /* Parse the input arguments */ 00149 for ( i = 0; i < argc; i++ ) { 00150 if ( strstr( argv[i], "-i" ) ) 00151 inner = 1; 00152 else if ( strstr( argv[i], "-f" ) ) 00153 fail = 0; 00154 else if ( strstr( argv[i], "-v" ) ) 00155 vector = 1; 00156 else if ( strstr( argv[i], "-m" ) ) 00157 matrix = 1; 00158 else if ( strstr( argv[i], "-e" ) ) { 00159 if ( ( argv[i + 1] == NULL ) || ( strlen( argv[i + 1] ) == 0 ) ) { 00160 print_help( argv ); 00161 exit( 1 ); 00162 } 00163 strncpy( papi_event_str, argv[i + 1], sizeof ( papi_event_str ) ); 00164 i++; 00165 } else if ( strstr( argv[i], "-d" ) ) 00166 double_precision = 1; 00167 else if ( strstr( argv[i], "-h" ) ) { 00168 print_help( argv ); 00169 exit( 1 ); 00170 } 00171 } 00172 00173 /* if no options specified, set all tests to TRUE */ 00174 if ( inner + vector + matrix == 0 ) 00175 inner = vector = matrix = 1; 00176 00177 00178 tests_quiet( argc, argv ); /* Set TESTS_QUIET variable */ 00179 00180 if ( !TESTS_QUIET ) 00181 printf( "Initializing..." ); 00182 00183 /* Initialize PAPI */ 00184 retval = PAPI_library_init( PAPI_VER_CURRENT ); 00185 if ( retval != PAPI_VER_CURRENT ) 00186 test_fail( __FILE__, __LINE__, "PAPI_library_init", retval ); 00187 00188 /* Translate name */ 00189 retval = PAPI_event_name_to_code( papi_event_str, &papi_event ); 00190 if ( retval != PAPI_OK ) 00191 test_fail( __FILE__, __LINE__, "PAPI_event_name_to_code", retval ); 00192 00193 if ( PAPI_query_event( papi_event ) != PAPI_OK ) 00194 test_skip( __FILE__, __LINE__, "PAPI_query_event", PAPI_ENOEVNT ); 00195 00196 if ( ( retval = PAPI_create_eventset( &EventSet ) ) != PAPI_OK ) 00197 test_fail( __FILE__, __LINE__, "PAPI_create_eventset", retval ); 00198 00199 if ( ( retval = PAPI_add_event( EventSet, papi_event ) ) != PAPI_OK ) 00200 test_fail( __FILE__, __LINE__, "PAPI_add_event", retval ); 00201 00202 printf( "\n" ); 00203 00204 retval = PAPI_OK; 00205 00206 /* Inner Product test */ 00207 if ( inner ) { 00208 /* Allocate the linear arrays */ 00209 if (double_precision) { 00210 xd = malloc( INDEX5 * sizeof(double) ); 00211 yd = malloc( INDEX5 * sizeof(double) ); 00212 if ( !( xd && yd ) ) 00213 retval = PAPI_ENOMEM; 00214 } 00215 else { 00216 x = malloc( INDEX5 * sizeof(float) ); 00217 y = malloc( INDEX5 * sizeof(float) ); 00218 if ( !( x && y ) ) 00219 retval = PAPI_ENOMEM; 00220 } 00221 00222 if ( retval == PAPI_OK ) { 00223 headerlines( "Inner Product Test", TESTS_QUIET ); 00224 00225 /* step through the different array sizes */ 00226 for ( n = 0; n < INDEX5; n++ ) { 00227 if ( n < INDEX1 || ( ( n + 1 ) % 50 ) == 0 ) { 00228 00229 /* Initialize the needed arrays at this size */ 00230 if ( double_precision ) { 00231 for ( i = 0; i <= n; i++ ) { 00232 xd[i] = ( double ) rand( ) * ( double ) 1.1; 00233 yd[i] = ( double ) rand( ) * ( double ) 1.1; 00234 } 00235 } else { 00236 for ( i = 0; i <= n; i++ ) { 00237 x[i] = ( float ) rand( ) * ( float ) 1.1; 00238 y[i] = ( float ) rand( ) * ( float ) 1.1; 00239 } 00240 } 00241 00242 /* reset PAPI flops count */ 00243 reset_flops( "Inner Product Test", EventSet ); 00244 00245 /* do the multiplication */ 00246 if ( double_precision ) { 00247 aad = inner_double( n, xd, yd ); 00248 dummy( ( void * ) &aad ); 00249 } else { 00250 aa = inner_single( n, x, y ); 00251 dummy( ( void * ) &aa ); 00252 } 00253 resultline( n, 1, EventSet, fail ); 00254 } 00255 } 00256 } 00257 if (double_precision) { 00258 free( xd ); 00259 free( yd ); 00260 } else { 00261 free( x ); 00262 free( y ); 00263 } 00264 } 00265 00266 /* Matrix Vector test */ 00267 if ( vector && retval != PAPI_ENOMEM ) { 00268 /* Allocate the needed arrays */ 00269 if (double_precision) { 00270 ad = malloc( INDEX5 * INDEX5 * sizeof(double) ); 00271 xd = malloc( INDEX5 * sizeof(double) ); 00272 yd = malloc( INDEX5 * sizeof(double) ); 00273 if ( !( ad && xd && yd ) ) 00274 retval = PAPI_ENOMEM; 00275 } else { 00276 a = malloc( INDEX5 * INDEX5 * sizeof(float) ); 00277 x = malloc( INDEX5 * sizeof(float) ); 00278 y = malloc( INDEX5 * sizeof(float) ); 00279 if ( !( a && x && y ) ) 00280 retval = PAPI_ENOMEM; 00281 } 00282 00283 if ( retval == PAPI_OK ) { 00284 headerlines( "Matrix Vector Test", TESTS_QUIET ); 00285 00286 /* step through the different array sizes */ 00287 for ( n = 0; n < INDEX5; n++ ) { 00288 if ( n < INDEX1 || ( ( n + 1 ) % 50 ) == 0 ) { 00289 00290 /* Initialize the needed arrays at this size */ 00291 if ( double_precision ) { 00292 for ( i = 0; i <= n; i++ ) { 00293 yd[i] = 0.0; 00294 xd[i] = ( double ) rand( ) * ( double ) 1.1; 00295 for ( j = 0; j <= n; j++ ) 00296 ad[i * n + j] = 00297 ( double ) rand( ) * ( double ) 1.1; 00298 } 00299 } else { 00300 for ( i = 0; i <= n; i++ ) { 00301 y[i] = 0.0; 00302 x[i] = ( float ) rand( ) * ( float ) 1.1; 00303 for ( j = 0; j <= n; j++ ) 00304 a[i * n + j] = 00305 ( float ) rand( ) * ( float ) 1.1; 00306 } 00307 } 00308 00309 /* reset PAPI flops count */ 00310 reset_flops( "Matrix Vector Test", EventSet ); 00311 00312 /* compute the resultant vector */ 00313 if ( double_precision ) { 00314 vector_double( n, ad, xd, yd ); 00315 dummy( ( void * ) yd ); 00316 } else { 00317 vector_single( n, a, x, y ); 00318 dummy( ( void * ) y ); 00319 } 00320 resultline( n, 2, EventSet, fail ); 00321 } 00322 } 00323 } 00324 if (double_precision) { 00325 free( ad ); 00326 free( xd ); 00327 free( yd ); 00328 } else { 00329 free( a ); 00330 free( x ); 00331 free( y ); 00332 } 00333 } 00334 00335 /* Matrix Multiply test */ 00336 if ( matrix && retval != PAPI_ENOMEM ) { 00337 /* Allocate the needed arrays */ 00338 if (double_precision) { 00339 ad = malloc( INDEX5 * INDEX5 * sizeof(double) ); 00340 bd = malloc( INDEX5 * INDEX5 * sizeof(double) ); 00341 cd = malloc( INDEX5 * INDEX5 * sizeof(double) ); 00342 if ( !( ad && bd && cd ) ) 00343 retval = PAPI_ENOMEM; 00344 } else { 00345 a = malloc( INDEX5 * INDEX5 * sizeof(float) ); 00346 b = malloc( INDEX5 * INDEX5 * sizeof(float) ); 00347 c = malloc( INDEX5 * INDEX5 * sizeof(float) ); 00348 if ( !( a && b && c ) ) 00349 retval = PAPI_ENOMEM; 00350 } 00351 00352 00353 if ( retval == PAPI_OK ) { 00354 headerlines( "Matrix Multiply Test", TESTS_QUIET ); 00355 00356 /* step through the different array sizes */ 00357 for ( n = 0; n < INDEX5; n++ ) { 00358 if ( n < INDEX1 || ( ( n + 1 ) % 50 ) == 0 ) { 00359 00360 /* Initialize the needed arrays at this size */ 00361 if ( double_precision ) { 00362 for ( i = 0; i <= n * n + n; i++ ) { 00363 cd[i] = 0.0; 00364 ad[i] = ( double ) rand( ) * ( double ) 1.1; 00365 bd[i] = ( double ) rand( ) * ( double ) 1.1; 00366 } 00367 } else { 00368 for ( i = 0; i <= n * n + n; i++ ) { 00369 c[i] = 0.0; 00370 a[i] = ( float ) rand( ) * ( float ) 1.1; 00371 b[i] = ( float ) rand( ) * ( float ) 1.1; 00372 } 00373 } 00374 00375 /* reset PAPI flops count */ 00376 reset_flops( "Matrix Multiply Test", EventSet ); 00377 00378 /* compute the resultant matrix */ 00379 if ( double_precision ) { 00380 matrix_double( n, cd, ad, bd ); 00381 dummy( ( void * ) c ); 00382 } else { 00383 matrix_single( n, c, a, b ); 00384 dummy( ( void * ) c ); 00385 } 00386 resultline( n, 3, EventSet, fail ); 00387 } 00388 } 00389 } 00390 if (double_precision) { 00391 free( ad ); 00392 free( bd ); 00393 free( cd ); 00394 } else { 00395 free( a ); 00396 free( b ); 00397 free( c ); 00398 } 00399 } 00400 00401 /* exit with status code */ 00402 if ( retval == PAPI_ENOMEM ) 00403 test_fail( __FILE__, __LINE__, "malloc", retval ); 00404 else 00405 test_pass( __FILE__, NULL, 0 ); 00406 exit( 1 ); 00407 } 00408 00409 /* 00410 Extract and display hardware information for this processor. 00411 (Re)Initialize PAPI_flops() and begin counting floating ops. 00412 */ 00413 static void 00414 headerlines( char *title, int TESTS_QUIET ) 00415 { 00416 const PAPI_hw_info_t *hwinfo = NULL; 00417 00418 if ( !TESTS_QUIET ) { 00419 if ( papi_print_header( "", &hwinfo ) != PAPI_OK ) 00420 test_fail( __FILE__, __LINE__, "PAPI_get_hardware_info", 2 ); 00421 00422 printf( "\n%s:\n%8s %12s %12s %8s %8s\n", title, "i", "papi", "theory", 00423 "diff", "%error" ); 00424 printf 00425 ( "-------------------------------------------------------------------------\n" ); 00426 } 00427 } 00428 00429 /* 00430 Read PAPI_flops. 00431 Format and display results. 00432 Compute error without using floating ops. 00433 */ 00434 #if defined(mips) 00435 #define FMA 1 00436 #elif (defined(sparc) && defined(sun)) 00437 #define FMA 1 00438 #else 00439 #define FMA 0 00440 #endif 00441 00442 static void 00443 resultline( int i, int j, int EventSet, int fail ) 00444 { 00445 float ferror = 0; 00446 long long flpins = 0; 00447 long long papi, theory; 00448 int diff, retval; 00449 char err_str[PAPI_MAX_STR_LEN]; 00450 00451 retval = PAPI_stop( EventSet, &flpins ); 00452 if ( retval != PAPI_OK ) 00453 test_fail( __FILE__, __LINE__, "PAPI_stop", retval ); 00454 00455 i++; /* convert to 1s base */ 00456 theory = 2; 00457 while ( j-- ) 00458 theory *= i; /* theoretical ops */ 00459 papi = flpins << FMA; 00460 00461 diff = ( int ) ( papi - theory ); 00462 00463 ferror = ( ( float ) abs( diff ) ) / ( ( float ) theory ) * 100; 00464 00465 printf( "%8d %12lld %12lld %8d %10.4f\n", i, papi, theory, diff, ferror ); 00466 00467 if ( ferror > MAX_WARN && abs( diff ) > MAX_DIFF && i > 20 ) { 00468 sprintf( err_str, "Calibrate: difference exceeds %d percent", MAX_WARN ); 00469 test_warn( __FILE__, __LINE__, err_str, 0 ); 00470 } 00471 if (fail) { 00472 if ( ferror > MAX_ERROR && abs( diff ) > MAX_DIFF && i > 20 ) { 00473 sprintf( err_str, "Calibrate: error exceeds %d percent", MAX_ERROR ); 00474 test_fail( __FILE__, __LINE__, err_str, PAPI_EMISC ); 00475 } 00476 } 00477 }