HPCToolkit
tst.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 // _tst sample source simple oo interface
49 //
50 
51 /******************************************************************************
52  * system includes
53  *****************************************************************************/
54 
55 #include <errno.h>
56 #include <stddef.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <assert.h>
60 
61 #include <signal.h>
62 #include <sys/time.h> /* setitimer() */
63 #include <ucontext.h> /* struct ucontext */
64 
65 
66 /******************************************************************************
67  * libmonitor
68  *****************************************************************************/
69 
70 #include <monitor.h>
71 
72 
73 /******************************************************************************
74  * local includes
75  *****************************************************************************/
76 #include "sample_source_obj.h"
77 #include "common.h"
78 #include "ss-errno.h"
79 
80 #include <hpcrun/hpcrun_options.h>
81 #include <hpcrun/hpcrun_stats.h>
82 
83 #include <hpcrun/metrics.h>
84 #include <hpcrun/safe-sampling.h>
85 #include <hpcrun/sample_event.h>
87 #include <hpcrun/thread_data.h>
88 
89 #include <lush/lush-backtrace.h>
90 #include <messages/messages.h>
91 
92 #include <utilities/tokenize.h>
94 
95 #include <unwind/common/unwind.h>
96 
97 #include <lib/support-lean/timer.h>
98 
99 /******************************************************************************
100  * macros
101  *****************************************************************************/
102 
103 #if defined(CATAMOUNT)
104 # define HPCRUN_PROFILE_SIGNAL SIGALRM
105 # define HPCRUN_PROFILE_TIMER ITIMER_REAL
106 #else
107 # define HPCRUN_PROFILE_SIGNAL SIGPROF
108 # define HPCRUN_PROFILE_TIMER ITIMER_PROF
109 #endif
110 
111 #define SECONDS_PER_HOUR 3600
112 
113 #if !defined(HOST_SYSTEM_IBM_BLUEGENE)
114 # define USE_ELAPSED_TIME_FOR_WALLCLOCK
115 #endif
116 
117 #define RESET_ITIMER_EACH_SAMPLE
118 
119 #if defined(RESET_ITIMER_EACH_SAMPLE)
120 
121 # if defined(HOST_SYSTEM_IBM_BLUEGENE)
122  //--------------------------------------------------------------------------
123  // Blue Gene/P compute node support for itimer incorrectly delivers SIGALRM
124  // in one-shot mode. To sidestep this problem, we use itimer in
125  // interval mode, but with an interval so long that we never expect to get
126  // a repeat interrupt before resetting it.
127  //--------------------------------------------------------------------------
128 # define AUTOMATIC_ITIMER_RESET_SECONDS(x) (SECONDS_PER_HOUR)
129 # define AUTOMATIC_ITIMER_RESET_MICROSECONDS(x) (0)
130 # else // !defined(HOST_SYSTEM_IBM_BLUEGENE)
131 # define AUTOMATIC_ITIMER_RESET_SECONDS(x) (0)
132 # define AUTOMATIC_ITIMER_RESET_MICROSECONDS(x) (0)
133 # endif // !defined(HOST_SYSTEM_IBM_BLUEGENE)
134 
135 #else // !defined(RESET_ITIMER_EACH_SAMPLE)
136 
137 # define AUTOMATIC_ITIMER_RESET_SECONDS(x) (x)
138 # define AUTOMATIC_ITIMER_RESET_MICROSECONDS(x) (x)
139 
140 #endif // !defined(RESET_ITIMER_EACH_SAMPLE)
141 
142 #define DEFAULT_THRESHOLD 5000L
143 
144 /******************************************************************************
145  * local constants
146  *****************************************************************************/
147 
149  _TST_EVENT = 0 // _tst has only 1 event
150 };
151 
152 /******************************************************************************
153  * forward declarations
154  *****************************************************************************/
155 
156 static int
157 _tst_signal_handler(int sig, siginfo_t *siginfo, void *context);
158 
159 
160 /******************************************************************************
161  * local variables
162  *****************************************************************************/
163 
164 static struct itimerval itimer;
165 
166 static const struct itimerval zerotimer = {
167  .it_interval = {
168  .tv_sec = 0L,
169  .tv_usec = 0L
170  },
171 
172  .it_value = {
173  .tv_sec = 0L,
174  .tv_usec = 0L
175  }
176 
177 };
178 
179 static long period = DEFAULT_THRESHOLD;
180 
181 static sigset_t sigset_itimer;
182 
183 // ******* METHOD DEFINITIONS ***********
184 
185 static void
187 {
188  self->state = INIT; // no actual init actions necessary for _tst
189 }
190 
191 static void
192 METHOD_FN(thread_init)
193 {
194 }
195 
196 static void
197 METHOD_FN(thread_init_action)
198 {
199 }
200 
201 static void
202 METHOD_FN(start)
203 {
204  if (! hpcrun_td_avail()){
205  return; // in the unlikely event that we are trying to start, but thread data is unavailable,
206  // assume that all sample source ops are suspended.
207  }
208 
209  TMSG(_TST_CTL,"starting _tst w value = (%d,%d), interval = (%d,%d)",
210  itimer.it_interval.tv_sec,
211  itimer.it_interval.tv_usec,
212  itimer.it_value.tv_sec,
213  itimer.it_value.tv_usec);
214 
215  if (setitimer(HPCRUN_PROFILE_TIMER, &itimer, NULL) != 0) {
216  EMSG("setitimer failed (%d): %s", errno, strerror(errno));
217  hpcrun_ssfail_start("_tst");
218  }
219 
220 #ifdef USE_ELAPSED_TIME_FOR_WALLCLOCK
221  int ret = time_getTimeCPU(&TD_GET(last_time_us));
222  if (ret != 0) {
223  EMSG("time_getTimeCPU (clock_gettime) failed!");
224  abort();
225  }
226 #endif
227 
228  TD_GET(ss_state)[self->sel_idx] = START;
229 }
230 
231 static void
232 METHOD_FN(thread_fini_action)
233 {
234 }
235 
236 static void
238 {
239  int rc;
240 
241  rc = setitimer(HPCRUN_PROFILE_TIMER, &zerotimer, NULL);
242 
243  TMSG(ITIMER_CTL,"stopping _tst");
244  TD_GET(ss_state)[self->sel_idx] = STOP;
245 }
246 
247 static void
248 METHOD_FN(shutdown)
249 {
250  METHOD_CALL(self, stop); // make sure stop has been called
251  self->state = UNINIT;
252 }
253 
254 static bool
255 METHOD_FN(supports_event, const char *ev_str)
256 {
257  return hpcrun_ev_is(ev_str,"_TST");
258 }
259 
260 static void
261 METHOD_FN(process_event_list, int lush_metrics)
262 {
263 
264  // fetch the event string for the sample source
265  char* _p = METHOD_CALL(self, get_event_str);
266 
267  //
268  // EVENT: Only 1 wallclock event
269  //
270  char* event = start_tok(_p);
271 
272  char name[1024]; // local buffer needed for extract_ev_threshold
273 
274  TMSG(_TST_CTL,"checking event spec = %s",event);
275 
276  // extract event threshold
277  hpcrun_extract_ev_thresh(event, sizeof(name), name, &period, DEFAULT_THRESHOLD);
278 
279  // store event threshold
280  METHOD_CALL(self, store_event, _TST_EVENT, period);
281  TMSG(OPTIONS,"_TST period set to %ld",period);
282 
283  // set up file local variables for sample source control
284  int seconds = period / 1000000;
285  int microseconds = period % 1000000;
286 
287  TMSG(OPTIONS,"init timer w sample_period = %ld, seconds = %ld, usec = %ld",
288  period, seconds, microseconds);
289 
290  // signal once after the given delay
291  itimer.it_value.tv_sec = seconds;
292  itimer.it_value.tv_usec = microseconds;
293 
294  // macros define whether automatic restart or not
295  itimer.it_interval.tv_sec = AUTOMATIC_ITIMER_RESET_SECONDS(seconds);
296  itimer.it_interval.tv_usec = AUTOMATIC_ITIMER_RESET_MICROSECONDS(microseconds);
297 
298  // handle metric allocation
299  hpcrun_pre_allocate_metrics(1 + lush_metrics);
300 
301  int metric_id = hpcrun_new_metric();
302  METHOD_CALL(self, store_metric_id, _TST_EVENT, metric_id);
303 
304  // set metric information in metric table
305 
306 #ifdef USE_ELAPSED_TIME_FOR_WALLCLOCK
307 # define sample_period 1
308 #else
309 # define sample_period period
310 #endif
311 
312  TMSG(_TST_CTL, "setting metric _TST, period = %ld", sample_period);
313  hpcrun_set_metric_info_and_period(metric_id, "_TST",
316  if (lush_metrics == 1) {
317  int mid_idleness = hpcrun_new_metric();
318  lush_agents->metric_time = metric_id;
319  lush_agents->metric_idleness = mid_idleness;
320 
321  hpcrun_set_metric_info_and_period(mid_idleness, "idleness (ms)",
324  }
325 
326  event = next_tok();
327  if (more_tok()) {
328  EMSG("MULTIPLE _TST events detected! Using first event spec: %s");
329  }
330 }
331 
332 //
333 // Event "sets" not possible for this sample source.
334 // It has only 1 event.
335 // Initialize the sigset and installing the signal handler are
336 // the only actions
337 //
338 static void
339 METHOD_FN(gen_event_set, int lush_metrics)
340 {
341  sigemptyset(&sigset_itimer);
343  monitor_sigaction(HPCRUN_PROFILE_SIGNAL, &_tst_signal_handler, 0, NULL);
344 }
345 
346 static void
347 METHOD_FN(display_events)
348 {
349  //
350  // normally _tst does not display events
351  // DEVELOPER ONLY: modify this method in your sandbox as needed
352  //
353 
354 #ifdef DISPLAY_TEST_EVENTS
355  printf("===========================================================================\n");
356  printf("Available _tst events\n");
357  printf("===========================================================================\n");
358  printf("Name\t\tDescription\n");
359  printf("---------------------------------------------------------------------------\n");
360  printf("WALLCLOCK\tWall clock time used by the process in microseconds\n");
361  printf("\n");
362 #endif
363 }
364 
365 /***************************************************************************
366  * object
367  ***************************************************************************/
368 
369 #define ss_name _tst
370 #define ss_cls SS_HARDWARE
371 
372 #include "ss_obj.h"
373 
374 /******************************************************************************
375  * private operations
376  *****************************************************************************/
377 
378 static int
379 _tst_signal_handler(int sig, siginfo_t* siginfo, void* context)
380 {
382 
383  // If the interrupt came from inside our code, then drop the sample
384  // and return and avoid any MSG.
385  void* pc = hpcrun_context_pc(context);
386  if (! hpcrun_safe_enter_async(pc)) {
388  }
389  else {
390  TMSG(_TST_HANDLER,"_Tst sample event");
391 
392  uint64_t metric_incr = 1; // default: one time unit
393 #ifdef USE_ELAPSED_TIME_FOR_WALLCLOCK
394  uint64_t cur_time_us;
395  int ret = time_getTimeCPU(&cur_time_us);
396  if (ret != 0) {
397  EMSG("time_getTimeCPU (clock_gettime) failed!");
398  abort();
399  }
400  metric_incr = cur_time_us - TD_GET(last_time_us);
401 #endif
402 
403  int metric_id = hpcrun_event2metric(&__tst_obj, _TST_EVENT);
404  hpcrun_sample_callpath_w_bt(context, metric_id, metric_incr, NULL, NULL, 0);
405  }
407  TMSG(SPECIAL, "No _tst restart, due to disabled sampling");
408 
410 
411  return 0; // tell monitor that the signal has been handled
412  }
413 
414 #ifdef RESET_ITIMER_EACH_SAMPLE
415  METHOD_CALL(&__tst_obj, start);
416 #endif
417 
419 
420  return 0; // tell monitor that the signal has been handled
421 }
static const struct itimerval zerotimer
Definition: tst.c:166
#define AUTOMATIC_ITIMER_RESET_SECONDS(x)
Definition: tst.c:131
#define HPCTOOLKIT_APPLICATION_ERRNO_RESTORE()
Definition: ss-errno.h:64
static void METHOD_FN(init)
Definition: tst.c:186
abort
Definition: names.cpp:1
static bool hpcrun_is_sampling_disabled(void)
Definition: sample_event.h:73
cct_node_t * hpcrun_sample_callpath_w_bt(void *context, int metricId, uint64_t metricIncr, bt_mut_fn bt_fn, bt_fn_arg arg, int isSync)
#define sample_period
bool(* hpcrun_td_avail)(void)
Definition: thread_data.c:169
void hpcrun_stats_num_samples_blocked_async_inc(void)
Definition: hpcrun_stats.c:148
char * next_tok(void)
Definition: tokenize.c:87
metric_desc_t * hpcrun_set_metric_info_and_period(int metric_id, const char *name, MetricFlags_ValFmt_t valFmt, size_t period, metric_desc_properties_t prop)
Definition: metrics.c:411
#define EMSG
Definition: messages.h:70
static long period
Definition: tst.c:179
_local_const
Definition: main.c:164
static int time_getTimeCPU(uint64_t *time)
Definition: timer.h:124
char * start_tok(char *lst)
Definition: tokenize.c:70
int lush_metrics
Definition: main.c:188
void hpcrun_ssfail_start(char *source)
Definition: common.c:265
#define TD_GET(field)
Definition: thread_data.h:256
bool hpcrun_ev_is(const char *candidate, const char *event_name)
Definition: tokenize.c:194
#define DEFAULT_THRESHOLD
Definition: tst.c:142
#define HPCRUN_PROFILE_TIMER
Definition: tst.c:108
int metric_idleness
Definition: lush.h:96
#define TMSG(f,...)
Definition: messages.h:93
static sigset_t sigset_itimer
Definition: tst.c:181
int hpcrun_extract_ev_thresh(const char *in, int evlen, char *ev, long *th, long def)
Definition: tokenize.c:157
static int hpcrun_safe_enter_async(void *pc)
int hpcrun_event2metric(sample_source_t *ss, int event_idx)
Definition: common.c:143
static struct itimerval itimer
Definition: tst.c:164
#define METHOD_CALL(obj, meth,...)
Definition: simple_oo.h:87
#define NULL
Definition: ElfHelper.cpp:85
int hpcrun_new_metric(void)
Definition: metrics.c:333
#define HPCTOOLKIT_APPLICATION_ERRNO_SAVE()
Definition: ss-errno.h:63
void hpcrun_pre_allocate_metrics(size_t num)
Definition: metrics.c:190
void * hpcrun_context_pc(void *context)
#define AUTOMATIC_ITIMER_RESET_MICROSECONDS(x)
Definition: tst.c:132
static int _tst_signal_handler(int sig, siginfo_t *siginfo, void *context)
Definition: tst.c:379
lush_agent_pool_t * lush_agents
int more_tok(void)
Definition: tokenize.c:78
#define HPCRUN_PROFILE_SIGNAL
Definition: tst.c:107
#define metric_property_none
Definition: hpcrun-fmt.h:202
int metric_time
Definition: lush.h:95