HPCToolkit
lush.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 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // LUSH: Logical Unwind Support for HPCToolkit
54 //
55 // Description:
56 // [The set of functions, macros, etc. defined in the file]
57 //
58 // Author:
59 // Nathan Tallent, Rice University.
60 //
61 //***************************************************************************
62 
63 //************************* System Include Files ****************************
64 
65 #include <stdlib.h>
66 #include <string.h>
67 #include <errno.h>
68 #include <stdio.h>
69 
70 #include <dlfcn.h>
71 
72 //************************** Xtrnl Include Files ****************************
73 
74 #include <monitor.h>
75 
76 //*************************** User Include Files ****************************
77 
78 #include "lush.h"
79 
81 
82 #include <unwind/common/unwind.h> // hpcrun_unw_step()
83 
84 #include <memory/hpcrun-malloc.h>
85 
86 
87 //*************************** Forward Declarations **************************
88 
89 static void handle_any_dlerror();
90 
91 
92 // **************************************************************************
93 // LUSH Agents
94 // **************************************************************************
95 
96 int
97 lush_agent__init(lush_agent_t* x, int id, const char* path,
98  lush_agent_pool_t* pool)
99 {
100  x->id = id;
101 
102  x->path = hpcrun_malloc(strlen(path) + 1); // strdup() uses malloc
103  strcpy(x->path, path);
104 
105  //x->dlhandle = dlopen(path, RTLD_LAZY);
106  x->dlhandle = monitor_real_dlopen(path, RTLD_LAZY);
108 
109 #define CALL_DLSYM(BASE, X, ID, HANDLE) \
110  BASE->X[ID] = (X ## _fn_t)dlsym(HANDLE, #X); \
111  handle_any_dlerror()
112 
113  CALL_DLSYM(pool, LUSHI_init, id, x->dlhandle);
114  CALL_DLSYM(pool, LUSHI_fini, id, x->dlhandle);
115  CALL_DLSYM(pool, LUSHI_strerror, id, x->dlhandle);
116  CALL_DLSYM(pool, LUSHI_reg_dlopen, id, x->dlhandle);
117  CALL_DLSYM(pool, LUSHI_ismycode, id, x->dlhandle);
118  CALL_DLSYM(pool, LUSHI_step_bichord, id, x->dlhandle);
119  CALL_DLSYM(pool, LUSHI_step_pnote, id, x->dlhandle);
120  CALL_DLSYM(pool, LUSHI_step_lnote, id, x->dlhandle);
121  CALL_DLSYM(pool, LUSHI_do_metric, id, x->dlhandle);
122 
123 #undef CALL_DLSYM
124 
125  pool->LUSHI_init[x->id](0, NULL, id,
126  (LUSHCB_malloc_fn_t)NULL,
127  (LUSHCB_free_fn_t)NULL,
128  (LUSHCB_step_fn_t)hpcrun_unw_step,
130  return 0;
131 }
132 
133 
134 int
136 {
137  pool->LUSHI_fini[x->id]();
138 
139  //dlclose(x->dlhandle);
140  monitor_real_dlclose(x->dlhandle);
142 
143  //free(x->path);
144  return 0;
145 }
146 
147 // **************************************************************************
148 
149 // FIXME: Copied from dlpapi.c. When hpcrun and csprof are merged,
150 // this can be merged into a common lib.
151 static void
153 {
154  // Note: We assume dlsym() or something similar has just been called!
155  char *error;
156  if ((error = dlerror()) != NULL) {
157  fprintf(stderr, "%s\n", error);
158  exit(1);
159  }
160 }
161 
162 
163 // **************************************************************************
164 // LUSH Agent Pool
165 // **************************************************************************
166 
167 int
169 {
170  int num_agents = 1; // count the agents
171 
174 
175  // 1. Allocate tables first
176 #define FN_TBL_ALLOC(BASE, FN, SZ) \
177  BASE->FN = (FN ## _fn_t *) hpcrun_malloc(sizeof(FN ## _fn_t) * (SZ))
178 
179  FN_TBL_ALLOC(x, LUSHI_init, num_agents + 1);
180  FN_TBL_ALLOC(x, LUSHI_fini, num_agents + 1);
181  FN_TBL_ALLOC(x, LUSHI_strerror, num_agents + 1);
182  FN_TBL_ALLOC(x, LUSHI_reg_dlopen, num_agents + 1);
183  FN_TBL_ALLOC(x, LUSHI_ismycode, num_agents + 1);
184  FN_TBL_ALLOC(x, LUSHI_step_bichord, num_agents + 1);
185  FN_TBL_ALLOC(x, LUSHI_step_pnote, num_agents + 1);
186  FN_TBL_ALLOC(x, LUSHI_step_lnote, num_agents + 1);
187  FN_TBL_ALLOC(x, LUSHI_do_metric, num_agents + 1);
188 
189 #undef FN_TBL_ALLOC
190 
191  // 2. Now initialize agents
192 
193  // FIXME: assumes only one agent at the moment
194  int aid = 1;
195  const char* apath = path;
196  lush_agent__init(&x->agent, aid, apath, x);
197 
198  return 0;
199 }
200 
201 
202 int
204 {
205 #define FN_TBL_FREE(BASE, FN) \
206  /* free(BASE->FN) */
207 
217 
218 #undef FN_TBL_FREE
219 
220  memset(x, 0, sizeof(*x));
221 
222  return 0;
223 }
224 
225 
226 // **************************************************************************
227 // LUSH Unwinding Interface
228 // **************************************************************************
229 
230 void
232  lush_agent_pool_t* apool, ucontext_t* context)
233 {
234  memset(cursor, 0, sizeof(*cursor));
235 
236  cursor->apool = apool;
240 }
241 
242 
245 {
246  // INVARIANT: the cursor is initialized with the first p-note of
247  // what will be the current p-chord (LUSH_CURSOR_FLAGS_BEG_PCHORD),
248  // or has the LUSH_CURSOR_FLAGS_END_PPROJ flag set.
249 
251 
252  // 1. Sanity check
254  return LUSH_STEP_END_PROJ;
255  }
256 
257  // 2. Officially step to next bichord. First attempt to use an
258  // agent to interpret the p-chord. Otherwise, use the 'identity
259  // agent'
262 
263  void* ip_unnorm = lush_cursor_get_ip_unnorm(cursor);
264  ip_normalized_t ip_norm = lush_cursor_get_ip_norm(cursor);
265  lush_agentid_t first_aid = lush_agentid_NULL;
266 
267  // Attempt to find an agent
268  lush_agent_pool_t* pool = cursor->apool;
269  lush_agentid_t aid = 1;
270  for (aid = 1; aid <= 1; ++aid) { // FIXME: first in list, etc.
271  if (pool->LUSHI_ismycode[aid]((void*) ip_unnorm)) {
272  ty = pool->LUSHI_step_bichord[aid](cursor);
273  lush_cursor_set_aid_prev(cursor, aid);
274  first_aid = aid;
275  // FIXME: move agent to beginning of list;
276  break;
277  }
278  }
279 
280  // Use the Identity agent: Association is 1-to-1
281  if (first_aid == lush_agentid_NULL) {
282  lush_lip_t* lip = lush_cursor_get_lip(cursor);
283 
284  // 32-bit warnings
285  lush_lip_setLMId(lip, ip_norm.lm_id);
286  lush_lip_setLMIP(lip, (uint64_t)(uintptr_t)ip_norm.lm_ip);
287 
288  ty = LUSH_STEP_CONT;
290  }
291 
292  // 3. Set the cursor's agentid
293  lush_cursor_set_aid(cursor, first_aid);
294 
295  return ty;
296 }
297 
298 
301 {
303  return LUSH_STEP_END_CHORD;
304  }
305 
308  }
309 
310  lush_step_t ty;
311 
312  // Special case: LUSH_CURSOR_FLAGS_BEG_PCHORD is set
315  if (lush_cursor_get_assoc(cursor) == LUSH_ASSOC_0_to_0) {
316  // Special case: LUSH_ASSOC_0_to_0
317  ty = LUSH_STEP_END_CHORD;
318  }
319  else {
320  return LUSH_STEP_CONT;
321  }
322  }
323 
324  ty = lush_forcestep_pnote(cursor);
325 
326  // filter return type
327  if (ty == LUSH_STEP_END_PROJ) {
328  ty = LUSH_STEP_END_CHORD;
329  }
330  return ty;
331 }
332 
333 
336 {
338  return LUSH_STEP_END_CHORD;
339  }
340 
342 
343  // Step cursor to next l-note, using the appropriate agent
344  lush_agent_pool_t* pool = cursor->apool;
345  lush_agentid_t aid = lush_cursor_get_aid(cursor);
346  if (aid != lush_agentid_NULL) {
347  ty = pool->LUSHI_step_lnote[aid](cursor);
348  }
349  else {
350  // Identity agent: Association is 1-to-1, so l-chord is unit length
351  // NOTE: lip was set by lush_step_bichord()
352  ty = LUSH_STEP_CONT;
354  }
355 
356  // Set cursor flags
357  if (ty == LUSH_STEP_END_CHORD
358  || ty == LUSH_STEP_END_PROJ
359  || ty == LUSH_STEP_ERROR) {
361  }
362  if (ty == LUSH_STEP_END_PROJ
363  || ty == LUSH_STEP_ERROR) {
365  }
366 
367  // filter return type
368  if (ty == LUSH_STEP_END_PROJ) {
369  ty = LUSH_STEP_END_CHORD;
370  }
371 
372  return ty;
373 }
374 
375 
376 // **************************************************************************
377 // LUSH Unwinding Primitives
378 // **************************************************************************
379 
382 {
384 
385 #if 0 // FIXME: check this
386  if (!lush_cursor_is_flag(cursor, LUSH_CURSOR_FLAGS_INIT)) {
387  // complete the current p-chord, if we haven't examined all p-notes
388  while (!lush_cursor_is_flag(cursor, LUSH_CURSOR_FLAGS_DONE_PCHORD)) {
389  lush_forcestep_pnote(cursor);
390  }
391  lush_cursor_unset_flag(cursor, LUSH_CURSOR_FLAGS_DONE_CHORD);
392 
393  ty = lush_forcestep_pnote(cursor);
394 
395  if (ty == LUSH_STEP_DONE_CHORDS || ty == LUSH_STEP_ERROR) {
396  // we have reached the outermost frame of the stack (or an error epoch)
397  lush_cursor_set_flag(cursor, LUSH_CURSOR_FLAGS_DONE_CHORD);
398  }
399  }
400  else {
401  // the first p-chord begins at the current p-note (p-cursor)
402  lush_cursor_unset_flag(cursor, LUSH_CURSOR_FLAGS_INIT);
403  ty = LUSH_STEP_CONT;
404  }
405 #endif
406 
407  return ty;
408 }
409 
410 
413 {
415  return LUSH_STEP_END_PROJ;
416  }
417 
419 
420  // Step cursor to next p-note, using the appropriate agent
421  lush_agent_pool_t* pool = cursor->apool;
422  lush_agentid_t aid = lush_cursor_get_aid(cursor);
423  if (aid != lush_agentid_NULL) {
424  ty = pool->LUSHI_step_pnote[aid](cursor);
425  }
426  else {
427  // Identity agent: Association is 1-to-1, so p-chord is unit length
428  int t = hpcrun_unw_step(lush_cursor_get_pcursor(cursor));
429  if (t > 0) {
430  ty = LUSH_STEP_END_CHORD;
431  }
432  else if (t == 0) {
433  ty = LUSH_STEP_END_PROJ;
434  }
435  else /* (t < 0) */ {
436  ty = LUSH_STEP_ERROR;
437  }
438  }
439 
440  // Set cursor flags
441  if (ty == LUSH_STEP_END_CHORD) {
442  // since prev p-note was end of p-chord, the cursor is pointing to
443  // the beginning of the next p-chord
445  }
446  if (ty == LUSH_STEP_END_CHORD
447  || ty == LUSH_STEP_END_PROJ
448  || ty == LUSH_STEP_ERROR) {
450  }
451  if (ty == LUSH_STEP_END_PROJ
452  || ty == LUSH_STEP_ERROR) {
454  }
455  return ty;
456 }
457 
458 
459 //***************************************************************************
lush_step_t lush_step_bichord(lush_cursor_t *cursor)
Definition: lush.c:244
#define lush_agentid_NULL
Definition: lush-support.h:98
lush_step_t LUSHI_step_bichord(lush_cursor_t *cursor)
Definition: agent-cilk.c:206
char * LUSHI_strerror(int code)
Definition: agent-cilk.c:152
static lush_lip_t * lush_cursor_get_lip(lush_cursor_t *cursor)
static void lush_lip_setLMId(lush_lip_t *x, uint16_t lmId)
Definition: lush-support.h:374
lush_agent_pool_t * apool
int LUSHI_fini()
Definition: agent-cilk.c:145
lush_step_t LUSHI_step_lnote(lush_cursor_t *cursor)
Definition: agent-cilk.c:327
lush_agentid_t id
Definition: lush-support.h:109
int LUSHI_init(int argc, char **argv, lush_agentid_t aid, LUSHCB_malloc_fn_t malloc_fn, LUSHCB_free_fn_t free_fn, LUSHCB_step_fn_t step_fn, LUSHCB_loadmap_find_fn_t loadmap_fn)
Definition: agent-cilk.c:126
int LUSHI_reg_dlopen()
Definition: agent-cilk.c:163
bool LUSHI_do_metric(uint64_t incrMetricIn, bool *doMetric, bool *doMetricIdleness, uint64_t *incrMetric, double *incrMetricIdleness)
Definition: agent-cilk.c:557
static void lush_cursor_unset_flag(lush_cursor_t *cursor, lush_cursor_flags_t f)
bool LUSHI_ismycode(void *addr)
Definition: agent-cilk.c:170
#define FN_TBL_FREE(BASE, FN)
#define CALL_DLSYM(BASE, X, ID, HANDLE)
static void * lush_cursor_get_ip_unnorm(lush_cursor_t *cursor)
lush_step_t LUSHI_step_pnote(lush_cursor_t *cursor)
Definition: agent-cilk.c:291
int LUSHCB_loadmap_find(void *addr, char *module_name, void **start, void **end)
Definition: lushi-cb.c:88
uintptr_t lm_ip
Definition: ip-normalized.h:78
void lush_init_unw(lush_cursor_t *cursor, lush_agent_pool_t *apool, ucontext_t *context)
Definition: lush.c:231
lush_step_t lush_forcestep_pnote(lush_cursor_t *cursor)
Definition: lush.c:412
int lush_agent__init(lush_agent_t *x, int id, const char *path, lush_agent_pool_t *pool)
Definition: lush.c:97
int lush_agent_pool__fini(lush_agent_pool_t *x)
Definition: lush.c:203
static void lush_lip_setLMIP(lush_lip_t *x, uint64_t lm_ip)
Definition: lush-support.h:388
step_state hpcrun_unw_step(hpcrun_unw_cursor_t *c)
exit
Definition: names.cpp:1
static ip_normalized_t lush_cursor_get_ip_norm(lush_cursor_t *cursor)
static void lush_cursor_set_aid(lush_cursor_t *cursor, lush_agentid_t aid)
int lush_agentid_t
Definition: lush-support.h:99
static void lush_cursor_set_aid_prev(lush_cursor_t *cursor, lush_agentid_t aid)
static bool lush_cursor_is_flag(lush_cursor_t *cursor, lush_cursor_flags_t f)
char * path
Definition: lush-support.h:110
lush_step_t lush_step_lnote(lush_cursor_t *cursor)
Definition: lush.c:335
void * hpcrun_malloc(size_t size)
Definition: mem.c:275
#define FN_TBL_ALLOC(BASE, FN, SZ)
enum lush_step lush_step_t
lush_step_t lush_step_pnote(lush_cursor_t *cursor)
Definition: lush.c:300
static void lush_cursor_set_assoc(lush_cursor_t *cursor, lush_assoc_t as)
int metric_idleness
Definition: lush.h:96
static void lush_cursor_set_flag(lush_cursor_t *cursor, lush_cursor_flags_t f)
static lush_assoc_t lush_cursor_get_assoc(lush_cursor_t *cursor)
#define lush_metricid_NULL
Definition: lush-support.h:87
static lush_agentid_t lush_cursor_get_aid(lush_cursor_t *cursor)
static hpcrun_unw_cursor_t * lush_cursor_get_pcursor(lush_cursor_t *cursor)
#define NULL
Definition: ElfHelper.cpp:85
void * dlhandle
Definition: lush-support.h:111
lush_agent_t agent
Definition: lush.h:93
int lush_agent__fini(lush_agent_t *x, lush_agent_pool_t *pool)
Definition: lush.c:135
lush_step_t lush_step_pchord(lush_cursor_t *cursor)
Definition: lush.c:381
static void handle_any_dlerror()
Definition: lush.c:152
void hpcrun_unw_init_cursor(hpcrun_unw_cursor_t *cursor, void *context)
int lush_agent_pool__init(lush_agent_pool_t *x, const char *path)
Definition: lush.c:168
int metric_time
Definition: lush.h:95