HPCToolkit
pthread-blame-overrides.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 #include <pthread.h>
48 #include <dlfcn.h>
49 
50 //
51 // Investigate TBB
52 //
53 #include <sched.h>
54 
55 #include <semaphore.h>
56 #include <stdio.h>
57 
60 #include <hpcrun/thread_data.h>
61 
62 // convenience macros to simplify overrides
63 #include <monitor-exts/overrides.h>
64 
65 #include <hpcrun/hpctoolkit.h>
66 #include <hpcrun/safe-sampling.h>
67 #include <hpcrun/sample_event.h>
68 #include <messages/messages.h>
69 
70 //
71 // No need to grab monitor.h for a single function
72 //
73 extern void monitor_real_abort(void);
74 
75 //
76 // NOTE 1: the following functions (apparently) need dlvsym instead of dlsym to obtain the
77 // true function:
78 // pthread_cond_broadcast
79 // pthread_cond_signal
80 // pthread_cond_wait
81 // pthread_cond_timedwait;
82 //
83 // !! This treatment is determined empirically !!
84 // Future systems may need different treatment (or different version for dlvsym)
85 //
86 //
87 // NOTE 2: Rather than use a constructor, use lazy initialization.
88 // If constructor needed, uncomment code below
89 //
90 // void
91 // HPCRUN_CONTRUCTOR(pthread_plugin_init)()
92 // {
93 // DL_LOOKUPV(pthread_cond_broadcast);
94 // DL_LOOKUPV(pthread_cond_signal);
95 // DL_LOOKUPV(pthread_cond_wait);
96 // DL_LOOKUPV(pthread_cond_timedwait);
97 //
98 // DL_LOOKUP(pthread_mutex_lock);
99 // DL_LOOKUP(pthread_mutex_unlock);
100 // DL_LOOKUP(pthread_mutex_timedlock);
101 // }
102 //
103 
104 //
105 // Define strategies for overrides
106 //
107 
108 #define pthread_cond_timedwait_REAL DLV
109 #define pthread_cond_wait_REAL DLV
110 #define pthread_cond_broadcast_REAL DLV
111 #define pthread_cond_signal_REAL DLV
112 
113 #define pthread_mutex_lock_REAL ALT
114 #define pthread_mutex_unlock_REAL ALT
115 #define pthread_mutex_timedlock_REAL DL
116 #define pthread_mutex_trylock_REAL ALT
117 
118 #define pthread_spin_lock_REAL DL
119 #define pthread_spin_unlock_REAL DL
120 
121 //
122 // TBB investigation
123 //
124 
125 #define sched_yield_REAL DL
126 #define sem_wait_REAL DL
127 #define sem_post_REAL DL
128 #define sem_timedwait_REAL DL
129 
130 //
131 // Typedefs and declarations for real routines that are overridden
132 //
133 
134 REAL_TYPEDEF(int, pthread_cond_timedwait)(pthread_cond_t* restrict cond,
135  pthread_mutex_t* restrict mutex,
136  const struct timespec* restrict abstime);
137 REAL_TYPEDEF(int, pthread_cond_wait)(pthread_cond_t* restrict cond,
138  pthread_mutex_t* restrict mutex);
139 REAL_TYPEDEF(int, pthread_cond_broadcast)(pthread_cond_t* cond);
140 REAL_TYPEDEF(int, pthread_cond_signal)(pthread_cond_t* cond);
141 
142 REAL_TYPEDEF(int, pthread_mutex_lock)(pthread_mutex_t* mutex);
143 REAL_TYPEDEF(int, pthread_mutex_unlock)(pthread_mutex_t* mutex);
144 REAL_TYPEDEF(int, pthread_mutex_timedlock)(pthread_mutex_t* restrict mutex,
145  const struct timespec* restrict abs_timeout);
146 REAL_TYPEDEF(int, pthread_spin_lock)(pthread_spinlock_t* lock);
147 REAL_TYPEDEF(int, pthread_spin_unlock)(pthread_spinlock_t* lock);
148 
149 
150 REAL_DCL(pthread_cond_timedwait);
159 
160 int
161 OVERRIDE_NM(pthread_cond_timedwait)(pthread_cond_t* restrict cond,
162  pthread_mutex_t* restrict mutex,
163  const struct timespec* restrict abstime)
164 {
165  REAL_INIT(pthread_cond_timedwait);
166 
168  int retval = REAL_FN(pthread_cond_timedwait)(cond, mutex, abstime);
170 
171  return retval;
172 }
173 
174 int
175 OVERRIDE_NM(pthread_cond_wait)(pthread_cond_t* restrict cond,
176  pthread_mutex_t* restrict mutex)
177 {
179 
181  int retval = REAL_FN(pthread_cond_wait)(cond, mutex);
183 
184  return retval;
185 }
186 
187 int
188 OVERRIDE_NM(pthread_cond_broadcast)(pthread_cond_t *cond)
189 {
191 
192  int retval = REAL_FN(pthread_cond_broadcast)(cond);
194  return retval;
195 }
196 
197 int
198 OVERRIDE_NM(pthread_cond_signal)(pthread_cond_t* cond)
199 {
201 
202  int retval = REAL_FN(pthread_cond_signal)(cond);
204  return retval;
205 }
206 
207 int
208 OVERRIDE_NM(pthread_mutex_lock)(pthread_mutex_t* mutex)
209 {
211 
212  TMSG(LOCKWAIT, "mutex lock ENCOUNTERED");
214  return REAL_FN(pthread_mutex_lock)(mutex);
215  }
216 
217  TMSG(LOCKWAIT, "pthread mutex LOCK override");
219  int retval = REAL_FN(pthread_mutex_lock)(mutex);
221 
222  return retval;
223 }
224 
225 int
226 OVERRIDE_NM(pthread_mutex_unlock)(pthread_mutex_t* mutex)
227 {
229 
230  TMSG(LOCKWAIT, "mutex unlock ENCOUNTERED");
232  return REAL_FN(pthread_mutex_unlock)(mutex);
233  }
234  TMSG(LOCKWAIT, "pthread mutex UNLOCK");
235  int retval = REAL_FN(pthread_mutex_unlock)(mutex);
237  return retval;
238 }
239 
240 int
241 OVERRIDE_NM(pthread_mutex_timedlock)(pthread_mutex_t* restrict mutex,
242  const struct timespec* restrict abs_timeout)
243 {
245 
246  TMSG(LOCKWAIT, "mutex timedlock ENCOUNTERED");
248  return REAL_FN(pthread_mutex_timedlock)(mutex, abs_timeout);
249  }
250 
251  TMSG(LOCKWAIT, "pthread mutex TIMEDLOCK");
252 
254  int retval = REAL_FN(pthread_mutex_timedlock)(mutex, abs_timeout);
256  return retval;
257 }
258 
259 int
260 OVERRIDE_NM(pthread_spin_lock)(pthread_spinlock_t* lock)
261 {
263 
264  TMSG(LOCKWAIT, "pthread_spin_lock ENCOUNTERED");
266  return REAL_FN(pthread_spin_lock)(lock);
267  }
268 
269  TMSG(LOCKWAIT, "pthread SPIN LOCK override");
271  int retval = REAL_FN(pthread_spin_lock)((void*) lock);
273 
274  return retval;
275 }
276 
277 int
278 OVERRIDE_NM(pthread_spin_unlock)(pthread_spinlock_t* lock)
279 {
281 
282  TMSG(LOCKWAIT, "pthread_spin_unlock ENCOUNTERED");
285  }
286 
287  TMSG(LOCKWAIT, "pthread SPIN UNLOCK");
288  int retval = REAL_FN(pthread_spin_unlock)((void*) lock);
290  return retval;
291 }
292 
293 //
294 // (dlsym-based) lookup utility for lazy initialization
295 //
296 
297 void*
298 override_lookup(char* fname)
299 {
300  dlerror(); // clear dlerror
301  void* rv = dlsym(RTLD_NEXT, fname);
302  char* e = dlerror();
303  if (e) {
304  hpcrun_abort("dlsym(RTLD_NEXT, %s) failed: %s", fname, e);
305  }
306  return rv;
307 }
308 
309 //
310 // (dlvsym-based) lookup utility for lazy initialization
311 //
312 
313 void*
314 override_lookupv(char* fname)
315 {
316  dlerror(); // clear dlerror
317  void* rv = dlvsym(RTLD_NEXT, fname, "GLIBC_2.3.2");
318  char* e = dlerror();
319  if (e) {
320  hpcrun_abort("dlsym(RTLD_NEXT, %s) failed: %s", fname, e);
321  }
322  return rv;
323 }
324 
325 //
326 // Further determination of TBB mechanisms
327 //
328 
329 // **** global vars for now ****
330 //
331 
332 static unsigned int calls_to_sched_yield = 0;
333 static unsigned int calls_to_sem_wait = 0;
334 
335 REAL_TYPEDEF(int, sched_yield)(void);
336 REAL_DCL(sched_yield);
337 
338 int
339 OVERRIDE_NM(sched_yield)(void)
340 {
341  REAL_INIT(sched_yield);
342 
343  // TMSG(TBB_EACH, "sched_yield hit");
344 
345  int retval = REAL_FN(sched_yield)();
346 
347  // __sync_fetch_and_add(&calls_to_sched_yield, 1);
348  return retval;
349 }
350 
351 REAL_TYPEDEF(int, sem_wait)(sem_t* sem);
352 REAL_TYPEDEF(int, sem_post)(sem_t* sem);
353 REAL_TYPEDEF(int, sem_timedwait)(sem_t* sem, const struct timespec* abs_timeout);
354 
355 
356 REAL_DCL(sem_wait);
359 
360 int
361 OVERRIDE_NM(sem_wait)(sem_t* sem)
362 {
363  REAL_INIT(sem_wait);
364 
366  return REAL_FN(sem_wait)(sem);
367  }
368  TMSG(TBB_EACH, "sem wait hit, sem = %p", sem);
370  int retval = REAL_FN(sem_wait)(sem);
372 
373  // hpcrun_atomicIncr(&calls_to_sem_wait);
374  // calls_to_sem_wait++;
375  return retval;
376 }
377 
378 int
379 OVERRIDE_NM(sem_post)(sem_t* sem)
380 {
382 
383  TMSG(LOCKWAIT, "sem_post ENCOUNTERED");
385  return REAL_FN(sem_post)(sem);
386  }
387  TMSG(LOCKWAIT, "sem POST");
388  int retval = REAL_FN(sem_post)(sem);
390  // TMSG(TBB_EACH, "sem post hit, sem = %p", sem);
391 
392  return retval;
393 }
394 
395 int
396 OVERRIDE_NM(sem_timedwait)(sem_t* sem, const struct timespec* abs_timeout)
397 {
399 
400  TMSG(TBB_EACH, "sem timedwait hit, sem = %p", sem);
401  int retval = REAL_FN(sem_timedwait)(sem, abs_timeout);
402 
403  return retval;
404 }
405 
406 void
408 {
409  AMSG("TBB stuff: ");
410  AMSG("Calls to sched yield: %d", calls_to_sched_yield);
411  AMSG("Calls to sem wait", calls_to_sem_wait);
412 }
int OVERRIDE_NM() pthread_cond_broadcast(pthread_cond_t *cond)
static unsigned int calls_to_sched_yield
void * override_lookup(char *fname)
void pthread_directed_blame_shift_spin_start(void *obj)
#define REAL_INIT(n)
Definition: overrides.h:127
void * override_lookupv(char *fname)
void tbb_stats(void)
#define hpcrun_abort(...)
Definition: messages.h:102
mcs_lock_t lock
void pthread_directed_blame_accept(void *obj)
int OVERRIDE_NM() sem_post(sem_t *sem)
void pthread_directed_blame_shift_end(void)
bool pthread_blame_lockwait_enabled(void)
int OVERRIDE_NM() pthread_spin_lock(pthread_spinlock_t *lock)
#define RTLD_NEXT
Definition: monitor_ext.h:76
static unsigned int calls_to_sem_wait
int OVERRIDE_NM() pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout)
int OVERRIDE_NM() pthread_spin_unlock(pthread_spinlock_t *lock)
int OVERRIDE_NM() pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)
void pthread_directed_blame_shift_blocked_start(void *obj)
#define TMSG(f,...)
Definition: messages.h:93
#define REAL_FN(n)
Definition: overrides.h:124
#define AMSG
Definition: messages.h:71
REAL_TYPEDEF(REAL_TYPEDEF(int, pthread_cond_timedwait)
int OVERRIDE_NM() pthread_mutex_lock(pthread_mutex_t *mutex)
#define OVERRIDE_NM(n)
Definition: overrides.h:110
#define REAL_DCL(n)
Definition: overrides.h:126
int OVERRIDE_NM() pthread_cond_signal(pthread_cond_t *cond)
void monitor_real_abort(void)
int OVERRIDE_NM() sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
int OVERRIDE_NM() pthread_mutex_unlock(pthread_mutex_t *mutex)