PAPI  5.0.1.0
multiattach.c
Go to the documentation of this file.
00001 /* This file performs the following test: start, stop and timer functionality for
00002    multiple attached processes.
00003 
00004    - It attempts to use the following two counters. It may use less depending on
00005      hardware counter resource limitations. These are counted in the default counting
00006      domain and default granularity, depending on the platform. Usually this is 
00007      the user domain (PAPI_DOM_USER) and thread context (PAPI_GRN_THR).
00008      + PAPI_FP_INS
00009      + PAPI_TOT_CYC
00010    - Get us.
00011    - Start counters
00012    - Do flops
00013    - Stop and read counters
00014    - Get us.
00015 */
00016 
00017 #include "papi_test.h"
00018 #include <sys/ptrace.h>
00019 #include <inttypes.h>
00020 
00021 #ifdef _AIX
00022 #define _LINUX_SOURCE_COMPAT
00023 #endif
00024 
00025 #if defined(__FreeBSD__)
00026 # define PTRACE_ATTACH PT_ATTACH
00027 # define PTRACE_CONT PT_CONTINUE
00028 #endif
00029 
00030 int
00031 wait_for_attach_and_loop( int num )
00032 {
00033     kill( getpid(  ), SIGSTOP );
00034     do_flops( NUM_FLOPS * num );
00035     kill( getpid(  ), SIGSTOP );
00036     return ( 0 );
00037 }
00038 
00039 int
00040 main( int argc, char **argv )
00041 {
00042     int status, retval, num_tests = 2, tmp;
00043     int EventSet1 = PAPI_NULL, EventSet2 = PAPI_NULL;
00044     int PAPI_event, PAPI_event2, mask1, mask2;
00045     int num_events1, num_events2;
00046     long long **values;
00047     long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc;
00048     char event_name[PAPI_MAX_STR_LEN], add_event_str[PAPI_MAX_STR_LEN];
00049     const PAPI_component_info_t *cmpinfo;
00050     pid_t pid, pid2;
00051     double ratio1,ratio2;
00052 
00053     /* Set TESTS_QUIET variable */
00054     tests_quiet( argc, argv );
00055 
00056     /* Initialize the library */
00057     retval = PAPI_library_init( PAPI_VER_CURRENT );
00058     if ( retval != PAPI_VER_CURRENT ) {
00059        test_fail_exit( __FILE__, __LINE__, "PAPI_library_init", retval );
00060     }
00061 
00062     /* get the component info and check if we support attach */
00063     if ( ( cmpinfo = PAPI_get_component_info( 0 ) ) == NULL ) {
00064        test_fail_exit( __FILE__, __LINE__, "PAPI_get_component_info", 0 );
00065     }
00066 
00067     if ( cmpinfo->attach == 0 ) {
00068        test_skip( __FILE__, __LINE__, 
00069               "Platform does not support attaching", 0 );
00070     }
00071 
00072     /* fork off first child */
00073     pid = fork(  );
00074     if ( pid < 0 ) {
00075        test_fail_exit( __FILE__, __LINE__, "fork()", PAPI_ESYS );
00076     }
00077     if ( pid == 0 ) {
00078        exit( wait_for_attach_and_loop( 1 ) );
00079     }
00080 
00081     /* fork off second child, does twice as much */
00082     pid2 = fork(  );
00083     if ( pid2 < 0 ) {
00084        test_fail_exit( __FILE__, __LINE__, "fork()", PAPI_ESYS );
00085     }
00086     if ( pid2 == 0 ) {
00087        exit( wait_for_attach_and_loop( 2 ) );
00088     }
00089 
00090     /* add PAPI_TOT_CYC and one of the events in 
00091            PAPI_FP_INS, PAPI_FP_OPS or PAPI_TOT_INS, 
00092            depending on the availability of the event 
00093            on the platform                            */
00094     EventSet1 = add_two_events( &num_events1, &PAPI_event, &mask1 );
00095     EventSet2 = add_two_events( &num_events2, &PAPI_event2, &mask2 );
00096 
00097     if ( cmpinfo->attach_must_ptrace ) {
00098        if ( ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) {
00099           perror( "ptrace(PTRACE_ATTACH)" );
00100           return 1 ;
00101        }
00102        if ( waitpid( pid, &status, 0 ) == -1 ) {
00103           perror( "waitpid()" );
00104           exit( 1 );
00105        }
00106        if ( WIFSTOPPED( status ) == 0 ) {
00107           test_fail( __FILE__, __LINE__,
00108             "Child process didnt return true to WIFSTOPPED", 0 );
00109        }
00110        
00111        if ( ptrace( PTRACE_ATTACH, pid2, NULL, NULL ) == -1 ) {
00112           perror( "ptrace(PTRACE_ATTACH)" );
00113           return 1;
00114        }
00115        if ( waitpid( pid2, &status, 0 ) == -1 ) {
00116           perror( "waitpid()" );
00117           exit( 1 );
00118        }
00119        if ( WIFSTOPPED( status ) == 0 ) {
00120           test_fail( __FILE__, __LINE__,
00121             "Child process didnt return true to WIFSTOPPED", 0 );
00122        }
00123     }
00124 
00125     retval = PAPI_attach( EventSet1, ( unsigned long ) pid );
00126     if ( retval != PAPI_OK ) {
00127        test_fail( __FILE__, __LINE__, "PAPI_attach", retval ); 
00128     }
00129 
00130     retval = PAPI_attach( EventSet2, ( unsigned long ) pid2 );
00131     if ( retval != PAPI_OK ) {
00132        test_fail( __FILE__, __LINE__, "PAPI_attach", retval ); 
00133     }
00134 
00135     retval = PAPI_event_code_to_name( PAPI_event, event_name );
00136     if ( retval != PAPI_OK ) {
00137        test_fail( __FILE__, __LINE__, "PAPI_event_code_to_name", retval );
00138     }
00139     sprintf( add_event_str, "PAPI_add_event[%s]", event_name );
00140 
00141     /* num_events1 is greater than num_events2 so don't worry. */
00142 
00143     values = allocate_test_space( num_tests, num_events1 );
00144 
00145     /* Gather before values */
00146     elapsed_us = PAPI_get_real_usec(  );
00147     elapsed_cyc = PAPI_get_real_cyc(  );
00148     elapsed_virt_us = PAPI_get_virt_usec(  );
00149     elapsed_virt_cyc = PAPI_get_virt_cyc(  );
00150 
00151     /* Wait for the SIGSTOP. */
00152     if ( cmpinfo->attach_must_ptrace ) {
00153        if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
00154           perror( "ptrace(PTRACE_CONT)" );
00155           return 1;
00156        }
00157        if ( waitpid( pid, &status, 0 ) == -1 ) {
00158           perror( "waitpid()" );
00159           exit( 1 );
00160        }
00161        if ( WIFSTOPPED( status ) == 0 ) {
00162           test_fail( __FILE__, __LINE__,
00163             "Child process didn't return true to WIFSTOPPED", 0 );
00164        }
00165        if ( WSTOPSIG( status ) != SIGSTOP ) {
00166           test_fail( __FILE__, __LINE__,
00167             "Child process didn't stop on SIGSTOP", 0 );
00168        }
00169 
00170        if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
00171           perror( "ptrace(PTRACE_CONT)" );
00172           return 1;
00173        }
00174        if ( waitpid( pid2, &status, 0 ) == -1 ) {
00175           perror( "waitpid()" );
00176           exit( 1 );
00177        }
00178        if ( WIFSTOPPED( status ) == 0 ) {
00179           test_fail( __FILE__, __LINE__,
00180             "Child process didn't return true to WIFSTOPPED", 0 );
00181        }
00182        if ( WSTOPSIG( status ) != SIGSTOP ) {
00183           test_fail( __FILE__, __LINE__,
00184             "Child process didn't stop on SIGSTOP", 0 );
00185        }
00186     }
00187 
00188     /* start first child */
00189     retval = PAPI_start( EventSet1 );
00190     if ( retval != PAPI_OK ) {
00191         test_fail( __FILE__, __LINE__, "PAPI_start", retval );
00192     }
00193 
00194     /* start second child */
00195     retval = PAPI_start( EventSet2 );
00196     if ( retval != PAPI_OK ) {
00197         test_fail( __FILE__, __LINE__, "PAPI_start", retval );
00198     }
00199 
00200     /* Wait for the SIGSTOP. */
00201     if ( cmpinfo->attach_must_ptrace ) {
00202        if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
00203           perror( "ptrace(PTRACE_ATTACH)" );
00204           return 1;
00205        }
00206        if ( waitpid( pid, &status, 0 ) == -1 ) {
00207           perror( "waitpid()" );
00208           exit( 1 );
00209        }
00210        if ( WIFSTOPPED( status ) == 0 ) {
00211           test_fail( __FILE__, __LINE__,
00212             "Child process didn't return true to WIFSTOPPED", 0 );
00213        }
00214        if ( WSTOPSIG( status ) != SIGSTOP ) {
00215           test_fail( __FILE__, __LINE__,
00216             "Child process didn't stop on SIGSTOP", 0 );
00217        }
00218 
00219        if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
00220            perror( "ptrace(PTRACE_ATTACH)" );
00221            return 1;
00222        }
00223        if ( waitpid( pid2, &status, 0 ) == -1 ) {
00224           perror( "waitpid()" );
00225           exit( 1 );
00226        }
00227        if ( WIFSTOPPED( status ) == 0 ) {
00228           test_fail( __FILE__, __LINE__,
00229             "Child process didn't return true to WIFSTOPPED", 0 );
00230        }
00231        if ( WSTOPSIG( status ) != SIGSTOP ) {
00232           test_fail( __FILE__, __LINE__,
00233             "Child process didn't stop on SIGSTOP", 0 );
00234        }
00235     }
00236 
00237     elapsed_virt_us = PAPI_get_virt_usec(  ) - elapsed_virt_us;
00238     elapsed_virt_cyc = PAPI_get_virt_cyc(  ) - elapsed_virt_cyc;
00239     elapsed_us = PAPI_get_real_usec(  ) - elapsed_us;
00240     elapsed_cyc = PAPI_get_real_cyc(  ) - elapsed_cyc;
00241 
00242     /* stop first child */
00243     retval = PAPI_stop( EventSet1, values[0] );
00244     if ( retval != PAPI_OK ) {
00245        printf( "Warning: PAPI_stop returned error %d, probably ok.\n",
00246                 retval );
00247     }
00248 
00249     /* stop second child */
00250     retval = PAPI_stop( EventSet2, values[1] );
00251     if ( retval != PAPI_OK ) {
00252        printf( "Warning: PAPI_stop returned error %d, probably ok.\n",
00253                 retval );
00254     }
00255 
00256     remove_test_events( &EventSet1, mask1 );
00257     remove_test_events( &EventSet2, mask2 );
00258 
00259     if ( cmpinfo->attach_must_ptrace ) {
00260        if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
00261           perror( "ptrace(PTRACE_CONT)" );
00262           return 1;
00263        }
00264        if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
00265           perror( "ptrace(PTRACE_CONT)" );
00266           return 1;
00267        }
00268     }
00269 
00270     if ( waitpid( pid, &status, 0 ) == -1 ) {
00271        perror( "waitpid()" );
00272        exit( 1 );
00273     }
00274     if ( WIFEXITED( status ) == 0 ) {
00275        test_fail( __FILE__, __LINE__,
00276              "Child process didn't return true to WIFEXITED", 0 );
00277     }
00278 
00279     if ( waitpid( pid2, &status, 0 ) == -1 ) {
00280        perror( "waitpid()" );
00281        exit( 1 );
00282     }
00283     if ( WIFEXITED( status ) == 0 ) {
00284         test_fail( __FILE__, __LINE__,
00285               "Child process didn't return true to WIFEXITED", 0 );
00286     }
00287 
00288     /* This code isn't necessary as we know the child has exited, */
00289     /* it *may* return an error if the component so chooses. You  */
00290         /* should use read() instead. */
00291 
00292     printf( "Test case: multiple 3rd party attach start, stop.\n" );
00293     printf( "-----------------------------------------------\n" );
00294     tmp = PAPI_get_opt( PAPI_DEFDOM, NULL );
00295     printf( "Default domain is: %d (%s)\n", tmp, 
00296         stringify_all_domains( tmp ) );
00297     tmp = PAPI_get_opt( PAPI_DEFGRN, NULL );
00298     printf( "Default granularity is: %d (%s)\n", tmp,
00299             stringify_granularity( tmp ) );
00300     printf( "Using %d iterations of c += a*b\n", NUM_FLOPS );
00301     printf( "-------------------------------------------------------------------------\n" );
00302 
00303     sprintf( add_event_str, "(PID %jd) %-12s : \t", ( intmax_t ) pid,
00304              event_name );
00305     printf( TAB1, add_event_str, values[0][1] );
00306     sprintf( add_event_str, "(PID %jd) PAPI_TOT_CYC : \t", 
00307          ( intmax_t ) pid );
00308     printf( TAB1, add_event_str, values[0][0] );
00309     sprintf( add_event_str, "(PID %jd) %-12s : \t", ( intmax_t ) pid2,
00310              event_name );
00311     printf( TAB1, add_event_str,values[1][1] );
00312     sprintf( add_event_str, "(PID %jd) PAPI_TOT_CYC : \t", 
00313          ( intmax_t ) pid2 );
00314     printf( TAB1, add_event_str, values[1][0] );
00315     printf( TAB1, "Real usec    : \t", elapsed_us );
00316     printf( TAB1, "Real cycles  : \t", elapsed_cyc );
00317     printf( TAB1, "Virt usec    : \t", elapsed_virt_us );
00318     printf( TAB1, "Virt cycles  : \t", elapsed_virt_cyc );
00319 
00320     printf
00321         ( "-------------------------------------------------------------------------\n" );
00322 
00323     printf("Verification: pid %d results should be twice pid %d\n",pid2,pid );
00324 
00325     ratio1=(double)values[1][0]/(double)values[0][0];
00326     ratio2=(double)values[1][1]/(double)values[0][1];
00327 
00328     printf("\t%lld/%lld = %lf\n",values[1][0],values[0][0],ratio1);
00329     
00330 
00331     if ((ratio1 >2.15 ) || (ratio1 < 1.85)) {
00332       printf("Ratio out of range, should be ~2.0 not %lf\n",ratio1);
00333       test_fail( __FILE__, __LINE__,
00334             "Error: Counter ratio not two", 0 );
00335     }
00336 
00337     printf("\t%lld/%lld = %lf\n",values[1][1],values[0][1],ratio2);
00338 
00339     if ((ratio2 >2.75 ) || (ratio2 < 1.25)) {
00340       printf("Ratio out of range, should be ~2.0, not %lf\n",ratio2);
00341       test_fail( __FILE__, __LINE__,
00342             "Known issue: Counter ratio not two", 0 );
00343     }
00344 
00345     test_pass( __FILE__, values, num_tests );
00346     return 0;
00347 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines