PAPI  5.3.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cpus.c
Go to the documentation of this file.
1 /****************************/
2 /* THIS IS OPEN SOURCE CODE */
3 /****************************/
4 
5 /*
6 * File: cpus.c
7 * Author: Gary Mohr
8 * gary.mohr@bull.com
9 * - based on threads.c by Philip Mucci -
10 */
11 
12 /* This file contains cpu allocation and bookkeeping functions */
13 
14 #include "papi.h"
15 #include "papi_internal.h"
16 #include "papi_vector.h"
17 #include "papi_memory.h"
18 #include "cpus.h"
19 #include <string.h>
20 #include <unistd.h>
21 
22 /* The list of cpus; this gets built as user apps set the cpu papi */
23 /* option on an event set */
24 
26 
27 
28 static CpuInfo_t *
29 _papi_hwi_lookup_cpu( unsigned int cpu_num )
30 {
31  APIDBG("Entry:\n");
32 
33  CpuInfo_t *tmp;
34 
35  tmp = ( CpuInfo_t * ) _papi_hwi_cpu_head;
36  while ( tmp != NULL ) {
37  THRDBG( "Examining cpu %#x at %p\n", tmp->cpu_num, tmp );
38  if ( tmp->cpu_num == cpu_num ) {
39  break;
40  }
41  tmp = tmp->next;
42  if ( tmp == _papi_hwi_cpu_head ) {
43  tmp = NULL;
44  break;
45  }
46  }
47 
48  if ( tmp ) {
49  _papi_hwi_cpu_head = tmp;
50  THRDBG( "Found cpu %#x at %p\n", cpu_num, tmp );
51  } else {
52  THRDBG( "Did not find cpu %#x\n", cpu_num );
53  }
54 
55  return tmp;
56 }
57 
58 int
59 _papi_hwi_lookup_or_create_cpu( CpuInfo_t **here, unsigned int cpu_num )
60 {
61  APIDBG("Entry: here: %p\n", here);
62 
63  CpuInfo_t *tmp = NULL;
64  int retval = PAPI_OK;
65 
67 
68  tmp = _papi_hwi_lookup_cpu(cpu_num);
69  if ( tmp == NULL ) {
70  retval = _papi_hwi_initialize_cpu( &tmp, cpu_num );
71  }
72 
73  /* Increment use count */
74  tmp->num_users++;
75 
76  if ( retval == PAPI_OK ) {
77  *here = tmp;
78  }
79 
81 
82  return retval;
83 }
84 
85 
86 static CpuInfo_t *
87 allocate_cpu( unsigned int cpu_num )
88 {
89  APIDBG("Entry: cpu_num: %d\n", cpu_num);
90 
91  CpuInfo_t *cpu;
92  int i;
93 
94  /* Allocate new CpuInfo structure */
95  cpu = ( CpuInfo_t * ) papi_calloc( 1, sizeof ( CpuInfo_t ) );
96  if ( cpu == NULL ) {
97  goto allocate_error;
98  }
99 
100  /* identify the cpu this info structure represents */
101  cpu->cpu_num = cpu_num;
102  cpu->context = ( hwd_context_t ** )
103  papi_calloc( ( size_t ) papi_num_components ,
104  sizeof ( hwd_context_t * ) );
105  if ( !cpu->context ) {
106  goto error_free_cpu;
107  }
108 
109  /* Allocate an eventset per component per cpu? Why? */
110 
111  cpu->running_eventset = ( EventSetInfo_t ** )
112  papi_calloc(( size_t ) papi_num_components,
113  sizeof ( EventSetInfo_t * ) );
114  if ( !cpu->running_eventset ) {
115  goto error_free_context;
116  }
117 
118  for ( i = 0; i < papi_num_components; i++ ) {
119  cpu->context[i] =
120  ( void * ) papi_calloc( 1, ( size_t ) _papi_hwd[i]->size.context );
121  cpu->running_eventset[i] = NULL;
122  if ( cpu->context[i] == NULL ) {
123  goto error_free_contexts;
124  }
125  }
126 
127  cpu->num_users=0;
128 
129  THRDBG( "Allocated CpuInfo: %p\n", cpu );
130 
131  return cpu;
132 
133 error_free_contexts:
134  for ( i--; i >= 0; i-- ) papi_free( cpu->context[i] );
135 error_free_context:
136  papi_free( cpu->context );
137 error_free_cpu:
138  papi_free( cpu );
139 allocate_error:
140  return NULL;
141 }
142 
143 /* Must be called with CPUS_LOCK held! */
144 static int
146 {
147  APIDBG("Entry: entry: %p\n", entry);
148 
149  CpuInfo_t *tmp = NULL, *prev = NULL;
150 
151  THRDBG( "_papi_hwi_cpu_head was cpu %d at %p\n",
152  _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head );
153 
154  /* Find the preceding element and the matched element,
155  short circuit if we've seen the head twice */
156 
157  for ( tmp = ( CpuInfo_t * ) _papi_hwi_cpu_head;
158  ( entry != tmp ) || ( prev == NULL ); tmp = tmp->next ) {
159  prev = tmp;
160  }
161 
162  if ( tmp != entry ) {
163  THRDBG( "Cpu %d at %p was not found in the cpu list!\n",
164  entry->cpu_num, entry );
165  return PAPI_EBUG;
166  }
167 
168  /* Only 1 element in list */
169 
170  if ( prev == tmp ) {
171  _papi_hwi_cpu_head = NULL;
172  tmp->next = NULL;
173  THRDBG( "_papi_hwi_cpu_head now NULL\n" );
174  } else {
175  prev->next = tmp->next;
176  /* If we're removing the head, better advance it! */
177  if ( _papi_hwi_cpu_head == tmp ) {
178  _papi_hwi_cpu_head = tmp->next;
179  THRDBG( "_papi_hwi_cpu_head now cpu %d at %p\n",
180  _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head );
181  }
182  THRDBG( "Removed cpu %p from list\n", tmp );
183  }
184 
185  return PAPI_OK;
186 }
187 
188 
189 static void
191 {
192  APIDBG( "Entry: *cpu: %p, cpu_num: %d, cpu_users: %d\n",
193  *cpu, ( *cpu )->cpu_num, (*cpu)->num_users);
194 
195  int i,users,retval;
196 
198 
199  (*cpu)->num_users--;
200 
201  users=(*cpu)->num_users;
202 
203  /* Remove from linked list if no users */
204  if (!users) remove_cpu( *cpu );
205 
207 
208  /* Exit early if still users of this CPU */
209  if (users!=0) return;
210 
211  THRDBG( "Shutting down cpu %d at %p\n", (*cpu)->cpu_num, cpu );
212 
213  for ( i = 0; i < papi_num_components; i++ ) {
214  if (_papi_hwd[i]->cmp_info.disabled) continue;
215  retval = _papi_hwd[i]->shutdown_thread( (*cpu)->context[i] );
216  if ( retval != PAPI_OK ) {
217  // failure = retval;
218  }
219  }
220 
221  for ( i = 0; i < papi_num_components; i++ ) {
222  if ( ( *cpu )->context[i] ) {
223  papi_free( ( *cpu )->context[i] );
224  }
225  }
226 
227  if ( ( *cpu )->context ) {
228  papi_free( ( *cpu )->context );
229  }
230 
231  if ( ( *cpu )->running_eventset ) {
232  papi_free( ( *cpu )->running_eventset );
233  }
234 
235  /* why do we clear this? */
236  memset( *cpu, 0x00, sizeof ( CpuInfo_t ) );
237  papi_free( *cpu );
238  *cpu = NULL;
239 }
240 
241 /* Must be called with CPUS_LOCK held! */
242 static void
244 {
245  APIDBG("Entry: entry: %p\n", entry);
246 
247  if ( _papi_hwi_cpu_head == NULL ) {
248  /* 0 elements */
249  THRDBG( "_papi_hwi_cpu_head is NULL\n" );
250  entry->next = entry;
251  } else if ( _papi_hwi_cpu_head->next == _papi_hwi_cpu_head ) {
252  /* 1 element */
253  THRDBG( "_papi_hwi_cpu_head was cpu %d at %p\n",
254  _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head );
255  _papi_hwi_cpu_head->next = entry;
256  entry->next = ( CpuInfo_t * ) _papi_hwi_cpu_head;
257  } else {
258  /* 2+ elements */
259  THRDBG( "_papi_hwi_cpu_head was cpu %d at %p\n",
260  _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head );
261  entry->next = _papi_hwi_cpu_head->next;
262  _papi_hwi_cpu_head->next = entry;
263  }
264 
265  _papi_hwi_cpu_head = entry;
266 
267  THRDBG( "_papi_hwi_cpu_head now cpu %d at %p\n",
268  _papi_hwi_cpu_head->cpu_num, _papi_hwi_cpu_head );
269 }
270 
271 
272 
273 /* Must be called with CPUS_LOCK held! */
274 int
275 _papi_hwi_initialize_cpu( CpuInfo_t **dest, unsigned int cpu_num )
276 {
277  APIDBG("Entry: dest: %p, *dest: %p, cpu_num: %d\n", dest, *dest, cpu_num);
278 
279  int retval;
280  CpuInfo_t *cpu;
281  int i;
282 
283  if ( ( cpu = allocate_cpu(cpu_num) ) == NULL ) {
284  *dest = NULL;
285  return PAPI_ENOMEM;
286  }
287 
288  /* Call the component to fill in anything special. */
289  for ( i = 0; i < papi_num_components; i++ ) {
290  if (_papi_hwd[i]->cmp_info.disabled) continue;
291  retval = _papi_hwd[i]->init_thread( cpu->context[i] );
292  if ( retval ) {
293  free_cpu( &cpu );
294  *dest = NULL;
295  return retval;
296  }
297  }
298 
299  insert_cpu( cpu );
300 
301  *dest = cpu;
302  return PAPI_OK;
303 }
304 
305 int
307 {
308  APIDBG("Entry: cpu: %p, cpu_num: %d\n", cpu, cpu->cpu_num);
309 
310  free_cpu( &cpu );
311 
312  return PAPI_OK;
313 }
static CpuInfo_t * _papi_hwi_lookup_cpu(unsigned int cpu_num)
Definition: cpus.c:29
memset(eventId, 0, size)
#define PAPI_ENOMEM
Definition: fpapi.h:107
#define papi_free(a)
Definition: papi_memory.h:35
EventSetInfo_t ** running_eventset
Definition: cpus.h:15
cpu
Definition: iozone.c:3872
#define CPUS_LOCK
Definition: papi_internal.h:92
static CpuInfo_t * _papi_hwi_cpu_head
Definition: cpus.c:25
struct _CpuInfo * next
Definition: cpus.h:13
int num_users
Definition: cpus.h:17
return PAPI_OK
Definition: linux-nvml.c:458
struct cache_ent * entry
Definition: libasync.c:1170
#define THRDBG(format, args...)
Definition: papi_debug.h:66
hwd_context_t ** context
Definition: cpus.h:14
static void insert_cpu(CpuInfo_t *entry)
Definition: cpus.c:243
Return codes and api definitions.
#define APIDBG(format, args...)
Definition: papi_debug.h:64
int i
Definition: fileop.c:140
inline_static int _papi_hwi_lock(int lck)
Definition: threads.h:64
unsigned int cpu_num
Definition: cpus.h:12
Definition: cpus.h:10
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:78
static CpuInfo_t * allocate_cpu(unsigned int cpu_num)
Definition: cpus.c:87
int _papi_hwi_shutdown_cpu(CpuInfo_t *cpu)
Definition: cpus.c:306
int _papi_hwi_initialize_cpu(CpuInfo_t **dest, unsigned int cpu_num)
Definition: cpus.c:275
int papi_num_components
#define PAPI_EBUG
Definition: fpapi.h:111
int _papi_hwi_lookup_or_create_cpu(CpuInfo_t **here, unsigned int cpu_num)
Definition: cpus.c:59
struct papi_vectors * _papi_hwd[]
static int remove_cpu(CpuInfo_t *entry)
Definition: cpus.c:145
ssize_t retval
Definition: libasync.c:338
long long tmp
Definition: iozone.c:12031
#define papi_calloc(a, b)
Definition: papi_memory.h:37
static void free_cpu(CpuInfo_t **cpu)
Definition: cpus.c:190