HPCToolkit
ompt-callstack.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 // local includes
50 //******************************************************************************
51 
52 #include <ompt.h>
53 
56 #include <hpcrun/sample_event.h>
57 #include <hpcrun/trace.h>
58 #include <hpcrun/unresolved.h>
59 
60 #include "ompt-callstack.h"
61 #include "ompt-interface.h"
62 #include "ompt-state-placeholders.h"
63 #include "ompt-defer.h"
64 #include "ompt-region.h"
65 #include "ompt-task-map.h"
66 
67 #if defined(HOST_CPU_PPC)
68 #include "ppc64-gnu-omp.h"
69 #elif defined(HOST_CPU_x86) || defined(HOST_CPU_x86_64)
70 #include "x86-gnu-omp.h"
71 #else
72 #error "invalid architecture type"
73 #endif
74 
75 
76 //******************************************************************************
77 // macros
78 //******************************************************************************
79 
80 #define OMPT_DEBUG 1
81 
82 #if OMPT_DEBUG
83 #define elide_debug_dump(t,i,o,r) if (ompt_callstack_debug) stack_dump(t,i,o,r)
84 #else
85 #define elide_debug_dump(t,i,o,r)
86 #endif
87 
88 
89 //******************************************************************************
90 // private variables
91 //******************************************************************************
92 
94 
95 static int ompt_eager_context = 0;
96 static int ompt_callstack_debug = 0;
97 
98 
99 
100 //******************************************************************************
101 // private operations
102 //******************************************************************************
103 
104 static void
106  char *tag,
107  frame_t *inner,
108  frame_t *outer,
109  uint64_t region_id
110 )
111 {
112  EMSG("-----%s start", tag);
113  for (frame_t* x = inner; x <= outer; ++x) {
114  void* ip;
115  hpcrun_unw_get_ip_unnorm_reg(&(x->cursor), &ip);
116 
117  load_module_t* lm = hpcrun_loadmap_findById(x->ip_norm.lm_id);
118  const char* lm_name = (lm) ? lm->name : "(null)";
119 
120  EMSG("ip = %p (%p), load module = %s", ip, x->ip_norm.lm_ip, lm_name);
121  }
122  EMSG("-----%s end", tag);
123  EMSG("<0x%lx>\n", region_id);
124 }
125 
126 
127 static int
129  void *lower,
130  void *upper,
131  void *addr
132 )
133 {
134  uint64_t uaddr = (uint64_t) addr;
135  uint64_t ulower = (uint64_t) lower;
136  uint64_t uupper = (uint64_t) upper;
137 
138  return ((ulower <= uaddr) & (uaddr <= uupper));
139 }
140 
141 
142 static ompt_state_t
144 {
145  uint64_t wait_id;
146  return hpcrun_ompt_get_state(&wait_id);
147 }
148 
149 
150 static void
151 set_frame(frame_t *f, ompt_placeholder_t *ph)
152 {
153  f->cursor.pc_unnorm = ph->pc;
154  f->ip_norm = ph->pc_norm;
155  f->the_function = ph->pc_norm;
156 }
157 
158 
159 static void
160 collapse_callstack(backtrace_info_t *bt, ompt_placeholder_t *placeholder)
161 
162 {
163  set_frame(bt->last, placeholder);
164  bt->begin = bt->last;
165  bt->bottom_frame_elided = false;
166  bt->partial_unwind = false;
167 }
168 
169 
170 static void
172  backtrace_info_t *bt,
173  uint64_t region_id,
174  int isSync
175 )
176 {
177  // collapse callstack if a thread is idle or waiting in a barrier
178  switch(check_state()) {
179  case ompt_state_wait_barrier:
180  case ompt_state_wait_barrier_implicit:
181  case ompt_state_wait_barrier_explicit:
182  break; // FIXME: skip barrier collapsing until the kinks are worked out.
183  collapse_callstack(bt, &ompt_placeholders.ompt_barrier_wait);
184  return;
185  case ompt_state_idle:
186  if (!TD_GET(master)) {
187  collapse_callstack(bt, &ompt_placeholders.ompt_idle);
188  return;
189  }
190  default: break;
191  }
192 
193  frame_t **bt_outer = &bt->last;
194  frame_t **bt_inner = &bt->begin;
195 
196  frame_t *bt_outer_at_entry = *bt_outer;
197 
198 
199  int i = 0;
200  frame_t *it = NULL;
201 
202  ompt_frame_t *frame0 = hpcrun_ompt_get_task_frame(i);
203 
204  TD_GET(omp_task_context) = 0;
205 
206  elide_debug_dump("ORIGINAL", *bt_inner, *bt_outer, region_id);
207 
208  //---------------------------------------------------------------
209  // handle all of the corner cases that can occur at the top of
210  // the stack first
211  //---------------------------------------------------------------
212 
213  if (!frame0) {
214  // corner case: the innermost task (if any) has no frame info.
215  // no action necessary. just return.
216  goto clip_base_frames;
217  }
218 
219  while ((frame0->reenter_runtime_frame == 0) && (frame0->exit_runtime_frame == 0)) {
220  // corner case: the top frame has been set up, but not filled in.
221  // ignore this frame.
222  frame0 = hpcrun_ompt_get_task_frame(++i);
223 
224  if (!frame0) {
225  // corner case: the innermost task (if any) has no frame info.
226  goto clip_base_frames;
227  }
228  }
229 
230  if (frame0->exit_runtime_frame &&
231  (((uint64_t) frame0->exit_runtime_frame) < ((uint64_t) (*bt_inner)->cursor.sp))) {
232  // corner case: the top frame has been set up, exit frame has been filled in;
233  // however, exit_runtime_frame points beyond the top of stack. the final call
234  // to user code hasn't been made yet. ignore this frame.
235  frame0 = hpcrun_ompt_get_task_frame(++i);
236  }
237 
238  if (!frame0) {
239  // corner case: the innermost task (if any) has no frame info.
240  goto clip_base_frames;
241  }
242 
243  if (frame0->reenter_runtime_frame) {
244  // the sample was received inside the runtime;
245  // elide frames from top of stack down to runtime entry
246  int found = 0;
247  for (it = *bt_inner; it <= *bt_outer; it++) {
248  if ((uint64_t)(it->cursor.sp) > (uint64_t)frame0->reenter_runtime_frame) {
249  if (isSync) {
250  // for synchronous samples, elide runtime frames at top of stack
251  *bt_inner = it;
252  }
253  found = 1;
254  break;
255  }
256  }
257 
258  if (found == 0) {
259  // reenter_runtime_frame not found on stack. all frames are runtime frames
260  goto clip_base_frames;
261  }
262  // frames at top of stack elided. continue with the rest
263  }
264 
265  // general case: elide frames between frame1->enter and frame0->exit
266  while (true) {
267  frame_t *exit0 = NULL, *reenter1 = NULL;
268  ompt_frame_t *frame1;
269 
270  frame0 = hpcrun_ompt_get_task_frame(i);
271 
272  if (!frame0) break;
273 
274  ompt_task_id_t tid = hpcrun_ompt_get_task_id(i);
275  cct_node_t *omp_task_context = task_map_lookup(tid);
276 
277  void *low_sp = (*bt_inner)->cursor.sp;
278  void *high_sp = (*bt_outer)->cursor.sp;
279 
280  // if a frame marker is inside the call stack, set its flag to true
281  bool exit0_flag =
282  interval_contains(low_sp, high_sp, frame0->exit_runtime_frame);
283 
284  /* start from the top of the stack (innermost frame).
285  find the matching frame in the callstack for each of the markers in the
286  stack. look for them in the order in which they should occur.
287 
288  optimization note: this always starts at the top of the stack. this can
289  lead to quadratic cost. could pick up below where you left off cutting in
290  previous iterations.
291  */
292  it = *bt_inner;
293  if(exit0_flag) {
294  for (; it <= *bt_outer; it++) {
295  if((uint64_t)(it->cursor.sp) > (uint64_t)(frame0->exit_runtime_frame)) {
296  exit0 = it - 1;
297  break;
298  }
299  }
300  }
301 
302  if (exit0_flag && omp_task_context) {
303  TD_GET(omp_task_context) = omp_task_context;
304  *bt_outer = exit0 - 1;
305  break;
306  }
307 
308  frame1 = hpcrun_ompt_get_task_frame(++i);
309  if (!frame1) break;
310 
311  bool reenter1_flag =
312  interval_contains(low_sp, high_sp, frame1->reenter_runtime_frame);
313  if(reenter1_flag) {
314  for (; it <= *bt_outer; it++) {
315  if((uint64_t)(it->cursor.sp) > (uint64_t)(frame1->reenter_runtime_frame)) {
316  reenter1 = it - 1;
317  break;
318  }
319  }
320  }
321 
322  if (exit0 && reenter1) {
323 // FIXME: IBM and INTEL need to agree
324 #if 1
325  // laksono 2014.07.08: hack removing one more frame to avoid redundancy with the parent
326  // It seems the last frame of the master is the same as the first frame of the workers thread
327  // By eliminating the topmost frame we should avoid the appearance of the same frame twice
328  // in the callpath
329  memmove(*bt_inner+(reenter1-exit0+1), *bt_inner,
330  (exit0 - *bt_inner)*sizeof(frame_t));
331  *bt_inner = *bt_inner + (reenter1 - exit0 + 1);
332 #else
333  // was missing a frame with intel's runtime; eliminate +1 -- johnmc
334  memmove(*bt_inner+(reenter1-exit0), *bt_inner,
335  (exit0 - *bt_inner)*sizeof(frame_t));
336  *bt_inner = *bt_inner + (reenter1 - exit0);
337 #endif
338  exit0 = reenter1 = NULL;
339  } else if (exit0 && !reenter1) {
340  // corner case: reenter1 is in the team master's stack, not mine. eliminate all
341  // frames below the exit frame.
342  *bt_outer = exit0 - 1;
343  break;
344  }
345  }
346 
347  if (*bt_outer != bt_outer_at_entry) {
348  bt->bottom_frame_elided = true;
349  bt->partial_unwind = false;
350  }
351 
352  bt->trace_pc = (*bt_inner)->cursor.pc_unnorm;
353 
354  elide_debug_dump("ELIDED", *bt_inner, *bt_outer, region_id);
355  return;
356 
357  clip_base_frames:
358  {
359  int master = TD_GET(master);
360  if (!master) {
361  set_frame(*bt_outer, &ompt_placeholders.ompt_idle);
362  *bt_inner = *bt_outer;
363  bt->bottom_frame_elided = false;
364  bt->partial_unwind = false;
365  bt->trace_pc = (*bt_inner)->cursor.pc_unnorm;
366  return;
367  }
368 
369  /* runtime frames with nothing else; it is harmless to reveal them all */
370  uint64_t idle_frame = (uint64_t) hpcrun_ompt_get_idle_frame();
371 
372  if (idle_frame) {
373  /* clip below the idle frame */
374  for (it = *bt_inner; it <= *bt_outer; it++) {
375  if ((uint64_t)(it->cursor.sp) >= idle_frame) {
376  *bt_outer = it - 2;
377  bt->bottom_frame_elided = true;
378  bt->partial_unwind = true;
379  break;
380  }
381  }
382  } else {
383  /* no idle frame. show the whole stack. */
384  }
385 
386  elide_debug_dump("ELIDED INNERMOST FRAMES", *bt_inner, *bt_outer, region_id);
387  return;
388  }
389 }
390 
391 
392 static cct_node_t *
393 memoized_context_get(thread_data_t* td, uint64_t region_id)
394 {
395  return (td->outer_region_id == region_id && td->outer_region_context) ?
396  td->outer_region_context :
397  NULL;
398 }
399 
400 static void
401 memoized_context_set(thread_data_t* td, uint64_t region_id, cct_node_t *result)
402 {
403  td->outer_region_id = region_id;
404  td->outer_region_context = result;
405 }
406 
407 
408 cct_node_t *
410 {
411  cct_node_t *root;
412  cct_node_t *node = _node;
413  while (node) {
415  if (IS_UNRESOLVED_ROOT(addr)) {
416  root = hpcrun_get_thread_epoch()->csdata.unresolved_root;
417  break;
418  } else if (IS_PARTIAL_ROOT(addr)) {
419  root = hpcrun_get_thread_epoch()->csdata.partial_unw_root;
420  break;
421  }
422  node = hpcrun_cct_parent(node);
423  }
424  if (node == NULL) root = hpcrun_get_thread_epoch()->csdata.tree_root;
425  return root;
426 }
427 
428 static cct_node_t *
429 lookup_region_id(uint64_t region_id)
430 {
432  cct_node_t *result = NULL;
433 
434  if (hpcrun_trace_isactive()) {
435  result = memoized_context_get(td, region_id);
436  if (result) return result;
437 
438  cct_node_t *t0_path = hpcrun_region_lookup(region_id);
439  if (t0_path) {
440  cct_node_t *rroot = region_root(t0_path);
441  result = hpcrun_cct_insert_path_return_leaf(rroot, t0_path);
442  memoized_context_set(td, region_id, result);
443  }
444  }
445 
446  return result;
447 }
448 
449 
450 cct_node_t *
451 ompt_region_context(uint64_t region_id,
452  ompt_context_type_t ctype,
453  int levels_to_skip,
454  int adjust_callsite)
455 {
456  cct_node_t *node;
457  ucontext_t uc;
458  getcontext(&uc);
459 
460  node = hpcrun_sample_callpath(&uc, 0, 0, ++levels_to_skip, 1, NULL).sample_node;
461  TMSG(DEFER_CTXT, "unwind the callstack for region 0x%lx", region_id);
462 
463  if (node && adjust_callsite) {
464  // extract the load module and offset of the leaf CCT node at the
465  // end of a call path representing a parallel region
466  cct_addr_t *n = hpcrun_cct_addr(node);
467  cct_node_t *n_parent = hpcrun_cct_parent(node);
468  uint16_t lm_id = n->ip_norm.lm_id;
469  uintptr_t lm_ip = n->ip_norm.lm_ip;
470  uintptr_t master_outlined_fn_return_addr;
471 
472  // adjust the address to point to return address of the call to
473  // the outlined function in the master
474  if (ctype == ompt_context_begin) {
475  void *ip = hpcrun_denormalize_ip(&(n->ip_norm));
476  uint64_t offset = offset_to_pc_after_next_call(ip);
477  master_outlined_fn_return_addr = lm_ip + offset;
478  } else {
479  uint64_t offset = length_of_call_instruction();
480  master_outlined_fn_return_addr = lm_ip - offset;
481  }
482  // ensure that there is a leaf CCT node with the proper return address
483  // to use as the context. when using the GNU API for OpenMP, it will
484  // be a sibling to one returned by sample_callpath.
486  (n_parent, &(ADDR2(lm_id, master_outlined_fn_return_addr)));
487  node = sibling;
488  }
489 
490  return node;
491 }
492 
493 cct_node_t *
494 ompt_parallel_begin_context(ompt_parallel_id_t region_id, int levels_to_skip,
495  int adjust_callsite)
496 {
497  if (ompt_eager_context)
498  return ompt_region_context(region_id, ompt_context_begin,
499  ++levels_to_skip, adjust_callsite);
500  else return NULL;
501 }
502 
503 
504 static void
506  backtrace_info_t *bt,
507  int isSync
508 )
509 {
510  // ompt: elide runtime frames
511  // if that is the case, then it will later become available in a deferred fashion.
512  int master = TD_GET(master);
513  if (!master) {
514  if (need_defer_cntxt()) {
515  resolve_cntxt();
516  }
517  }
518  uint64_t region_id = TD_GET(region_id);
519 
520  ompt_elide_runtime_frame(bt, region_id, isSync);
521 }
522 
523 
524 cct_node_t *
526  cct_node_t *cct_cursor)
527 {
528  cct_node_t *omp_task_context = TD_GET(omp_task_context);
529 
530  // FIXME: should memoize the resulting task context in a thread-local variable
531  // I think we can just return omp_task_context here. it is already
532  // relative to one root or another.
533  if (omp_task_context) {
534  cct_node_t *root;
535 #if 1
536  root = region_root(omp_task_context);
537 #else
538  if((is_partial_resolve((cct_node_t *)omp_task_context) > 0)) {
539  root = hpcrun_get_thread_epoch()->csdata.unresolved_root;
540  } else {
541  root = hpcrun_get_thread_epoch()->csdata.tree_root;
542  }
543 #endif
544  return hpcrun_cct_insert_path_return_leaf(root, omp_task_context);
545  }
546 
547  // if I am not the master thread, full context may not be immediately available.
548  // if that is the case, then it will later become available in a deferred fashion.
549  if (!TD_GET(master)) { // sub-master thread in nested regions
550  uint64_t region_id = TD_GET(region_id);
551  // FIXME: check whether bottom frame elided will be right for IBM runtime
552  // without help of get_idle_frame
553  if (region_id > 0 && bt->bottom_frame_elided) {
554 
555  cct_node_t *prefix = lookup_region_id(region_id);
556  if (prefix) {
557  // full context is available now. use it.
558  cct_cursor = prefix;
559  } else {
560  // full context is not available. if the there is a node for region_id in
561  // the unresolved tree, use it as the cursor to anchor the sample for now.
562  // it will be resolved later. otherwise, use the default cursor.
563  prefix =
564  hpcrun_cct_find_addr((hpcrun_get_thread_epoch()->csdata).unresolved_root,
565  &(ADDR2(UNRESOLVED, region_id)));
566  if (prefix) cct_cursor = prefix;
567  }
568  }
569  }
570 
571  return cct_cursor;
572 }
573 
574 
575 void
577 {
579 
580  ompt_finalizer.next = 0;
581  ompt_finalizer.fn = ompt_backtrace_finalize;
582  cct_backtrace_finalize_register(&ompt_finalizer);
584 }
static ompt_state_t check_state()
cct_node_t * region_root(cct_node_t *_node)
void cct_backtrace_finalize_register(cct_backtrace_finalize_entry_t *e)
static int ompt_callstack_debug
static int interval_contains(void *lower, void *upper, void *addr)
sample_val_t hpcrun_sample_callpath(void *context, int metricId, hpcrun_metricVal_t metricIncr, int skipInner, int isSync, sampling_info_t *data)
Definition: sample_event.c:160
void cct_cursor_finalize_register(cct_cursor_finalize_fn fn)
cct_node_t * ompt_cct_cursor_finalize(cct_bundle_t *cct, backtrace_info_t *bt, cct_node_t *cct_cursor)
ip_normalized_t ip_norm
Definition: frame.h:61
ip_normalized_t the_function
Definition: frame.h:62
static int ompt_eager_context
cct_node_t * node
Definition: cct.c:128
static __thread u32 tid
cct_node_t * ompt_parallel_begin_context(ompt_parallel_id_t region_id, int levels_to_skip, int adjust_callsite)
cct_node_t * sample_node
Definition: sample_event.h:96
static void stack_dump(char *tag, frame_t *inner, frame_t *outer, uint64_t region_id)
cct_node_t * ompt_region_context(uint64_t region_id, ompt_context_type_t ctype, int levels_to_skip, int adjust_callsite)
uintptr_t lm_ip
Definition: ip-normalized.h:78
#define hpcrun_get_thread_epoch()
Definition: thread_data.h:278
char * name
Definition: loadmap.h:128
cct_node_t * hpcrun_cct_parent(cct_node_t *x)
Definition: cct.c:357
static char * prefix
Definition: common.c:164
#define ADDR2(id, ip)
Definition: cct.h:104
cct_node_t * hpcrun_cct_insert_addr(cct_node_t *node, cct_addr_t *frm)
Definition: cct.c:405
static void ompt_elide_runtime_frame(backtrace_info_t *bt, uint64_t region_id, int isSync)
void ompt_callstack_register_handlers(void)
int hpcrun_trace_isactive()
Definition: trace.c:107
static cct_backtrace_finalize_entry_t ompt_finalizer
#define EMSG
Definition: messages.h:70
load_module_t * hpcrun_loadmap_findById(uint16_t id)
Definition: loadmap.c:301
#define elide_debug_dump(t, i, o, r)
ip_normalized_t ip_norm
Definition: cct_addr.h:66
hpcrun_unw_cursor_t cursor
Definition: frame.h:59
#define TD_GET(field)
Definition: thread_data.h:256
static cct_node_t * lookup_region_id(uint64_t region_id)
bool found
Definition: cct.c:129
#define TMSG(f,...)
Definition: messages.h:93
static void ompt_backtrace_finalize(backtrace_info_t *bt, int isSync)
cct_backtrace_finalize_fn fn
static cct_node_t * memoized_context_get(thread_data_t *td, uint64_t region_id)
#define NULL
Definition: ElfHelper.cpp:85
cct_node_t * hpcrun_cct_insert_path_return_leaf(cct_node_t *path, cct_node_t *root)
Definition: cct.c:871
static void set_frame(frame_t *f, ompt_placeholder_t *ph)
unsigned char uc
Definition: amd-xop.c:3
Definition: cct.c:96
static void collapse_callstack(backtrace_info_t *bt, ompt_placeholder_t *placeholder)
Definition: frame.h:58
cct_addr_t * addr
Definition: cct.c:130
<!-- ********************************************************************--> n<!-- HPCToolkit Experiment DTD --> n<!-- Version 2.1 --> n<!-- ********************************************************************--> n<!ELEMENT HPCToolkitExperiment(Header,(SecCallPathProfile|SecFlatProfile) *)> n<!ATTLIST HPCToolkitExperiment\n version CDATA #REQUIRED > n n<!-- ******************************************************************--> n n<!-- Info/NV:flexible name-value pairs:(n) ame;(t) ype;(v) alue --> n<!ELEMENT Info(NV *)> n<!ATTLIST Info\n n CDATA #IMPLIED > n<!ELEMENT NV EMPTY > n<!ATTLIST NV\n n CDATA #REQUIRED\n t CDATA #IMPLIED\n v CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Header --> n<!-- ******************************************************************--> n<!ELEMENT Header(Info *)> n<!ATTLIST Header\n n CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Section Header --> n<!-- ******************************************************************--> n<!ELEMENT SecHeader(MetricTable?, MetricDBTable?, TraceDBTable?, LoadModuleTable?, FileTable?, ProcedureTable?, Info *)> n n<!-- MetricTable:--> n<!ELEMENT MetricTable(Metric) * > n n<!-- Metric:(i) d;(n) ame --> n<!--(v) alue-type:transient type of values --> n<!--(t) ype:persistent type of metric --> n<!-- fmt:format;show;--> n<!ELEMENT Metric(MetricFormula *, Info?)> n<!ATTLIST Metric\n i CDATA #REQUIRED\n n CDATA #REQUIRED\n es CDATA #IMPLIED\n em CDATA #IMPLIED\n ep CDATA #IMPLIED\n v(raw|final|derived-incr|derived) \"raw\\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ fmt CDATA #IMPLIED\ show (1|0) \1\\ show-percent (1|0) \1> n n<!-- MetricFormula represents derived metrics: (t)ype; (frm): formula --> n<!ELEMENT MetricFormula (Info?)> n<!ATTLIST MetricFormula\ t (combine|finalize) \finalize\\ i CDATA #IMPLIED\ frm CDATA #REQUIRED> n n<!-- Metric data, used in sections: (n)ame [from Metric]; (v)alue --> n<!ELEMENT M EMPTY> n<!ATTLIST M\ n CDATA #REQUIRED\ v CDATA #REQUIRED> n n<!-- MetricDBTable: --> n<!ELEMENT MetricDBTable (MetricDB)*> n n<!-- MetricDB: (i)d; (n)ame --> n<!-- (t)ype: persistent type of metric --> n<!-- db-glob: file glob describing files in metric db --> n<!-- db-id: id within metric db --> n<!-- db-num-metrics: number of metrics in db --> n<!-- db-header-sz: size (in bytes) of a db file header --> n<!ELEMENT MetricDB EMPTY> n<!ATTLIST MetricDB\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ db-glob CDATA #IMPLIED\ db-id CDATA #IMPLIED\ db-num-metrics CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- TraceDBTable: --> n<!ELEMENT TraceDBTable (TraceDB)> n n<!-- TraceDB: (i)d --> n<!-- db-min-time: min beginning time stamp (global) --> n<!-- db-max-time: max ending time stamp (global) --> n<!ELEMENT TraceDB EMPTY> n<!ATTLIST TraceDB\ i CDATA #REQUIRED\ db-glob CDATA #IMPLIED\ db-min-time CDATA #IMPLIED\ db-max-time CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- LoadModuleTable assigns a short name to a load module --> n<!ELEMENT LoadModuleTable (LoadModule)*> n n<!ELEMENT LoadModule (Info?)> n<!ATTLIST LoadModule\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- FileTable assigns a short name to a file --> n<!ELEMENT FileTable (File)*> n n<!ELEMENT File (Info?)> n<!ATTLIST File\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- ProcedureTable assigns a short name to a procedure --> n<!ELEMENT ProcedureTable (Procedure)*> n n<!-- Info/NV: flexible name-value pairs: (n)ame; (t)ype; (v)alue --> n<!-- f: family of the procedure (fake, root, ...)--> n<!ELEMENT Procedure (Info?)> n<!ATTLIST Procedure\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ f CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Call path profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecCallPathProfile (SecHeader, SecCallPathProfileData)> n<!ATTLIST SecCallPathProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecCallPathProfileData (PF|M)*> n<!-- Procedure frame --> n<!-- (i)d: unique identifier for cross referencing --> n<!-- (s)tatic scope id --> n<!-- (n)ame: a string or an id in ProcedureTable --> n<!-- (lm) load module: a string or an id in LoadModuleTable --> n<!-- (f)ile name: a string or an id in LoadModuleTable --> n<!-- (l)ine range: \beg-end\ (inclusive range) --> n<!-- (a)lien: whether frame is alien to enclosing P --> n<!-- (str)uct: hpcstruct node id --> n<!-- (t)ype: hpcrun node type: memory access, variable declaration, ... --> n<!-- (v)ma-range-set: \{[beg-end), [beg-end)...}\ --> n<!ELEMENT PF (PF|Pr|L|C|S|M)*> n<!ATTLIST PF\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Procedure (static): GOAL: replace with 'P' --> n<!ELEMENT Pr (Pr|L|C|S|M)*> n<!ATTLIST Pr\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ a (1|0) \0\\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Callsite (a special StatementRange) --> n<!ELEMENT C (PF|M)*> n<!ATTLIST C\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Flat profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecFlatProfile (SecHeader, SecFlatProfileData)> n<!ATTLIST SecFlatProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecFlatProfileData (LM|M)*> n<!-- Load module: (i)d; (n)ame; (v)ma-range-set --> n<!ELEMENT LM (F|P|M)*> n<!ATTLIST LM\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ v CDATA #IMPLIED> n<!-- File --> n<!ELEMENT F (P|L|S|M)*> n<!ATTLIST F\ i CDATA #IMPLIED\ n CDATA #REQUIRED> n<!-- Procedure (Note 1) --> n<!ELEMENT P (P|A|L|S|C|M)*> n<!ATTLIST P\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Alien (Note 1) --> n<!ELEMENT A (A|L|S|C|M)*> n<!ATTLIST A\ i CDATA #IMPLIED\ f CDATA #IMPLIED\ n CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Loop (Note 1,2) --> n<!ELEMENT L (A|Pr|L|S|C|M)*> n<!ATTLIST L\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ f CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Statement (Note 2) --> n<!-- (it): trace record identifier --> n<!ELEMENT S (S|M)*> n<!ATTLIST S\ i CDATA #IMPLIED\ it CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Note 1: Contained Cs may not contain PFs --> n<!-- Note 2: The 's' attribute is not used for flat profiles --> n
int hpcrun_unw_get_ip_unnorm_reg(hpcrun_unw_cursor_t *c, void **reg_value)
cct_node_t * hpcrun_cct_find_addr(cct_node_t *cct, cct_addr_t *addr)
Definition: cct.c:719
static void memoized_context_set(thread_data_t *td, uint64_t region_id, cct_node_t *result)
struct cct_backtrace_finalize_entry_s * next
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
cct_addr_t * hpcrun_cct_addr(cct_node_t *node)
Definition: cct.c:369