/* This file attempts to test the retired instruction event */ /* As implemented by PAPI_TOT_INS */ /* For more info on the causes of overcount on x86 systems */ /* See the ISPASS2013 paper: */ /* "Non-Determinism and Overcount on Modern Hardware */ /* Performance Counter Implementations" */ /* by Vince Weaver, */ #include #include #include #include #include #include "papi.h" #include "papi_test.h" #include "display_error.h" #include "testcode.h" #define NUM_RUNS 100 /* Test a simple loop of 1 million instructions */ /* Most implementations should count be correct within 1% */ /* This loop in in assembly language, as compiler generated */ /* code varies too much. */ static void test_million(int quiet) { int i,result,ins_result; long long count,high=0,low=0,total=0,average=0; double error; int eventset=PAPI_NULL; if (!quiet) { printf("\nTesting a loop of 1 million instructions (%d times):\n", NUM_RUNS); } result=PAPI_create_eventset(&eventset); if (result!=PAPI_OK) { test_fail( __FILE__, __LINE__, "PAPI_create_eventset", result ); } result=PAPI_add_named_event(eventset,"PAPI_TOT_INS"); if (result!=PAPI_OK) { if (!quiet) printf("Could not add PAPI_TOT_INS\n"); test_skip( __FILE__, __LINE__, "adding PAPI_TOT_INS", result ); } for(i=0;ihigh) high=count; if ((low==0) || (count 1.0) || (error<-1.0)) { #if defined(__PPC__) if(!quiet) { printf("If PPC is off by 50%%, this might be due to\n" "\"folded\" branch instructions on PPC32\n"); } #endif test_fail( __FILE__, __LINE__, "validation", result ); } } /* Test fldcw. Pentium 4 overcounts this instruction */ static void test_fldcw(int quiet) { (void)quiet; #if defined(__i386__) || (defined __x86_64__) int i,result,ins_result; int eventset=PAPI_NULL; long long count,high=0,low=0,total=0,average=0; double error; if (!quiet) { printf("\nTesting a fldcw loop of 900,000 instructions (%d times):\n", NUM_RUNS); } result=PAPI_create_eventset(&eventset); if (result!=PAPI_OK) { test_fail( __FILE__, __LINE__, "PAPI_create_eventset", result ); } result=PAPI_add_named_event(eventset,"PAPI_TOT_INS"); if (result!=PAPI_OK) { test_fail( __FILE__, __LINE__, "adding PAPI_TOT_INS", result ); } for(i=0;ihigh) high=count; if ((low==0) || (count 1.0) || (error<-1.0)) { if (!quiet) { printf("On Pentium 4 machines, the fldcw instruction counts as 2.\n"); printf("This will lead to an overcount of 22%%\n"); } test_fail( __FILE__, __LINE__, "Error too high", 1 ); } #endif } /* Test rep-prefixed instructions. */ /* HW counters count this as one each, not one per repeat */ static void test_rep(int quiet) { (void)quiet; #if defined(__i386__) || (defined __x86_64__) int i,result,ins_result; int eventset=PAPI_NULL; long long count,high=0,low=0,total=0,average=0; double error; if(!quiet) { printf("\nTesting a 16k rep loop (%d times):\n", NUM_RUNS); } result=PAPI_create_eventset(&eventset); if (result!=PAPI_OK) { test_fail( __FILE__, __LINE__, "PAPI_create_eventset", result ); } result=PAPI_add_named_event(eventset,"PAPI_TOT_INS"); if (result!=PAPI_OK) { test_fail( __FILE__, __LINE__, "adding PAPI_TOT_INS", result ); } for(i=0;ihigh) high=count; if ((low==0) || (count 10.0) || (error<-10.0)) { if (!quiet) { printf("Instruction count off by more than 10%%\n"); } test_fail( __FILE__, __LINE__, "Error too high", 1 ); } #endif } int main(int argc, char **argv) { int retval; int quiet=0; (void)argc; (void)argv; quiet=tests_quiet(argc,argv); if (!quiet) { printf("\nThis test checks that the \"PAPI_TOT_INS\" generalized " "event is working.\n"); } /* Init the PAPI library */ retval = PAPI_library_init( PAPI_VER_CURRENT ); if ( retval != PAPI_VER_CURRENT ) { test_fail( __FILE__, __LINE__, "PAPI_library_init", retval ); } test_million(quiet); test_fldcw(quiet); test_rep(quiet); if (!quiet) printf("\n"); test_pass( __FILE__ ); PAPI_shutdown(); return 0; }