PAPI  5.0.1.0
multiattach.c File Reference
Include dependency graph for multiattach.c:

Go to the source code of this file.

Functions

int wait_for_attach_and_loop (int num)
int main (int argc, char **argv)

Function Documentation

int main ( int  argc,
char **  argv 
)

Definition at line 40 of file multiattach.c.

{
    int status, retval, num_tests = 2, tmp;
    int EventSet1 = PAPI_NULL, EventSet2 = PAPI_NULL;
    int PAPI_event, PAPI_event2, mask1, mask2;
    int num_events1, num_events2;
    long long **values;
    long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc;
    char event_name[PAPI_MAX_STR_LEN], add_event_str[PAPI_MAX_STR_LEN];
    const PAPI_component_info_t *cmpinfo;
    pid_t pid, pid2;
    double ratio1,ratio2;

    /* Set TESTS_QUIET variable */
    tests_quiet( argc, argv );

    /* Initialize the library */
    retval = PAPI_library_init( PAPI_VER_CURRENT );
    if ( retval != PAPI_VER_CURRENT ) {
       test_fail_exit( __FILE__, __LINE__, "PAPI_library_init", retval );
    }

    /* get the component info and check if we support attach */
    if ( ( cmpinfo = PAPI_get_component_info( 0 ) ) == NULL ) {
       test_fail_exit( __FILE__, __LINE__, "PAPI_get_component_info", 0 );
    }

    if ( cmpinfo->attach == 0 ) {
       test_skip( __FILE__, __LINE__, 
              "Platform does not support attaching", 0 );
    }

    /* fork off first child */
    pid = fork(  );
    if ( pid < 0 ) {
       test_fail_exit( __FILE__, __LINE__, "fork()", PAPI_ESYS );
    }
    if ( pid == 0 ) {
       exit( wait_for_attach_and_loop( 1 ) );
    }

    /* fork off second child, does twice as much */
    pid2 = fork(  );
    if ( pid2 < 0 ) {
       test_fail_exit( __FILE__, __LINE__, "fork()", PAPI_ESYS );
    }
    if ( pid2 == 0 ) {
       exit( wait_for_attach_and_loop( 2 ) );
    }

    /* add PAPI_TOT_CYC and one of the events in 
           PAPI_FP_INS, PAPI_FP_OPS or PAPI_TOT_INS, 
           depending on the availability of the event 
           on the platform                            */
    EventSet1 = add_two_events( &num_events1, &PAPI_event, &mask1 );
    EventSet2 = add_two_events( &num_events2, &PAPI_event2, &mask2 );

    if ( cmpinfo->attach_must_ptrace ) {
       if ( ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_ATTACH)" );
          return 1 ;
       }
       if ( waitpid( pid, &status, 0 ) == -1 ) {
          perror( "waitpid()" );
          exit( 1 );
       }
       if ( WIFSTOPPED( status ) == 0 ) {
          test_fail( __FILE__, __LINE__,
            "Child process didnt return true to WIFSTOPPED", 0 );
       }
       
       if ( ptrace( PTRACE_ATTACH, pid2, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_ATTACH)" );
          return 1;
       }
       if ( waitpid( pid2, &status, 0 ) == -1 ) {
          perror( "waitpid()" );
          exit( 1 );
       }
       if ( WIFSTOPPED( status ) == 0 ) {
          test_fail( __FILE__, __LINE__,
            "Child process didnt return true to WIFSTOPPED", 0 );
       }
    }

    retval = PAPI_attach( EventSet1, ( unsigned long ) pid );
    if ( retval != PAPI_OK ) {
       test_fail( __FILE__, __LINE__, "PAPI_attach", retval ); 
    }

    retval = PAPI_attach( EventSet2, ( unsigned long ) pid2 );
    if ( retval != PAPI_OK ) {
       test_fail( __FILE__, __LINE__, "PAPI_attach", retval ); 
    }

    retval = PAPI_event_code_to_name( PAPI_event, event_name );
    if ( retval != PAPI_OK ) {
       test_fail( __FILE__, __LINE__, "PAPI_event_code_to_name", retval );
    }
    sprintf( add_event_str, "PAPI_add_event[%s]", event_name );

    /* num_events1 is greater than num_events2 so don't worry. */

    values = allocate_test_space( num_tests, num_events1 );

    /* Gather before values */
    elapsed_us = PAPI_get_real_usec(  );
    elapsed_cyc = PAPI_get_real_cyc(  );
    elapsed_virt_us = PAPI_get_virt_usec(  );
    elapsed_virt_cyc = PAPI_get_virt_cyc(  );

    /* Wait for the SIGSTOP. */
    if ( cmpinfo->attach_must_ptrace ) {
       if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_CONT)" );
          return 1;
       }
       if ( waitpid( pid, &status, 0 ) == -1 ) {
          perror( "waitpid()" );
          exit( 1 );
       }
       if ( WIFSTOPPED( status ) == 0 ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't return true to WIFSTOPPED", 0 );
       }
       if ( WSTOPSIG( status ) != SIGSTOP ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't stop on SIGSTOP", 0 );
       }

       if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_CONT)" );
          return 1;
       }
       if ( waitpid( pid2, &status, 0 ) == -1 ) {
          perror( "waitpid()" );
          exit( 1 );
       }
       if ( WIFSTOPPED( status ) == 0 ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't return true to WIFSTOPPED", 0 );
       }
       if ( WSTOPSIG( status ) != SIGSTOP ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't stop on SIGSTOP", 0 );
       }
    }

    /* start first child */
    retval = PAPI_start( EventSet1 );
    if ( retval != PAPI_OK ) {
        test_fail( __FILE__, __LINE__, "PAPI_start", retval );
    }

    /* start second child */
    retval = PAPI_start( EventSet2 );
    if ( retval != PAPI_OK ) {
        test_fail( __FILE__, __LINE__, "PAPI_start", retval );
    }

    /* Wait for the SIGSTOP. */
    if ( cmpinfo->attach_must_ptrace ) {
       if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_ATTACH)" );
          return 1;
       }
       if ( waitpid( pid, &status, 0 ) == -1 ) {
          perror( "waitpid()" );
          exit( 1 );
       }
       if ( WIFSTOPPED( status ) == 0 ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't return true to WIFSTOPPED", 0 );
       }
       if ( WSTOPSIG( status ) != SIGSTOP ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't stop on SIGSTOP", 0 );
       }

       if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
           perror( "ptrace(PTRACE_ATTACH)" );
           return 1;
       }
       if ( waitpid( pid2, &status, 0 ) == -1 ) {
          perror( "waitpid()" );
          exit( 1 );
       }
       if ( WIFSTOPPED( status ) == 0 ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't return true to WIFSTOPPED", 0 );
       }
       if ( WSTOPSIG( status ) != SIGSTOP ) {
          test_fail( __FILE__, __LINE__,
            "Child process didn't stop on SIGSTOP", 0 );
       }
    }

    elapsed_virt_us = PAPI_get_virt_usec(  ) - elapsed_virt_us;
    elapsed_virt_cyc = PAPI_get_virt_cyc(  ) - elapsed_virt_cyc;
    elapsed_us = PAPI_get_real_usec(  ) - elapsed_us;
    elapsed_cyc = PAPI_get_real_cyc(  ) - elapsed_cyc;

    /* stop first child */
    retval = PAPI_stop( EventSet1, values[0] );
    if ( retval != PAPI_OK ) {
       printf( "Warning: PAPI_stop returned error %d, probably ok.\n",
                retval );
    }

    /* stop second child */
    retval = PAPI_stop( EventSet2, values[1] );
    if ( retval != PAPI_OK ) {
       printf( "Warning: PAPI_stop returned error %d, probably ok.\n",
                retval );
    }

    remove_test_events( &EventSet1, mask1 );
    remove_test_events( &EventSet2, mask2 );

    if ( cmpinfo->attach_must_ptrace ) {
       if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_CONT)" );
          return 1;
       }
       if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
          perror( "ptrace(PTRACE_CONT)" );
          return 1;
       }
    }

    if ( waitpid( pid, &status, 0 ) == -1 ) {
       perror( "waitpid()" );
       exit( 1 );
    }
    if ( WIFEXITED( status ) == 0 ) {
       test_fail( __FILE__, __LINE__,
             "Child process didn't return true to WIFEXITED", 0 );
    }

    if ( waitpid( pid2, &status, 0 ) == -1 ) {
       perror( "waitpid()" );
       exit( 1 );
    }
    if ( WIFEXITED( status ) == 0 ) {
        test_fail( __FILE__, __LINE__,
              "Child process didn't return true to WIFEXITED", 0 );
    }

    /* This code isn't necessary as we know the child has exited, */
    /* it *may* return an error if the component so chooses. You  */
        /* should use read() instead. */

    printf( "Test case: multiple 3rd party attach start, stop.\n" );
    printf( "-----------------------------------------------\n" );
    tmp = PAPI_get_opt( PAPI_DEFDOM, NULL );
    printf( "Default domain is: %d (%s)\n", tmp, 
        stringify_all_domains( tmp ) );
    tmp = PAPI_get_opt( PAPI_DEFGRN, NULL );
    printf( "Default granularity is: %d (%s)\n", tmp,
            stringify_granularity( tmp ) );
    printf( "Using %d iterations of c += a*b\n", NUM_FLOPS );
    printf( "-------------------------------------------------------------------------\n" );

    sprintf( add_event_str, "(PID %jd) %-12s : \t", ( intmax_t ) pid,
             event_name );
    printf( TAB1, add_event_str, values[0][1] );
    sprintf( add_event_str, "(PID %jd) PAPI_TOT_CYC : \t", 
         ( intmax_t ) pid );
    printf( TAB1, add_event_str, values[0][0] );
    sprintf( add_event_str, "(PID %jd) %-12s : \t", ( intmax_t ) pid2,
             event_name );
    printf( TAB1, add_event_str,values[1][1] );
    sprintf( add_event_str, "(PID %jd) PAPI_TOT_CYC : \t", 
         ( intmax_t ) pid2 );
    printf( TAB1, add_event_str, values[1][0] );
    printf( TAB1, "Real usec    : \t", elapsed_us );
    printf( TAB1, "Real cycles  : \t", elapsed_cyc );
    printf( TAB1, "Virt usec    : \t", elapsed_virt_us );
    printf( TAB1, "Virt cycles  : \t", elapsed_virt_cyc );

    printf
        ( "-------------------------------------------------------------------------\n" );

    printf("Verification: pid %d results should be twice pid %d\n",pid2,pid );

    ratio1=(double)values[1][0]/(double)values[0][0];
    ratio2=(double)values[1][1]/(double)values[0][1];

    printf("\t%lld/%lld = %lf\n",values[1][0],values[0][0],ratio1);
    

    if ((ratio1 >2.15 ) || (ratio1 < 1.85)) {
      printf("Ratio out of range, should be ~2.0 not %lf\n",ratio1);
      test_fail( __FILE__, __LINE__,
            "Error: Counter ratio not two", 0 );
    }

    printf("\t%lld/%lld = %lf\n",values[1][1],values[0][1],ratio2);

    if ((ratio2 >2.75 ) || (ratio2 < 1.25)) {
      printf("Ratio out of range, should be ~2.0, not %lf\n",ratio2);
      test_fail( __FILE__, __LINE__,
            "Known issue: Counter ratio not two", 0 );
    }

    test_pass( __FILE__, values, num_tests );
    return 0;
}

Here is the call graph for this function:

int wait_for_attach_and_loop ( int  num)

Definition at line 31 of file multiattach.c.

{
    kill( getpid(  ), SIGSTOP );
    do_flops( NUM_FLOPS * num );
    kill( getpid(  ), SIGSTOP );
    return ( 0 );
}

Here is the call graph for this function:

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines