HPCToolkit
sample_event.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 #include <setjmp.h>
49 #include <string.h>
50 
51 //*************************** User Include Files ****************************
52 
54 #include <cct/cct.h>
55 #include "hpcrun_dlfns.h"
56 #include "hpcrun_stats.h"
57 #include "hpcrun-malloc.h"
58 #include "fnbounds_interface.h"
59 #include "main.h"
60 #include "metrics_types.h"
61 #include "cct2metrics.h"
62 #include "metrics.h"
63 #include "segv_handler.h"
64 #include "epoch.h"
65 #include "thread_data.h"
66 #include "trace.h"
67 #include "handling_sample.h"
68 #include "unwind.h"
70 #include "hpcrun-malloc.h"
71 #include "sample_event.h"
72 #include "sample_sources_all.h"
73 #include "start-stop.h"
74 #include "uw_recipe_map.h"
75 #include "validate_return_addr.h"
76 #include "write_data.h"
77 #include "cct_insert_backtrace.h"
78 
79 #include <monitor.h>
80 
81 #include <messages/messages.h>
82 
84 
85 //*************************** Forward Declarations **************************
86 
87 
88 //***************************************************************************
89 
90 //************************* Local helper routines ***************************
91 
92 // ------------------------------------------------------------
93 // recover from SEGVs and partial unwinds
94 // ------------------------------------------------------------
95 
96 static void
98 {
100  sigjmp_buf_t* it = &(td->bad_unwind);
101 
102  memset((void *)it->jb, '\0', sizeof(it->jb));
103 
104  if ( ! td->deadlock_drop)
106 
108 
109  if (TD_GET(fnbounds_lock)) {
111  }
112 }
113 
114 
115 static cct_node_t*
117  cct_bundle_t* cct, frame_t* bt_beg,
118  frame_t* bt_last, int metricId,
119  hpcrun_metricVal_t metricIncr,
120  int skipInner, struct cct_custom_update_s *custom_update)
121 {
122  if (ENABLED(NO_PARTIAL_UNW)){
123  return NULL;
124  }
125 
126  bt_beg = hpcrun_skip_chords(bt_last, bt_beg, skipInner);
127 
128  backtrace_info_t bt;
129 
130  bt.begin = bt_beg;
131  bt.last = bt_last;
132  bt.fence = FENCE_BAD;
133  bt.has_tramp = false;
134  bt.n_trolls = 0;
135  bt.bottom_frame_elided = false;
136 
137  TMSG(PARTIAL_UNW, "recording partial unwind from segv");
139  return hpcrun_cct_record_backtrace_w_metric(cct, true, &bt,
140 // false, bt_beg, bt_last,
141  false, metricId, metricIncr, custom_update);
142 }
143 
144 
145 
146 //***************************************************************************
147 
149 
150 void
152 {
153  TMSG(DROP, "dropping sample");
154  sigjmp_buf_t *it = &(TD_GET(bad_unwind));
155  (*hpcrun_get_real_siglongjmp())(it->jb, 9);
156 }
157 
158 
160 hpcrun_sample_callpath(void* context, int metricId,
161  hpcrun_metricVal_t metricIncr,
162  int skipInner, int isSync, sampling_info_t *data)
163 {
164  sample_val_t ret;
166 
167  if (monitor_block_shootdown()) {
168  monitor_unblock_shootdown();
169  return ret;
170  }
171 
172  // Sampling turned off by the user application.
173  // This doesn't count as a sample for the summary stats.
175  return ret;
176  }
177 
179 
181  TMSG(SAMPLE,"global suspension");
183  monitor_unblock_shootdown();
184  return ret;
185  }
186 
187  // Synchronous unwinds (pthread_create) must wait until they acquire
188  // the read lock, but async samples give up if not avail.
189  // This only applies in the dynamic case.
190 #ifndef HPCRUN_STATIC_LINK
191  if (isSync) {
192  while (! hpcrun_dlopen_read_lock()) ;
193  }
194  else if (! hpcrun_dlopen_read_lock()) {
195  TMSG(SAMPLE_CALLPATH, "skipping sample for dlopen lock");
197  monitor_unblock_shootdown();
198  return ret;
199  }
200 #endif
201 
202  TMSG(SAMPLE_CALLPATH, "attempting sample");
204 
206  sigjmp_buf_t* it = &(td->bad_unwind);
207  sigjmp_buf_t* old = td->current_jmp_buf;
208  td->current_jmp_buf = it;
209 
210  cct_node_t* node = NULL;
212 
213  // --------------------------------------
214  // start of handling sample
215  // --------------------------------------
217 
218  td->btbuf_cur = NULL;
219  td->deadlock_drop = false;
220  int ljmp = sigsetjmp(it->jb, 1);
221  if (ljmp == 0) {
222  if (epoch != NULL) {
223  void* pc = hpcrun_context_pc(context);
224 
225  TMSG(SAMPLE_CALLPATH, "%s taking profile sample @ %p", __func__, pc);
226  TMSG(SAMPLE_METRIC_DATA, "--metric data for sample (as a uint64_t) = %"PRIu64"", metricIncr);
227 
228  /* check to see if shared library loadmap (of current epoch) has changed out from under us */
229  epoch = hpcrun_check_for_new_loadmap(epoch);
230 
232  if (data != NULL)
233  data_aux = &data->sample_custom_cct;
234 
235  node = hpcrun_backtrace2cct(&(epoch->csdata), context, metricId,
236  metricIncr, skipInner, isSync, data_aux);
237 
238  if (ENABLED(DUMP_BACKTRACES)) {
239  hpcrun_bt_dump(td->btbuf_cur, "UNWIND");
240  }
241  }
242  }
243  else {
245  node = record_partial_unwind(cct, td->btbuf_beg, td->btbuf_cur - 1,
246  metricId, metricIncr, skipInner, NULL);
248  }
249  td->current_jmp_buf = old;
250 
251  // --------------------------------------
252  // end of handling sample
253  // --------------------------------------
254 
255  ret.sample_node = node;
256 
258  ip_normalized_t leaf_ip = addr->ip_norm;
259 
260  if (ip_normalized_eq(&leaf_ip, &(td->btbuf_beg->ip_norm))) {
261  // the call chain sampled has as its leaf an instruction in a user
262  // procedure. we know this because leaf_ip matches the first entry
263  // in the backtrace buffer. samples in kernel space yield a
264  // leaf_ip that is not logged in the backtrace buffer. for user
265  // space samples, the first entry in the backtrace buffer includes
266  // not only the normalized IP of the call chain leaf but also the
267  // IP of the first instruction in the enclosing function, which we
268  // use to uniquely represent the function itself. in this case, we
269  // adjust leaf_ip to point to the first IP of its enclosing
270  // function to simplify processing of procedure-level traces for
271  // call chains that are completely in user space.
272 
273  // when call chain tracing is enabled, tracing arbitrary leaf IPs
274  // for user space call chains is messy because it can cause
275  // trace-ids to be marked on multiple call chain leaves
276  // (instructions) that belong to the same source-level
277  // statement. collapsing these when call path traces are present
278  // leaves us with many trace-ids referring to the same source
279  // construct. trust me: merging here is easier :-).
280  leaf_ip = td->btbuf_beg->the_function;
281  }
282 
283  bool trace_ok = ! td->deadlock_drop;
284  TMSG(TRACE1, "trace ok (!deadlock drop) = %d", trace_ok);
285  if (trace_ok && hpcrun_trace_isactive()) {
286  TMSG(TRACE, "Sample event encountered");
287 
288  cct_addr_t frm;
289  memset(&frm, 0, sizeof(cct_addr_t));
290  frm.ip_norm = leaf_ip;
291 
292  TMSG(TRACE,"parent node = %p, &frm = %p", hpcrun_cct_parent(node), &frm);
293  cct_node_t* func_proxy =
295 
296  ret.trace_node = func_proxy;
297 
298  TMSG(TRACE, "Changed persistent id to indicate mutation of func_proxy node");
299 
300  hpcrun_trace_append(&td->core_profile_trace_data, func_proxy, metricId);
301  TMSG(TRACE, "Appended func_proxy node to trace");
302  }
303 
305  if (TD_GET(mem_low) || ENABLED(FLUSH_EVERY_SAMPLE)) {
306  hpcrun_flush_epochs(&(TD_GET(core_profile_trace_data)));
308  }
309 #ifndef HPCRUN_STATIC_LINK
311 #endif
312 
313  TMSG(SAMPLE_CALLPATH,"done w sample, return %p", ret.sample_node);
314  monitor_unblock_shootdown();
315 
316  return ret;
317 }
318 
319 static int const PTHREAD_CTXT_SKIP_INNER = 1;
320 
321 cct_node_t*
323 {
324  if (monitor_block_shootdown()) {
325  monitor_unblock_shootdown();
326  return NULL;
327  }
328 
330  TMSG(THREAD_CTXT,"global suspension");
332  monitor_unblock_shootdown();
333  return NULL;
334  }
335 
336  // Synchronous unwinds (pthread_create) must wait until they acquire
337  // the read lock, but async samples give up if not avail.
338  // This only applies in the dynamic case.
339 #ifndef HPCRUN_STATIC_LINK
340  while (! hpcrun_dlopen_read_lock()) ;
341 #endif
342 
344  sigjmp_buf_t* it = &(td->bad_unwind);
345  sigjmp_buf_t* old = td->current_jmp_buf;
346  td->current_jmp_buf = it;
347 
348  cct_node_t* node = NULL;
350 
352 
353  td->btbuf_cur = NULL;
354  int ljmp = sigsetjmp(it->jb, 1);
355  backtrace_info_t bt;
356  if (ljmp == 0) {
357  if (epoch != NULL) {
358  if (! hpcrun_generate_backtrace_no_trampoline(&bt, context,
360  hpcrun_clear_handling_sample(td); // restore state
361  EMSG("Internal error: unable to obtain backtrace for pthread context");
362  return NULL;
363  }
364  }
365  //
366  // If this backtrace is generated from sampling in a thread,
367  // take off the top 'monitor_pthread_main' node
368  //
369  if ((epoch->csdata).ctxt && ! bt.has_tramp && (bt.fence == FENCE_THREAD)) {
370  TMSG(THREAD_CTXT, "Thread correction, back off outermost backtrace entry");
371  bt.last--;
372  }
373  node = hpcrun_cct_record_backtrace(&(epoch->csdata), false, &bt,
374  bt.has_tramp);
375  }
376  // restore back the sigjmp
377  td->current_jmp_buf = old;
378 
379  // FIXME: What to do when thread context is partial ?
380 #if 0
381  else {
382  cct_bundle_t* cct = &(td->epoch->csdata);
383  node = record_partial_unwind(cct, td->btbuf_beg, td->btbuf_cur - 1,
384  metricId, metricIncr);
386  }
387 #endif
389  if (TD_GET(mem_low) || ENABLED(FLUSH_EVERY_SAMPLE)) {
390  hpcrun_flush_epochs(&(TD_GET(core_profile_trace_data)));
392  }
393 #ifndef HPCRUN_STATIC_LINK
395 #endif
396 
397  TMSG(THREAD,"done w pthread ctxt");
398  monitor_unblock_shootdown();
399 
400  return node;
401 }
402 
fence_enum_t fence
void hpcrun_set_handling_sample(thread_data_t *td)
void hpcrun_stats_num_samples_dropped_inc(void)
Definition: hpcrun_stats.c:187
void hpcrun_stats_num_samples_blocked_dlopen_inc(void)
Definition: hpcrun_stats.c:168
bool deadlock_drop
Definition: thread_data.h:215
static void hpcrun_cleanup_partial_unwind(void)
Definition: sample_event.c:97
static int const PTHREAD_CTXT_SKIP_INNER
Definition: sample_event.c:319
struct cct_custom_update_s sample_custom_cct
Definition: sample_event.h:121
void hpcrun_stats_num_samples_total_inc(void)
Definition: hpcrun_stats.c:108
bool private_hpcrun_sampling_disabled
Definition: sample_event.c:148
void hpcrun_stats_num_samples_attempted_inc(void)
Definition: hpcrun_stats.c:127
void hpcrun_dlopen_read_unlock(void)
Definition: hpcrun_dlfns.c:172
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 hpcrun_stats_num_samples_partial_inc(void)
Definition: hpcrun_stats.c:203
ip_normalized_t ip_norm
Definition: frame.h:61
static spinlock_t fnbounds_lock
frame_t * btbuf_cur
Definition: thread_data.h:184
void hpcrun_trace_append(core_profile_trace_data_t *cptd, cct_node_t *node, uint metric_id)
Definition: trace.c:173
ip_normalized_t the_function
Definition: frame.h:62
cct_node_t * node
Definition: cct.c:128
static bool hpcrun_is_sampling_disabled(void)
Definition: sample_event.h:73
sigjmp_buf_t bad_unwind
Definition: thread_data.h:213
cct_node_t * sample_node
Definition: sample_event.h:96
cct_node_t * hpcrun_cct_record_backtrace(cct_bundle_t *cct, bool partial, backtrace_info_t *bt, bool tramp_found)
cct_node_t * hpcrun_cct_record_backtrace_w_metric(cct_bundle_t *cct, bool partial, backtrace_info_t *bt, bool tramp_found, int metricId, hpcrun_metricVal_t metricIncr, struct cct_custom_update_s *custom_update)
void hpcrun_all_sources_stop(void)
bool hpcrun_generate_backtrace_no_trampoline(backtrace_info_t *bt, ucontext_t *context, int skipInner)
Definition: backtrace.c:178
void fnbounds_release_lock(void)
cct_node_t * hpcrun_cct_parent(cct_node_t *x)
Definition: cct.c:357
cct_bundle_t csdata
Definition: epoch.h:65
void hpcrun_up_pmsg_count(void)
cct_node_t * hpcrun_cct_insert_addr(cct_node_t *node, cct_addr_t *frm)
Definition: cct.c:405
int hpcrun_dlopen_read_lock(void)
Definition: hpcrun_dlfns.c:156
int hpcrun_trace_isactive()
Definition: trace.c:107
void hpcrun_flush_epochs(core_profile_trace_data_t *cptd)
Definition: write_data.c:318
#define EMSG
Definition: messages.h:70
epoch_t * hpcrun_check_for_new_loadmap(epoch_t *epoch)
Definition: epoch.c:85
core_profile_trace_data_t core_profile_trace_data
Definition: thread_data.h:168
ip_normalized_t ip_norm
Definition: cct_addr.h:66
sigjmp_buf_t * current_jmp_buf
Definition: thread_data.h:211
Definition: epoch.h:64
cct_node_t * hpcrun_backtrace2cct(cct_bundle_t *cct, ucontext_t *context, int metricId, hpcrun_metricVal_t metricIncr, int skipInner, int isSync, struct cct_custom_update_s *custom_update)
#define TD_GET(field)
Definition: thread_data.h:256
frame_t * hpcrun_skip_chords(frame_t *bt_outer, frame_t *bt_inner, int skip)
Definition: backtrace.c:152
#define TMSG(f,...)
Definition: messages.h:93
static bool ip_normalized_eq(const ip_normalized_t *a, const ip_normalized_t *b)
Definition: ip-normalized.h:94
void hpcrun_clear_handling_sample(thread_data_t *td)
#define NULL
Definition: ElfHelper.cpp:85
cct_node_t * hpcrun_gen_thread_ctxt(void *context)
Definition: sample_event.c:322
Definition: cct.c:96
void hpcrun_drop_sample(void)
Definition: sample_event.c:151
int hpctoolkit_sampling_is_active(void)
Definition: start-stop.c:100
frame_t * btbuf_beg
Definition: thread_data.h:185
Definition: frame.h:58
void hpcrun_bt_dump(frame_t *unwind, const char *tag)
Definition: backtrace.c:90
cct_addr_t * addr
Definition: cct.c:130
void hpcrun_reclaim_freeable_mem(void)
Definition: mem.c:260
siglongjmp_fcn * hpcrun_get_real_siglongjmp(void)
Definition: main.c:1142
void * hpcrun_context_pc(void *context)
sigjmp_buf jb
Definition: thread_data.h:74
static cct_node_t * record_partial_unwind(cct_bundle_t *cct, frame_t *bt_beg, frame_t *bt_last, int metricId, hpcrun_metricVal_t metricIncr, int skipInner, struct cct_custom_update_s *custom_update)
Definition: sample_event.c:116
static void hpcrun_sample_val_init(sample_val_t *x)
Definition: sample_event.h:102
#define ENABLED(f)
Definition: debug-flag.h:76
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
cct_node_t * trace_node
Definition: sample_event.h:97
cct_addr_t * hpcrun_cct_addr(cct_node_t *node)
Definition: cct.c:369