PAPI  5.0.1.0
calibrate.c
Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines