|
PAPI
5.3.0.0
|
00001 /****************************/ 00002 /* THIS IS OPEN SOURCE CODE */ 00003 /****************************/ 00004 00005 /* 00006 * File: cpus.c 00007 * Author: Gary Mohr 00008 * gary.mohr@bull.com 00009 * - based on threads.c by Philip Mucci - 00010 */ 00011 00012 /* This file contains cpu allocation and bookkeeping functions */ 00013 00014 #include "papi.h" 00015 #include "papi_internal.h" 00016 #include "papi_vector.h" 00017 #include "papi_memory.h" 00018 #include "cpus.h" 00019 #include <string.h> 00020 #include <unistd.h> 00021 00022 /* The list of cpus; this gets built as user apps set the cpu papi */ 00023 /* option on an event set */ 00024 00025 static CpuInfo_t *_papi_hwi_cpu_head; 00026 00027 00028 static CpuInfo_t * 00029 _papi_hwi_lookup_cpu( unsigned int cpu_num ) 00030 { 00031 APIDBG("Entry:\n"); 00032 00033 CpuInfo_t *tmp; 00034 00035 tmp = ( CpuInfo_t * ) _papi_hwi_cpu_head; 00036 while ( tmp != NULL ) { 00037 THRDBG( "Examining cpu %#x at %p\n", tmp->cpu_num, tmp ); 00038 if ( tmp->cpu_num == cpu_num ) { 00039 break; 00040 } 00041 tmp = tmp->next; 00042 if ( tmp == _papi_hwi_cpu_head ) { 00043 tmp = NULL; 00044 break; 00045 } 00046 } 00047 00048 if ( tmp ) { 00049 _papi_hwi_cpu_head = tmp; 00050 THRDBG( "Found cpu %#x at %p\n", cpu_num, tmp ); 00051 } else { 00052 THRDBG( "Did not find cpu %#x\n", cpu_num ); 00053 } 00054 00055 return tmp; 00056 } 00057 00058 int 00059 _papi_hwi_lookup_or_create_cpu( CpuInfo_t **here, unsigned int cpu_num ) 00060 { 00061 APIDBG("Entry: here: %p\n", here); 00062 00063 CpuInfo_t *tmp = NULL; 00064 int retval = PAPI_OK; 00065 00066 _papi_hwi_lock( CPUS_LOCK ); 00067 00068 tmp = _papi_hwi_lookup_cpu(cpu_num); 00069 if ( tmp == NULL ) { 00070 retval = _papi_hwi_initialize_cpu( &tmp, cpu_num ); 00071 } 00072 00073 /* Increment use count */ 00074 tmp->num_users++; 00075 00076 if ( retval == PAPI_OK ) { 00077 *here = tmp; 00078 } 00079 00080 _papi_hwi_unlock( CPUS_LOCK ); 00081 00082 return retval; 00083 } 00084 00085 00086 static CpuInfo_t * 00087 allocate_cpu( unsigned int cpu_num ) 00088 { 00089 APIDBG("Entry: cpu_num: %d\n", cpu_num); 00090 00091 CpuInfo_t *cpu; 00092 int i; 00093 00094 /* Allocate new CpuInfo structure */ 00095 cpu = ( CpuInfo_t * ) papi_calloc( 1, sizeof ( CpuInfo_t ) ); 00096 if ( cpu == NULL ) { 00097 goto allocate_error; 00098 } 00099 00100 /* identify the cpu this info structure represents */ 00101 cpu->cpu_num = cpu_num; 00102 cpu->context = ( hwd_context_t ** ) 00103 papi_calloc( ( size_t ) papi_num_components , 00104 sizeof ( hwd_context_t * ) ); 00105 if ( !cpu->context ) { 00106 goto error_free_cpu; 00107 } 00108 00109 /* Allocate an eventset per component per cpu? Why? */ 00110 00111 cpu->running_eventset = ( EventSetInfo_t ** ) 00112 papi_calloc(( size_t ) papi_num_components, 00113 sizeof ( EventSetInfo_t * ) ); 00114 if ( !cpu->running_eventset ) { 00115 goto error_free_context; 00116 } 00117 00118 for ( i = 0; i < papi_num_components; i++ ) { 00119 cpu->context[i] = 00120 ( void * ) papi_calloc( 1, ( size_t ) _papi_hwd[i]->size.context ); 00121 cpu->running_eventset[i] = NULL; 00122 if ( cpu->context[i] == NULL ) { 00123 goto error_free_contexts; 00124 } 00125 } 00126 00127 cpu->num_users=0; 00128 00129 THRDBG( "Allocated CpuInfo: %p\n", cpu ); 00130 00131 return cpu; 00132 00133 error_free_contexts: 00134 for ( i--; i >= 0; i-- ) papi_free( cpu->context[i] ); 00135 error_free_context: 00136 papi_free( cpu->context ); 00137 error_free_cpu: 00138 papi_free( cpu ); 00139 allocate_error: 00140 return NULL; 00141 } 00142 00143 /* Must be called with CPUS_LOCK held! */ 00144 static int 00145 remove_cpu( CpuInfo_t * entry ) 00146 { 00147 APIDBG("Entry: entry: %p\n", entry); 00148 00149 CpuInfo_t *tmp = NULL, *prev = NULL; 00150 00151 THRDBG( "_papi_hwi_cpu_head was cpu %d at %p\n", 00152 _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head ); 00153 00154 /* Find the preceding element and the matched element, 00155 short circuit if we've seen the head twice */ 00156 00157 for ( tmp = ( CpuInfo_t * ) _papi_hwi_cpu_head; 00158 ( entry != tmp ) || ( prev == NULL ); tmp = tmp->next ) { 00159 prev = tmp; 00160 } 00161 00162 if ( tmp != entry ) { 00163 THRDBG( "Cpu %d at %p was not found in the cpu list!\n", 00164 entry->cpu_num, entry ); 00165 return PAPI_EBUG; 00166 } 00167 00168 /* Only 1 element in list */ 00169 00170 if ( prev == tmp ) { 00171 _papi_hwi_cpu_head = NULL; 00172 tmp->next = NULL; 00173 THRDBG( "_papi_hwi_cpu_head now NULL\n" ); 00174 } else { 00175 prev->next = tmp->next; 00176 /* If we're removing the head, better advance it! */ 00177 if ( _papi_hwi_cpu_head == tmp ) { 00178 _papi_hwi_cpu_head = tmp->next; 00179 THRDBG( "_papi_hwi_cpu_head now cpu %d at %p\n", 00180 _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head ); 00181 } 00182 THRDBG( "Removed cpu %p from list\n", tmp ); 00183 } 00184 00185 return PAPI_OK; 00186 } 00187 00188 00189 static void 00190 free_cpu( CpuInfo_t **cpu ) 00191 { 00192 APIDBG( "Entry: *cpu: %p, cpu_num: %d, cpu_users: %d\n", 00193 *cpu, ( *cpu )->cpu_num, (*cpu)->num_users); 00194 00195 int i,users,retval; 00196 00197 _papi_hwi_lock( CPUS_LOCK ); 00198 00199 (*cpu)->num_users--; 00200 00201 users=(*cpu)->num_users; 00202 00203 /* Remove from linked list if no users */ 00204 if (!users) remove_cpu( *cpu ); 00205 00206 _papi_hwi_unlock( CPUS_LOCK ); 00207 00208 /* Exit early if still users of this CPU */ 00209 if (users!=0) return; 00210 00211 THRDBG( "Shutting down cpu %d at %p\n", (*cpu)->cpu_num, cpu ); 00212 00213 for ( i = 0; i < papi_num_components; i++ ) { 00214 if (_papi_hwd[i]->cmp_info.disabled) continue; 00215 retval = _papi_hwd[i]->shutdown_thread( (*cpu)->context[i] ); 00216 if ( retval != PAPI_OK ) { 00217 // failure = retval; 00218 } 00219 } 00220 00221 for ( i = 0; i < papi_num_components; i++ ) { 00222 if ( ( *cpu )->context[i] ) { 00223 papi_free( ( *cpu )->context[i] ); 00224 } 00225 } 00226 00227 if ( ( *cpu )->context ) { 00228 papi_free( ( *cpu )->context ); 00229 } 00230 00231 if ( ( *cpu )->running_eventset ) { 00232 papi_free( ( *cpu )->running_eventset ); 00233 } 00234 00235 /* why do we clear this? */ 00236 memset( *cpu, 0x00, sizeof ( CpuInfo_t ) ); 00237 papi_free( *cpu ); 00238 *cpu = NULL; 00239 } 00240 00241 /* Must be called with CPUS_LOCK held! */ 00242 static void 00243 insert_cpu( CpuInfo_t * entry ) 00244 { 00245 APIDBG("Entry: entry: %p\n", entry); 00246 00247 if ( _papi_hwi_cpu_head == NULL ) { 00248 /* 0 elements */ 00249 THRDBG( "_papi_hwi_cpu_head is NULL\n" ); 00250 entry->next = entry; 00251 } else if ( _papi_hwi_cpu_head->next == _papi_hwi_cpu_head ) { 00252 /* 1 element */ 00253 THRDBG( "_papi_hwi_cpu_head was cpu %d at %p\n", 00254 _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head ); 00255 _papi_hwi_cpu_head->next = entry; 00256 entry->next = ( CpuInfo_t * ) _papi_hwi_cpu_head; 00257 } else { 00258 /* 2+ elements */ 00259 THRDBG( "_papi_hwi_cpu_head was cpu %d at %p\n", 00260 _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head ); 00261 entry->next = _papi_hwi_cpu_head->next; 00262 _papi_hwi_cpu_head->next = entry; 00263 } 00264 00265 _papi_hwi_cpu_head = entry; 00266 00267 THRDBG( "_papi_hwi_cpu_head now cpu %d at %p\n", 00268 _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head ); 00269 } 00270 00271 00272 00273 /* Must be called with CPUS_LOCK held! */ 00274 int 00275 _papi_hwi_initialize_cpu( CpuInfo_t **dest, unsigned int cpu_num ) 00276 { 00277 APIDBG("Entry: dest: %p, *dest: %p, cpu_num: %d\n", dest, *dest, cpu_num); 00278 00279 int retval; 00280 CpuInfo_t *cpu; 00281 int i; 00282 00283 if ( ( cpu = allocate_cpu(cpu_num) ) == NULL ) { 00284 *dest = NULL; 00285 return PAPI_ENOMEM; 00286 } 00287 00288 /* Call the component to fill in anything special. */ 00289 for ( i = 0; i < papi_num_components; i++ ) { 00290 if (_papi_hwd[i]->cmp_info.disabled) continue; 00291 retval = _papi_hwd[i]->init_thread( cpu->context[i] ); 00292 if ( retval ) { 00293 free_cpu( &cpu ); 00294 *dest = NULL; 00295 return retval; 00296 } 00297 } 00298 00299 insert_cpu( cpu ); 00300 00301 *dest = cpu; 00302 return PAPI_OK; 00303 } 00304 00305 int 00306 _papi_hwi_shutdown_cpu( CpuInfo_t *cpu ) 00307 { 00308 APIDBG("Entry: cpu: %p, cpu_num: %d\n", cpu, cpu->cpu_num); 00309 00310 free_cpu( &cpu ); 00311 00312 return PAPI_OK; 00313 }