Blame src/ctests/multiattach.c

Packit 577717
/* This file performs the following test: start, stop and timer functionality for
Packit 577717
   multiple attached processes.
Packit 577717
Packit 577717
   - It attempts to use the following two counters. It may use less depending on
Packit 577717
     hardware counter resource limitations. These are counted in the default counting
Packit 577717
     domain and default granularity, depending on the platform. Usually this is 
Packit 577717
     the user domain (PAPI_DOM_USER) and thread context (PAPI_GRN_THR).
Packit 577717
     + PAPI_FP_INS
Packit 577717
     + PAPI_TOT_CYC
Packit 577717
   - Get us.
Packit 577717
   - Start counters
Packit 577717
   - Do flops
Packit 577717
   - Stop and read counters
Packit 577717
   - Get us.
Packit 577717
*/
Packit 577717
Packit 577717
#include <stdio.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <string.h>
Packit 577717
#include <unistd.h>
Packit 577717
#include <sys/ptrace.h>
Packit 577717
#include <sys/wait.h>
Packit 577717
#include <inttypes.h>
Packit 577717
Packit 577717
#include "papi.h"
Packit 577717
#include "papi_test.h"
Packit 577717
Packit 577717
#include "do_loops.h"
Packit 577717
Packit 577717
#ifdef _AIX
Packit 577717
#define _LINUX_SOURCE_COMPAT
Packit 577717
#endif
Packit 577717
Packit 577717
#if defined(__FreeBSD__)
Packit 577717
# define PTRACE_ATTACH PT_ATTACH
Packit 577717
# define PTRACE_CONT PT_CONTINUE
Packit 577717
#endif
Packit 577717
Packit 577717
#define MULTIPLIER	5
Packit 577717
Packit 577717
static int
Packit 577717
wait_for_attach_and_loop( int num )
Packit 577717
{
Packit 577717
	kill( getpid(  ), SIGSTOP );
Packit 577717
	do_flops( NUM_FLOPS * num );
Packit 577717
	kill( getpid(  ), SIGSTOP );
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
main( int argc, char **argv )
Packit 577717
{
Packit 577717
	int status, retval, num_tests = 2, tmp;
Packit 577717
	int EventSet1 = PAPI_NULL, EventSet2 = PAPI_NULL;
Packit 577717
	int PAPI_event, PAPI_event2, mask1, mask2;
Packit 577717
	int num_events1, num_events2;
Packit 577717
	long long **values;
Packit 577717
	long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc;
Packit 577717
	char event_name[PAPI_MAX_STR_LEN], add_event_str[PAPI_MAX_STR_LEN];
Packit 577717
	const PAPI_component_info_t *cmpinfo;
Packit 577717
	pid_t pid, pid2;
Packit 577717
	double ratio1,ratio2;
Packit 577717
Packit 577717
	/* Set TESTS_QUIET variable */
Packit 577717
	tests_quiet( argc, argv );
Packit 577717
Packit 577717
	/* Initialize the library */
Packit 577717
	retval = PAPI_library_init( PAPI_VER_CURRENT );
Packit 577717
	if ( retval != PAPI_VER_CURRENT ) {
Packit 577717
	   test_fail( __FILE__, __LINE__, "PAPI_library_init", retval );
Packit 577717
	}
Packit 577717
Packit 577717
	/* get the component info and check if we support attach */
Packit 577717
	if ( ( cmpinfo = PAPI_get_component_info( 0 ) ) == NULL ) {
Packit 577717
	   test_fail( __FILE__, __LINE__, "PAPI_get_component_info", 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	if ( cmpinfo->attach == 0 ) {
Packit 577717
	   test_skip( __FILE__, __LINE__,
Packit 577717
		      "Platform does not support attaching", 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	/* fork off first child */
Packit 577717
	pid = fork(  );
Packit 577717
	if ( pid < 0 ) {
Packit 577717
	   test_fail( __FILE__, __LINE__, "fork()", PAPI_ESYS );
Packit 577717
	}
Packit 577717
	if ( pid == 0 ) {
Packit 577717
	   exit( wait_for_attach_and_loop( 1 ) );
Packit 577717
	}
Packit 577717
Packit 577717
	/* fork off second child, does twice as much */
Packit 577717
	pid2 = fork(  );
Packit 577717
	if ( pid2 < 0 ) {
Packit 577717
	   test_fail( __FILE__, __LINE__, "fork()", PAPI_ESYS );
Packit 577717
	}
Packit 577717
	if ( pid2 == 0 ) {
Packit 577717
	   exit( wait_for_attach_and_loop( MULTIPLIER ) );
Packit 577717
	}
Packit 577717
Packit 577717
	/* add PAPI_TOT_CYC and one of the events in
Packit 577717
           PAPI_FP_INS, PAPI_FP_OPS or PAPI_TOT_INS,
Packit 577717
           depending on the availability of the event
Packit 577717
           on the platform                            */
Packit 577717
	EventSet1 = add_two_events( &num_events1, &PAPI_event, &mask1 );
Packit 577717
	EventSet2 = add_two_events( &num_events2, &PAPI_event2, &mask2 );
Packit 577717
Packit 577717
	if ( cmpinfo->attach_must_ptrace ) {
Packit 577717
	   if ( ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_ATTACH)" );
Packit 577717
	      return 1 ;
Packit 577717
	   }
Packit 577717
	   if ( waitpid( pid, &status, 0 ) == -1 ) {
Packit 577717
	      perror( "waitpid()" );
Packit 577717
	      exit( 1 );
Packit 577717
	   }
Packit 577717
	   if ( WIFSTOPPED( status ) == 0 ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didnt return true to WIFSTOPPED", 0 );
Packit 577717
	   }
Packit 577717
Packit 577717
	   if ( ptrace( PTRACE_ATTACH, pid2, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_ATTACH)" );
Packit 577717
	      return 1;
Packit 577717
	   }
Packit 577717
	   if ( waitpid( pid2, &status, 0 ) == -1 ) {
Packit 577717
	      perror( "waitpid()" );
Packit 577717
	      exit( 1 );
Packit 577717
	   }
Packit 577717
	   if ( WIFSTOPPED( status ) == 0 ) {
Packit 577717
 	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didnt return true to WIFSTOPPED", 0 );
Packit 577717
	   }
Packit 577717
	}
Packit 577717
Packit 577717
	retval = PAPI_attach( EventSet1, ( unsigned long ) pid );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
	   test_fail( __FILE__, __LINE__, "PAPI_attach", retval );
Packit 577717
	}
Packit 577717
Packit 577717
	retval = PAPI_attach( EventSet2, ( unsigned long ) pid2 );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
	   test_fail( __FILE__, __LINE__, "PAPI_attach", retval );
Packit 577717
	}
Packit 577717
Packit 577717
	strcpy(event_name, "PAPI_TOT_INS");
Packit 577717
	sprintf( add_event_str, "PAPI_add_event[%s]", event_name );
Packit 577717
Packit 577717
	/* num_events1 is greater than num_events2 so don't worry. */
Packit 577717
Packit 577717
	values = allocate_test_space( num_tests, num_events1 );
Packit 577717
Packit 577717
	/* Gather before values */
Packit 577717
	elapsed_us = PAPI_get_real_usec(  );
Packit 577717
	elapsed_cyc = PAPI_get_real_cyc(  );
Packit 577717
	elapsed_virt_us = PAPI_get_virt_usec(  );
Packit 577717
	elapsed_virt_cyc = PAPI_get_virt_cyc(  );
Packit 577717
Packit 577717
	/* Wait for the SIGSTOP. */
Packit 577717
	if ( cmpinfo->attach_must_ptrace ) {
Packit 577717
	   if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_CONT)" );
Packit 577717
	      return 1;
Packit 577717
	   }
Packit 577717
	   if ( waitpid( pid, &status, 0 ) == -1 ) {
Packit 577717
	      perror( "waitpid()" );
Packit 577717
	      exit( 1 );
Packit 577717
	   }
Packit 577717
	   if ( WIFSTOPPED( status ) == 0 ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't return true to WIFSTOPPED", 0 );
Packit 577717
	   }
Packit 577717
	   if ( WSTOPSIG( status ) != SIGSTOP ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't stop on SIGSTOP", 0 );
Packit 577717
	   }
Packit 577717
Packit 577717
	   if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_CONT)" );
Packit 577717
	      return 1;
Packit 577717
	   }
Packit 577717
	   if ( waitpid( pid2, &status, 0 ) == -1 ) {
Packit 577717
	      perror( "waitpid()" );
Packit 577717
	      exit( 1 );
Packit 577717
	   }
Packit 577717
	   if ( WIFSTOPPED( status ) == 0 ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't return true to WIFSTOPPED", 0 );
Packit 577717
	   }
Packit 577717
	   if ( WSTOPSIG( status ) != SIGSTOP ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't stop on SIGSTOP", 0 );
Packit 577717
	   }
Packit 577717
	}
Packit 577717
Packit 577717
	/* start measuring in first child */
Packit 577717
	retval = PAPI_start( EventSet1 );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
		test_fail( __FILE__, __LINE__, "PAPI_start", retval );
Packit 577717
	}
Packit 577717
Packit 577717
	/* start measuring in second child */
Packit 577717
	retval = PAPI_start( EventSet2 );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
		test_fail( __FILE__, __LINE__, "PAPI_start", retval );
Packit 577717
	}
Packit 577717
Packit 577717
		/* Start first child and Wait for the SIGSTOP. */
Packit 577717
	if ( cmpinfo->attach_must_ptrace ) {
Packit 577717
	   if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_ATTACH)" );
Packit 577717
	      return 1;
Packit 577717
	   }
Packit 577717
	   if ( waitpid( pid, &status, 0 ) == -1 ) {
Packit 577717
	      perror( "waitpid()" );
Packit 577717
	      exit( 1 );
Packit 577717
	   }
Packit 577717
	   if ( WIFSTOPPED( status ) == 0 ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't return true to WIFSTOPPED", 0 );
Packit 577717
	   }
Packit 577717
	   if ( WSTOPSIG( status ) != SIGSTOP ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't stop on SIGSTOP", 0 );
Packit 577717
	   }
Packit 577717
Packit 577717
		/* Start second child and Wait for the SIGSTOP. */
Packit 577717
	   if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
Packit 577717
	       perror( "ptrace(PTRACE_ATTACH)" );
Packit 577717
	       return 1;
Packit 577717
	   }
Packit 577717
	   if ( waitpid( pid2, &status, 0 ) == -1 ) {
Packit 577717
	      perror( "waitpid()" );
Packit 577717
	      exit( 1 );
Packit 577717
	   }
Packit 577717
	   if ( WIFSTOPPED( status ) == 0 ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't return true to WIFSTOPPED", 0 );
Packit 577717
	   }
Packit 577717
	   if ( WSTOPSIG( status ) != SIGSTOP ) {
Packit 577717
	      test_fail( __FILE__, __LINE__,
Packit 577717
			"Child process didn't stop on SIGSTOP", 0 );
Packit 577717
	   }
Packit 577717
	}
Packit 577717
Packit 577717
	elapsed_virt_us = PAPI_get_virt_usec(  ) - elapsed_virt_us;
Packit 577717
	elapsed_virt_cyc = PAPI_get_virt_cyc(  ) - elapsed_virt_cyc;
Packit 577717
	elapsed_us = PAPI_get_real_usec(  ) - elapsed_us;
Packit 577717
	elapsed_cyc = PAPI_get_real_cyc(  ) - elapsed_cyc;
Packit 577717
Packit 577717
	/* stop measuring and read first child */
Packit 577717
	retval = PAPI_stop( EventSet1, values[0] );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
	   printf( "Warning: PAPI_stop returned error %d, probably ok.\n",
Packit 577717
				retval );
Packit 577717
	}
Packit 577717
Packit 577717
	/* stop measuring and read second child */
Packit 577717
	retval = PAPI_stop( EventSet2, values[1] );
Packit 577717
	if ( retval != PAPI_OK ) {
Packit 577717
	   printf( "Warning: PAPI_stop returned error %d, probably ok.\n",
Packit 577717
				retval );
Packit 577717
	}
Packit 577717
Packit 577717
	/* close down the measurements */
Packit 577717
	remove_test_events( &EventSet1, mask1 );
Packit 577717
	remove_test_events( &EventSet2, mask2 );
Packit 577717
Packit 577717
	/* restart events so they can end */
Packit 577717
	if ( cmpinfo->attach_must_ptrace ) {
Packit 577717
	   if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_CONT)" );
Packit 577717
	      return 1;
Packit 577717
	   }
Packit 577717
	   if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) {
Packit 577717
	      perror( "ptrace(PTRACE_CONT)" );
Packit 577717
	      return 1;
Packit 577717
	   }
Packit 577717
	}
Packit 577717
Packit 577717
	if ( waitpid( pid, &status, 0 ) == -1 ) {
Packit 577717
	   perror( "waitpid()" );
Packit 577717
	   exit( 1 );
Packit 577717
	}
Packit 577717
	if ( WIFEXITED( status ) == 0 ) {
Packit 577717
	   test_fail( __FILE__, __LINE__,
Packit 577717
		     "Child process didn't return true to WIFEXITED", 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	if ( waitpid( pid2, &status, 0 ) == -1 ) {
Packit 577717
	   perror( "waitpid()" );
Packit 577717
	   exit( 1 );
Packit 577717
	}
Packit 577717
	if ( WIFEXITED( status ) == 0 ) {
Packit 577717
		test_fail( __FILE__, __LINE__,
Packit 577717
			  "Child process didn't return true to WIFEXITED", 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	/* This code isn't necessary as we know the child has exited, */
Packit 577717
	/* it *may* return an error if the component so chooses. You  */
Packit 577717
        /* should use read() instead. */
Packit 577717
Packit 577717
	if (!TESTS_QUIET) {
Packit 577717
		printf( "Test case: multiple 3rd party attach start, stop.\n" );
Packit 577717
		printf( "-----------------------------------------------\n" );
Packit 577717
		tmp = PAPI_get_opt( PAPI_DEFDOM, NULL );
Packit 577717
		printf( "Default domain is: %d (%s)\n", tmp,
Packit 577717
			stringify_all_domains( tmp ) );
Packit 577717
		tmp = PAPI_get_opt( PAPI_DEFGRN, NULL );
Packit 577717
		printf( "Default granularity is: %d (%s)\n", tmp,
Packit 577717
			stringify_granularity( tmp ) );
Packit 577717
		printf( "Using %d iterations of c += a*b\n", NUM_FLOPS );
Packit 577717
		printf( "-------------------------------------------------------------------------\n" );
Packit 577717
Packit 577717
		sprintf( add_event_str, "(PID %jd) %-12s : \t", ( intmax_t ) pid,
Packit 577717
				 event_name );
Packit 577717
		printf( TAB1, add_event_str, values[0][1] );
Packit 577717
		sprintf( add_event_str, "(PID %jd) PAPI_TOT_CYC : \t",
Packit 577717
			 ( intmax_t ) pid );
Packit 577717
		printf( TAB1, add_event_str, values[0][0] );
Packit 577717
		sprintf( add_event_str, "(PID %jd) %-12s : \t", ( intmax_t ) pid2,
Packit 577717
			 event_name );
Packit 577717
		printf( TAB1, add_event_str,values[1][1] );
Packit 577717
		sprintf( add_event_str, "(PID %jd) PAPI_TOT_CYC : \t",
Packit 577717
			 ( intmax_t ) pid2 );
Packit 577717
		printf( TAB1, add_event_str, values[1][0] );
Packit 577717
		printf( TAB1, "Real usec    : \t", elapsed_us );
Packit 577717
		printf( TAB1, "Real cycles  : \t", elapsed_cyc );
Packit 577717
		printf( TAB1, "Virt usec    : \t", elapsed_virt_us );
Packit 577717
		printf( TAB1, "Virt cycles  : \t", elapsed_virt_cyc );
Packit 577717
Packit 577717
		printf( "-------------------------------------------------------------------------\n" );
Packit 577717
Packit 577717
		printf("Verification: pid %d results should be %dx pid %d\n",
Packit 577717
			pid2,MULTIPLIER,pid );
Packit 577717
	}
Packit 577717
Packit 577717
	/* FLOPS ratio */
Packit 577717
	ratio1=(double)values[1][0]/(double)values[0][0];
Packit 577717
Packit 577717
	/* CYCLES ratio */
Packit 577717
	ratio2=(double)values[1][1]/(double)values[0][1];
Packit 577717
Packit 577717
	if (!TESTS_QUIET) {
Packit 577717
		printf("\tFLOPS ratio %lld/%lld = %lf\n",
Packit 577717
			values[1][0],values[0][0],ratio1);
Packit 577717
	}
Packit 577717
Packit 577717
	double ratio1_high,ratio1_low,ratio2_high,ratio2_low;
Packit 577717
Packit 577717
	ratio1_high=(double)MULTIPLIER *1.10;
Packit 577717
	ratio1_low=(double)MULTIPLIER * 0.90;
Packit 577717
Packit 577717
	if ((ratio1 > ratio1_high ) || (ratio1 < ratio1_low)) {
Packit 577717
	  printf("Ratio out of range, should be ~%lf not %lf\n",
Packit 577717
		(double)MULTIPLIER, ratio1);
Packit 577717
	  test_fail( __FILE__, __LINE__,
Packit 577717
		    "Error: Counter ratio not two", 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	if (!TESTS_QUIET) {
Packit 577717
		printf("\tCycles ratio %lld/%lld = %lf\n",
Packit 577717
			values[1][1],values[0][1],ratio2);
Packit 577717
	}
Packit 577717
Packit 577717
	ratio2_high=(double)MULTIPLIER *1.20;
Packit 577717
	ratio2_low=(double)MULTIPLIER * 0.80;
Packit 577717
Packit 577717
	if ((ratio2 > ratio2_high ) || (ratio2 < ratio2_low )) {
Packit 577717
	  printf("Ratio out of range, should be ~%lf, not %lf\n",
Packit 577717
		(double)MULTIPLIER, ratio2);
Packit 577717
	  test_fail( __FILE__, __LINE__,
Packit 577717
		    "Known issue: Counter ratio not two", 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	test_pass( __FILE__ );
Packit 577717
Packit 577717
	return 0;
Packit 577717
}