cct_node_t* hpcrun_cct_record_backtrace_w_metric(cct_bundle_t* cct, bool partial, bool thread_stop, frame_t* bt_beg, frame_t* bt_last, bool tramp_found, int metricId, uint64_t metricIncr) { TMSG(FENCE, "Recording backtrace"); TMSG(BT_INSERT, "Record backtrace w metric to id %d, incr = %d", metricId, metricIncr); thread_data_t* td = hpcrun_get_thread_data(); cct_node_t* cct_cursor = cct->tree_root; TMSG(FENCE, "Initially picking tree root = %p", cct_cursor); if (tramp_found) { // start insertion below caller's frame, which is marked with the trampoline cct_cursor = hpcrun_cct_parent(td->tramp_cct_node); TMSG(FENCE, "Tramp found ==> cursor = %p", cct_cursor); } if (partial) { cct_cursor = cct->partial_unw_root; TMSG(FENCE, "Partial unwind ==> cursor = %p", cct_cursor); } if (thread_stop) { cct_cursor = cct->thread_root; TMSG(FENCE, "Thread stop ==> cursor = %p", cct_cursor); } TMSG(FENCE, "sanity check cursor = %p", cct_cursor); TMSG(FENCE, "further sanity check: bt_last frame = (%d, %p)", bt_last->ip_norm.lm_id, bt_last->ip_norm.lm_ip); return hpcrun_cct_insert_backtrace_w_metric(cct_cursor, metricId, bt_last, bt_beg, (cct_metric_data_t){.i = metricIncr});
// // Actually drop a sample, as opposed to recording a partial unwind // void hpcrun_unw_drop(void) { thread_data_t* td = hpcrun_get_thread_data(); td->btbuf_cur = td->btbuf_beg; // flush any collected backtrace frames sigjmp_buf_t *it = &(td->bad_unwind); (*hpcrun_get_real_siglongjmp())(it->jb, 9); }
static void METHOD_FN(shutdown) { METHOD_CALL(self, stop); // make sure stop has been called TMSG(ITIMER_CTL, "shutdown %s", the_event_name); // delete the realtime timer to avoid a timer leak if (use_realtime || use_cputime) { thread_data_t *td = hpcrun_get_thread_data(); hpcrun_delete_real_timer(td); } self->state = UNINIT; }
// Factor out the body of the start method so we can restart itimer // without messages in the case that we are interrupting our own code. // safe = 1 if not inside our code, so ok to print debug messages // static void hpcrun_restart_timer(sample_source_t *self, int safe) { int ret; // if thread data is unavailable, assume that all sample source ops // are suspended. if (! hpcrun_td_avail()) { if (safe) { TMSG(ITIMER_CTL, "Thread data unavailable ==> sampling suspended"); } return; } thread_data_t *td = hpcrun_get_thread_data(); if (safe) { TMSG(ITIMER_HANDLER, "starting %s: value = (%d,%d), interval = (%d,%d)", the_event_name, itval_start.it_value.tv_sec, itval_start.it_value.tv_usec, itval_start.it_interval.tv_sec, itval_start.it_interval.tv_usec); } ret = hpcrun_start_timer(td); if (ret != 0) { if (safe) { TMSG(ITIMER_CTL, "setitimer failed to start!!"); EMSG("setitimer failed (%d): %s", errno, strerror(errno)); } hpcrun_ssfail_start("itimer"); } #ifdef USE_ELAPSED_TIME_FOR_WALLCLOCK ret = time_getTimeReal(&TD_GET(last_time_us)); if (ret != 0) { if (safe) { EMSG("time_getTimeReal (clock_gettime) failed!"); } monitor_real_abort(); } #endif TD_GET(ss_state)[self->sel_idx] = START; }
static void METHOD_FN(stop) { TMSG(ITIMER_CTL, "stop %s", the_event_name); // itimer is process-wide, so it's worth blocking the signal in the // current thread at stop time. if (use_itimer) { monitor_real_pthread_sigmask(SIG_BLOCK, &timer_mask, NULL); } thread_data_t *td = hpcrun_get_thread_data(); int rc = hpcrun_stop_timer(td); if (rc != 0) { EMSG("stop %s failed, errno: %d", the_event_name, errno); } TD_GET(ss_state)[self->sel_idx] = STOP; }
static void METHOD_FN(start) { TMSG(ITIMER_CTL, "start %s", the_event_name); // the realtime clock needs an extra step to create the timer if (use_realtime || use_cputime) { thread_data_t *td = hpcrun_get_thread_data(); if (hpcrun_create_real_timer(td) != 0) { EEMSG("Unable to create the timer for %s", the_event_name); hpcrun_ssfail_start(the_event_name); } } // itimer is process-wide, so reopen the signal at start time if (use_itimer) { monitor_real_pthread_sigmask(SIG_UNBLOCK, &timer_mask, NULL); } hpcrun_restart_timer(self, 1); }