Blame SOURCES/papi-rhbz1807346.patch

7671e6
commit 660bfd20bc89a26629e99de958d38b031db4250d
7671e6
Author: William Cohen <wcohen@redhat.com>
7671e6
Date:   Thu Oct 31 15:30:00 2019 -0400
7671e6
7671e6
    This code is a modification of krentel_pthreads.c, to better test
7671e6
    some race conditions. It is not included in the standard tests;
7671e6
    it is a diagnostic that should be run with "valgrind --tool=helgrind".
7671e6
    
7671e6
    Signed-off-by: Anthony Castaldo <TonyCastaldo@icl.utk.edu>
7671e6
7671e6
diff --git a/src/ctests/krentel_pthreads_race.c b/src/ctests/krentel_pthreads_race.c
7671e6
new file mode 100644
7671e6
index 000000000..0ebfb5056
7671e6
--- /dev/null
7671e6
+++ b/src/ctests/krentel_pthreads_race.c
7671e6
@@ -0,0 +1,236 @@
7671e6
+/*
7671e6
+ *  Test PAPI with multiple threads.
7671e6
+ *  This code is a modification of krentel_pthreads.c by William Cohen
7671e6
+ *  <wcohen@redhat.com>, on Sep 10 2019, to exercise and test for the race
7671e6
+ *  condition in papi_internal.c involving the formerly static variables
7671e6
+ *  papi_event_code and papi_event_code_changed.  This code should be run with
7671e6
+ *  "valgrind --tool=helgrind" to show any data races. If run with:
7671e6
+ *  "valgrind --tool=helgrind --log-file=helgrind_out.txt"
7671e6
+ *  The output will be captured in helgrind_out.txt and can then be processed
7671e6
+ *  with the program filter_helgrind.c; see commentary at the top of that file.
7671e6
+ */
7671e6
+
7671e6
+#define MAX_THREADS 256
7671e6
+
7671e6
+#include <stdio.h>
7671e6
+#include <stdlib.h>
7671e6
+#include <pthread.h>
7671e6
+#include <sys/time.h>
7671e6
+
7671e6
+#include "papi.h"
7671e6
+#include "papi_test.h"
7671e6
+
7671e6
+#define EVENT  PAPI_TOT_CYC
7671e6
+
7671e6
+static int program_time = 5;
7671e6
+static int threshold = 20000000;
7671e6
+static int num_threads = 3;
7671e6
+
7671e6
+static long count[MAX_THREADS];
7671e6
+static long iter[MAX_THREADS];
7671e6
+static struct timeval last[MAX_THREADS];
7671e6
+
7671e6
+static pthread_key_t key;
7671e6
+
7671e6
+static struct timeval start;
7671e6
+
7671e6
+static void
7671e6
+my_handler( int EventSet, void *pc, long long ovec, void *context )
7671e6
+{
7671e6
+	( void ) EventSet;
7671e6
+	( void ) pc;
7671e6
+	( void ) ovec;
7671e6
+	( void ) context;
7671e6
+
7671e6
+	long num = ( long ) pthread_getspecific( key );
7671e6
+
7671e6
+	if ( num < 0 || num > num_threads )
7671e6
+		test_fail( __FILE__, __LINE__, "getspecific failed", 1 );
7671e6
+	count[num]++;
7671e6
+}
7671e6
+
7671e6
+static void
7671e6
+print_rate( long num )
7671e6
+{
7671e6
+	struct timeval now;
7671e6
+	long st_secs;
7671e6
+	double last_secs;
7671e6
+
7671e6
+	gettimeofday( &now, NULL );
7671e6
+	st_secs = now.tv_sec - start.tv_sec;
7671e6
+	last_secs = ( double ) ( now.tv_sec - last[num].tv_sec )
7671e6
+		+ ( ( double ) ( now.tv_usec - last[num].tv_usec ) ) / 1000000.0;
7671e6
+	if ( last_secs <= 0.001 )
7671e6
+		last_secs = 0.001;
7671e6
+
7671e6
+	if (!TESTS_QUIET) {
7671e6
+		printf( "[%ld] time = %ld, count = %ld, iter = %ld, "
7671e6
+			"rate = %.1f/Kiter\n",
7671e6
+			num, st_secs, count[num], iter[num],
7671e6
+			( 1000.0 * ( double ) count[num] ) / ( double ) iter[num] );
7671e6
+	}
7671e6
+
7671e6
+	count[num] = 0;
7671e6
+	iter[num] = 0;
7671e6
+	last[num] = now;
7671e6
+}
7671e6
+
7671e6
+static void
7671e6
+do_cycles( long num, int len )
7671e6
+{
7671e6
+	struct timeval start, now;
7671e6
+	double x, sum;
7671e6
+
7671e6
+	gettimeofday( &start, NULL );
7671e6
+
7671e6
+	for ( ;; ) {
7671e6
+		sum = 1.0;
7671e6
+		for ( x = 1.0; x < 250000.0; x += 1.0 )
7671e6
+			sum += x;
7671e6
+		if ( sum < 0.0 )
7671e6
+			printf( "==>>  SUM IS NEGATIVE !!  <<==\n" );
7671e6
+
7671e6
+		iter[num]++;
7671e6
+
7671e6
+		gettimeofday( &now, NULL );
7671e6
+		if ( now.tv_sec >= start.tv_sec + len )
7671e6
+			break;
7671e6
+	}
7671e6
+}
7671e6
+
7671e6
+static void *
7671e6
+my_thread( void *v )
7671e6
+{
7671e6
+	long num = ( long ) v;
7671e6
+	int n;
7671e6
+	int EventSet = PAPI_NULL;
7671e6
+	int event_code;
7671e6
+	long long value;
7671e6
+
7671e6
+	int retval;
7671e6
+
7671e6
+	retval = PAPI_register_thread(  );
7671e6
+	if ( retval != PAPI_OK ) {
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_register_thread", retval );
7671e6
+	}
7671e6
+	pthread_setspecific( key, v );
7671e6
+
7671e6
+	count[num] = 0;
7671e6
+	iter[num] = 0;
7671e6
+	last[num] = start;
7671e6
+
7671e6
+	retval = PAPI_create_eventset( &EventSet );
7671e6
+	if ( retval != PAPI_OK ) {
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_create_eventset failed", retval );
7671e6
+	}
7671e6
+
7671e6
+	retval = PAPI_event_name_to_code("PAPI_TOT_CYC", &event_code);
7671e6
+	if (retval != PAPI_OK ) {
7671e6
+		if (!TESTS_QUIET) printf("Trouble creating event name\n");
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_event_name_to_code failed", retval );
7671e6
+	}
7671e6
+
7671e6
+	retval = PAPI_add_event( EventSet, EVENT );
7671e6
+	if (retval != PAPI_OK ) {
7671e6
+		if (!TESTS_QUIET) printf("Trouble adding event\n");
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_add_event failed", retval );
7671e6
+	}
7671e6
+
7671e6
+	if ( PAPI_overflow( EventSet, EVENT, threshold, 0, my_handler ) != PAPI_OK )
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_overflow failed", 1 );
7671e6
+
7671e6
+	if ( PAPI_start( EventSet ) != PAPI_OK )
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_start failed", 1 );
7671e6
+
7671e6
+	if (!TESTS_QUIET) printf( "launched timer in thread %ld\n", num );
7671e6
+
7671e6
+	for ( n = 1; n <= program_time; n++ ) {
7671e6
+		do_cycles( num, 1 );
7671e6
+		print_rate( num );
7671e6
+	}
7671e6
+
7671e6
+	PAPI_stop( EventSet, &value );
7671e6
+
7671e6
+        retval = PAPI_overflow( EventSet, EVENT, 0, 0, my_handler);
7671e6
+	if ( retval != PAPI_OK )
7671e6
+            test_fail( __FILE__, __LINE__, "PAPI_overflow failed to reset the overflow handler", retval );
7671e6
+
7671e6
+	if ( PAPI_remove_event( EventSet, EVENT ) != PAPI_OK ) 
7671e6
+	    test_fail( __FILE__, __LINE__, "PAPI_remove_event", 1 );
7671e6
+
7671e6
+	if ( PAPI_destroy_eventset( &EventSet ) != PAPI_OK ) 
7671e6
+	    test_fail( __FILE__, __LINE__, "PAPI_destroy_eventset", 1 );
7671e6
+
7671e6
+	if ( PAPI_unregister_thread( ) != PAPI_OK ) 
7671e6
+            test_fail( __FILE__, __LINE__, "PAPI_unregister_thread", 1 );
7671e6
+
7671e6
+	return ( NULL );
7671e6
+}
7671e6
+
7671e6
+int
7671e6
+main( int argc, char **argv )
7671e6
+{
7671e6
+	pthread_t *td = NULL;
7671e6
+	long n;
7671e6
+	int quiet,retval;
7671e6
+
7671e6
+	/* Set TESTS_QUIET variable */
7671e6
+	quiet=tests_quiet( argc, argv );
7671e6
+
7671e6
+	if ( argc < 2 || sscanf( argv[1], "%d", &program_time ) < 1 )
7671e6
+		program_time = 6;
7671e6
+	if ( argc < 3 || sscanf( argv[2], "%d", &threshold ) < 1 )
7671e6
+		threshold = 20000000;
7671e6
+	if ( argc < 4 || sscanf( argv[3], "%d", &num_threads ) < 1 )
7671e6
+		num_threads = 32;
7671e6
+
7671e6
+	td = malloc((num_threads+1) * sizeof(pthread_t));
7671e6
+	if (!td) {
7671e6
+		test_fail( __FILE__, __LINE__, "td malloc failed", 1 );
7671e6
+	}
7671e6
+
7671e6
+	if (!quiet) {
7671e6
+		printf( "program_time = %d, threshold = %d, num_threads = %d\n\n",
7671e6
+			program_time, threshold, num_threads );
7671e6
+	}
7671e6
+
7671e6
+	if ( PAPI_library_init( PAPI_VER_CURRENT ) != PAPI_VER_CURRENT )
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_library_init failed", 1 );
7671e6
+
7671e6
+	/* Test to be sure we can add events */
7671e6
+	retval = PAPI_query_event( EVENT );
7671e6
+	if (retval!=PAPI_OK) {
7671e6
+		if (!quiet) printf("Trouble finding event\n");
7671e6
+		test_skip(__FILE__,__LINE__,"Event not available",1);
7671e6
+	}
7671e6
+
7671e6
+	if ( PAPI_thread_init( ( unsigned long ( * )( void ) ) ( pthread_self ) ) !=
7671e6
+		 PAPI_OK )
7671e6
+		test_fail( __FILE__, __LINE__, "PAPI_thread_init failed", 1 );
7671e6
+
7671e6
+	if ( pthread_key_create( &key, NULL ) != 0 )
7671e6
+		test_fail( __FILE__, __LINE__, "pthread key create failed", 1 );
7671e6
+
7671e6
+	gettimeofday( &start, NULL );
7671e6
+
7671e6
+	for ( n = 1; n <= num_threads; n++ ) {
7671e6
+		if ( pthread_create( &(td[n]), NULL, my_thread, ( void * ) n ) != 0 )
7671e6
+			test_fail( __FILE__, __LINE__, "pthread create failed", 1 );
7671e6
+	}
7671e6
+
7671e6
+	my_thread( ( void * ) 0 );
7671e6
+
7671e6
+	/* wait for all the threads */
7671e6
+	for ( n = 1; n <= num_threads; n++ ) {
7671e6
+	  	if ( pthread_join( td[n], NULL))
7671e6
+			test_fail( __FILE__, __LINE__, "pthread join failed", 1 );
7671e6
+	}
7671e6
+
7671e6
+	free(td);
7671e6
+
7671e6
+	if (!quiet) printf( "done\n" );
7671e6
+
7671e6
+	test_pass( __FILE__ );
7671e6
+
7671e6
+	return 0;
7671e6
+}
7671e6
commit 979e80136fd5e0ee2fb26f7374b36a8433147a68
7671e6
Author: Anthony Castaldo <TonyCastaldo@icl.utk.edu>
7671e6
Date:   Thu Oct 31 15:56:55 2019 -0400
7671e6
7671e6
    The changes to papi.c, papi_internal.c, threads.h and threads.c
7671e6
    correct a race condition that was the result of all threads using
7671e6
    the same two static variables (papi_event_code and papi_event_code_changed)
7671e6
    to temporarily record a state of operation. The solution was to
7671e6
    make these variables unique per thread, using the ThreadInfo_t
7671e6
    structure already provided in PAPI for such purposes. The file
7671e6
    krentel_pthread_race.c is a stress test to produce race conditions.
7671e6
    filter_helgrind.c reduces the volume of --tool-helgrind output to
7671e6
    a more manageable summary. Both are added to Makefile.recipies.
7671e6
7671e6
diff --git a/src/ctests/Makefile.recipies b/src/ctests/Makefile.recipies
7671e6
index 87340831d..b7c1963d7 100644
7671e6
--- a/src/ctests/Makefile.recipies
7671e6
+++ b/src/ctests/Makefile.recipies
7671e6
@@ -161,6 +161,12 @@ locks_pthreads: locks_pthreads.c $(TESTLIB) $(PAPILIB)
7671e6
 krentel_pthreads: krentel_pthreads.c $(TESTLIB) $(PAPILIB)
7671e6
 	$(CC_R) $(INCLUDE) $(CFLAGS) $(TOPTFLAGS) krentel_pthreads.c $(TESTLIB) $(PAPILIB) $(LDFLAGS) -o krentel_pthreads -lpthread
7671e6
 
7671e6
+# krentel_pthreads_race is not included with the standard tests;
7671e6
+# it is a modification of krentel_pthreads intended to be run with 
7671e6
+# "valgrind --tool=helgrind" to test for race conditions.
7671e6
+krentel_pthreads_race: krentel_pthreads_race.c $(TESTLIB) $(PAPILIB)
7671e6
+	$(CC_R) $(INCLUDE) $(CFLAGS) $(TOPTFLAGS) krentel_pthreads_race.c $(TESTLIB) $(PAPILIB) $(LDFLAGS) -o krentel_pthreads_race -lpthread
7671e6
+
7671e6
 overflow_pthreads: overflow_pthreads.c $(TESTLIB) $(DOLOOPS) $(PAPILIB)
7671e6
 	$(CC_R) $(INCLUDE) $(CFLAGS) $(TOPTFLAGS) overflow_pthreads.c $(TESTLIB) $(DOLOOPS) $(PAPILIB) $(LDFLAGS) -o overflow_pthreads -lpthread
7671e6
 
7671e6
@@ -434,6 +440,9 @@ forkexec4: forkexec4.c $(TESTLIB) $(PAPILIB)
7671e6
 prof_utils.o: prof_utils.c $(testlibdir)/papi_test.h prof_utils.h
7671e6
 	$(CC) $(INCLUDE) $(CFLAGS) $(TOPTFLAGS) -c prof_utils.c
7671e6
 
7671e6
+filter_helgrind: filter_helgrind.c $(TESTLIB) $(PAPILIB)
7671e6
+	-$(CC) $(INCLUDE) $(CFLAGS) $(TOPTFLAGS) filter_helgrind.c $(TESTLIB) $(PAPILIB) $(LDFLAGS) -o filter_helgrind 
7671e6
+
7671e6
 .PHONY : all default ctests ctest clean
7671e6
 
7671e6
 clean:
7671e6
diff --git a/src/ctests/filter_helgrind.c b/src/ctests/filter_helgrind.c
7671e6
new file mode 100644
7671e6
index 000000000..d918a789e
7671e6
--- /dev/null
7671e6
+++ b/src/ctests/filter_helgrind.c
7671e6
@@ -0,0 +1,170 @@
7671e6
+/*
7671e6
+ *  This code is a simple filter for the helgrind_out.txt file
7671e6
+ *  produced by:
7671e6
+ *  "valgrind --tool=helgrind --log-file=helgrind_out.txt someProgram"
7671e6
+ *
7671e6
+ * This is useful because the tool does not recognize PAPI locks,
7671e6
+ * thus reports as possible race conditions reads/writes by
7671e6
+ * different threads that are actually fine (surrounded by locks).
7671e6
+ *
7671e6
+ * This was written particularly for krentel_pthreads_race.c 
7671e6
+ * when processed by the above valgrind. We produce a line per
7671e6
+ * condition, in the form:
7671e6
+ * OP@file:line OP@file:line
7671e6
+ * where OP is R or W. The first file:line code occurred
7671e6
+ * after the second file:line code, and on a different thread.
7671e6
+ * 
7671e6
+ * We print the results to stdout. It is useful to filter this
7671e6
+ * through the standard utility 'uniq', each occurrence only 
7671e6
+ * needs to be investigated once. Just insure there are
7671e6
+ * MATCHING locks around each operation within the code.
7671e6
+ *
7671e6
+ * An example run (using uniq): The options -uc will print 
7671e6
+ * only unique lines, preceeded by a count of how many times
7671e6
+ * it occurs.
7671e6
+ *
7671e6
+ * ./filter_helgrind | uniq -uc
7671e6
+ *
7671e6
+ * An example output line (piped through uniq as above):
7671e6
+ *       1 R@threads.c:190                    W@threads.c:206
7671e6
+ * An investigation shows threads.c:190 is protected by 
7671e6
+ * _papi_hwi_lock(THREADS_LOCK); and threads.c:206 is
7671e6
+ * protected by the same lock. Thus no data race can 
7671e6
+ * occur for this instance.
7671e6
+ *
7671e6
+ * Compilation within the papi/src/ctests directory:
7671e6
+ * make filter_helgrind
7671e6
+ * 
7671e6
+ */
7671e6
+
7671e6
+#include <stdio.h>
7671e6
+#include <stdlib.h>
7671e6
+#include <string.h>
7671e6
+
7671e6
+int main(int argc, char** args) {
7671e6
+   (void) argc;
7671e6
+   (void) args;
7671e6
+
7671e6
+   char myLine[16384];
7671e6
+   int state, size;
7671e6
+   char type1, type2;
7671e6
+   char fname1[256], fname2[256];
7671e6
+   char *paren1, *paren2;
7671e6
+
7671e6
+   FILE *HELOUT = fopen("helgrind_out.txt", "r");  // Read the file.
7671e6
+   if (HELOUT == NULL) {
7671e6
+      fprintf(stderr, "Could not open helgrind_out.txt.\n");
7671e6
+      exit(-1);
7671e6
+   }
7671e6
+
7671e6
+   char PDRR[]="Possible data race during read";
7671e6
+   char PDRW[]="Possible data race during write";
7671e6
+   char TCWW[]="This conflicts with a previous write";
7671e6
+   char TCWR[]="This conflicts with a previous read";
7671e6
+   char atSTR[]="   at ";
7671e6
+
7671e6
+   // State machine:
7671e6
+   // State 0: We are looking for a line with PDRR or PDRW.
7671e6
+   //          We don't exit until we find it, or run out of lines.
7671e6
+   //          if we find it, we remember which and go to state 1.
7671e6
+   // State 1: Looking for "   at " in column 11. 
7671e6
+   //          When found, we extract the string betweeen '(' and ')'
7671e6
+   //          which is program name:line. go to state 2.
7671e6
+   // State 2: We are searching for TCWW, TCWR, PDRW, PDRR.
7671e6
+   //          If we find the first two:
7671e6
+   //             Remember which, and go to state 3.
7671e6
+   //          If we find either of the second two, go back to State 1.
7671e6
+   // State 3: Looking for "   at " in column 11.
7671e6
+   //          When found, extract the string betweeen '(' and ')',
7671e6
+   //          which is program name:line.
7671e6
+   //          OUTPUT LINE for an investigation.
7671e6
+   //          Go to State 0.
7671e6
+
7671e6
+   state = 0;        // looking for PDRR, PDRW. 
7671e6
+   while (fgets(myLine, 16384, HELOUT) != NULL) {
7671e6
+      if (strlen(myLine) < 20) continue;
7671e6
+      switch (state) {
7671e6
+         case 0:  // Looking for PDRR or PRDW.
7671e6
+            if (strstr(myLine, PDRR) != NULL) { 
7671e6
+               type1='R';
7671e6
+               state=1;
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            if (strstr(myLine, PDRW) != NULL) {
7671e6
+               type1='W';
7671e6
+               state=1;
7671e6
+               continue;
7671e6
+            }
7671e6
+      
7671e6
+            continue;
7671e6
+            break;
7671e6
+
7671e6
+         case 1: // Looking for atSTR in column 11.
7671e6
+            if (strncmp(myLine+10, atSTR, 6) != 0) continue;
7671e6
+            paren1=strchr(myLine, '(');
7671e6
+            paren2=strchr(myLine, ')');
7671e6
+            if (paren1 == NULL || paren2 == NULL ||
7671e6
+                paren1 > paren2) {
7671e6
+               state=0;             // Abort, found something I don't understand.
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            size = paren2-paren1-1;          // compute length of name.
7671e6
+            strncpy(fname1, paren1+1, size); // Copy the name.
7671e6
+            fname1[size]=0;                  // install z-terminator.
7671e6
+            state=2;
7671e6
+            continue;
7671e6
+            break;
7671e6
+
7671e6
+         case 2: // Looking for TCWW, TCWR, PDRR, PDRW.
7671e6
+            if (strstr(myLine, TCWR) != NULL) {
7671e6
+               type2='R';
7671e6
+               state=3;
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            if (strstr(myLine, TCWW) != NULL) { 
7671e6
+               type2='W';
7671e6
+               state=3;
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            if (strstr(myLine, PDRR) != NULL) { 
7671e6
+               type1='R';
7671e6
+               state=1;
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            if (strstr(myLine, PDRW) != NULL) {
7671e6
+               type1='W';
7671e6
+               state=1;
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            continue;
7671e6
+            break;
7671e6
+
7671e6
+         case 3: // Looking for atSTR in column 11.
7671e6
+            if (strncmp(myLine+10, atSTR, 6) != 0) continue;
7671e6
+            paren1=strchr(myLine, '(');
7671e6
+            paren2=strchr(myLine, ')');
7671e6
+            if (paren1 == NULL || paren2 == NULL ||
7671e6
+                paren1 > paren2) {
7671e6
+               state=0;             // Abort, found something I don't understand.
7671e6
+               continue;
7671e6
+            }
7671e6
+
7671e6
+            size = paren2-paren1-1;          // compute length of name.
7671e6
+            strncpy(fname2, paren1+1, size); // Copy the name.
7671e6
+            fname2[size]=0;                  // install z-terminator.
7671e6
+            fprintf(stdout, "%c@%-32s %c@%-32s\n", type1, fname1, type2, fname2);
7671e6
+            state=0;
7671e6
+            continue;
7671e6
+            break;
7671e6
+      } // end switch.
7671e6
+   } // end while.
7671e6
+   
7671e6
+   fclose(HELOUT);
7671e6
+   exit(0);
7671e6
+}  
7671e6
diff --git a/src/papi.c b/src/papi.c
7671e6
index 4e08dc840..070e3f8c6 100644
7671e6
--- a/src/papi.c
7671e6
+++ b/src/papi.c
7671e6
@@ -608,32 +608,26 @@ PAPI_library_init( int version )
7671e6
 	   papi_return( init_retval );
7671e6
 	}
7671e6
 
7671e6
-	/* Initialize component globals */
7671e6
+	/* Initialize thread globals, including the main threads  */
7671e6
 
7671e6
-	tmp = _papi_hwi_init_global(  );
7671e6
+	tmp = _papi_hwi_init_global_threads(  );
7671e6
 	if ( tmp ) {
7671e6
 		init_retval = tmp;
7671e6
 		_papi_hwi_shutdown_global_internal(  );
7671e6
-		_in_papi_library_init_cnt--;
7671e6
+   	_in_papi_library_init_cnt--;
7671e6
 		papi_return( init_retval );
7671e6
 	}
7671e6
-	
7671e6
-	/* Initialize thread globals, including the main threads  */
7671e6
 
7671e6
-	tmp = _papi_hwi_init_global_threads(  );
7671e6
+	/* Initialize component globals */
7671e6
+
7671e6
+	tmp = _papi_hwi_init_global(  );
7671e6
 	if ( tmp ) {
7671e6
-		int i;
7671e6
 		init_retval = tmp;
7671e6
 		_papi_hwi_shutdown_global_internal(  );
7671e6
-		for ( i = 0; i < papi_num_components; i++ ) {
7671e6
-		    if (!_papi_hwd[i]->cmp_info.disabled) {
7671e6
-                       _papi_hwd[i]->shutdown_component(  );
7671e6
-		    }
7671e6
-		}
7671e6
 		_in_papi_library_init_cnt--;
7671e6
 		papi_return( init_retval );
7671e6
 	}
7671e6
-
7671e6
+	
7671e6
 	init_level = PAPI_LOW_LEVEL_INITED;
7671e6
 	_in_papi_library_init_cnt--;
7671e6
 
7671e6
diff --git a/src/papi_internal.c b/src/papi_internal.c
7671e6
index 2412eca63..f0e457bf7 100644
7671e6
--- a/src/papi_internal.c
7671e6
+++ b/src/papi_internal.c
7671e6
@@ -111,31 +111,28 @@ _papi_hwi_free_papi_event_string() {
7671e6
 	}
7671e6
 	return;
7671e6
 }
7671e6
-// A place to keep the current papi event code so some component functions can fetch its value
7671e6
-// The current event code can be stored here prior to component calls and cleared after the component returns
7671e6
-static unsigned int papi_event_code = -1;
7671e6
-static int papi_event_code_changed = -1;
7671e6
+
7671e6
 void
7671e6
 _papi_hwi_set_papi_event_code (unsigned int event_code, int update_flag) {
7671e6
 	INTDBG("new event_code: %#x, update_flag: %d, previous event_code: %#x\n", event_code, update_flag, papi_event_code);
7671e6
 
7671e6
 	// if call is just to reset and start over, set both flags to show nothing saved yet
7671e6
 	if (update_flag < 0) {
7671e6
-		papi_event_code_changed = -1;
7671e6
-		papi_event_code = -1;
7671e6
+		_papi_hwi_my_thread->tls_papi_event_code_changed = -1;
7671e6
+		_papi_hwi_my_thread->tls_papi_event_code = -1;
7671e6
 		return;
7671e6
 	}
7671e6
 
7671e6
 	// if 0, it is being set prior to calling a component, if >0 it is being changed by the component
7671e6
-	papi_event_code_changed = update_flag;
7671e6
+	_papi_hwi_my_thread->tls_papi_event_code_changed = update_flag;
7671e6
 	// save the event code passed in
7671e6
-	papi_event_code = event_code;
7671e6
+	_papi_hwi_my_thread->tls_papi_event_code = event_code;
7671e6
 	return;
7671e6
 }
7671e6
 unsigned int
7671e6
 _papi_hwi_get_papi_event_code () {
7671e6
 	INTDBG("papi_event_code: %#x\n", papi_event_code);
7671e6
-	return papi_event_code;
7671e6
+	return _papi_hwi_my_thread->tls_papi_event_code;
7671e6
 }
7671e6
 /* Get the index into the ESI->NativeInfoArray for the current PAPI event code */
7671e6
 int
7671e6
@@ -560,7 +557,7 @@ _papi_hwi_native_to_eventcode(int cidx, int event_code, int ntv_idx, const char
7671e6
 
7671e6
   int result;
7671e6
 
7671e6
-  if (papi_event_code_changed > 0) {
7671e6
+  if (_papi_hwi_my_thread->tls_papi_event_code_changed > 0) {
7671e6
 	  result = _papi_hwi_get_papi_event_code();
7671e6
 	  INTDBG("EXIT: papi_event_code: %#x set by the component\n", result);
7671e6
 	  return result;
7671e6
diff --git a/src/threads.c b/src/threads.c
7671e6
index 4dd0cf4e3..9f586c415 100644
7671e6
--- a/src/threads.c
7671e6
+++ b/src/threads.c
7671e6
@@ -286,6 +286,10 @@ _papi_hwi_initialize_thread( ThreadInfo_t ** dest, int tid )
7671e6
 		return PAPI_ENOMEM;
7671e6
 	}
7671e6
 
7671e6
+   /* init event memory variables, used by papi_internal.c  */
7671e6
+   thread->tls_papi_event_code = -1;
7671e6
+   thread->tls_papi_event_code_changed = -1;
7671e6
+
7671e6
 	/* Call the component to fill in anything special. */
7671e6
 
7671e6
 	for ( i = 0; i < papi_num_components; i++ ) {
7671e6
@@ -421,6 +425,11 @@ _papi_hwi_shutdown_thread( ThreadInfo_t * thread, int force_shutdown )
7671e6
 	unsigned long tid;
7671e6
 	int i, failure = 0;
7671e6
 
7671e6
+   /* Clear event memory variables */
7671e6
+   thread->tls_papi_event_code = -1;
7671e6
+   thread->tls_papi_event_code_changed = -1;
7671e6
+
7671e6
+   /* Get thread id */
7671e6
 	if ( _papi_hwi_thread_id_fn )
7671e6
 		tid = ( *_papi_hwi_thread_id_fn ) (  );
7671e6
 	else
7671e6
diff --git a/src/threads.h b/src/threads.h
7671e6
index cd3369068..264d9f3a6 100644
7671e6
--- a/src/threads.h
7671e6
+++ b/src/threads.h
7671e6
@@ -30,6 +30,11 @@ typedef struct _ThreadInfo
7671e6
 	EventSetInfo_t **running_eventset;
7671e6
 	EventSetInfo_t *from_esi;          /* ESI used for last update this control state */
7671e6
 	int wants_signal;
7671e6
+
7671e6
+   // The current event code can be stored here prior to 
7671e6
+   // component calls and cleared after the component returns.
7671e6
+   unsigned int tls_papi_event_code;
7671e6
+   int tls_papi_event_code_changed;
7671e6
 } ThreadInfo_t;
7671e6
 
7671e6
 /** The list of threads, gets initialized to master process with TID of getpid()