HPCToolkit
generic.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 // A generic sample source object file
49 //
50 // There are no actual "generic" sample sources.
51 // This file is provided as a template for those who wish to add
52 // additional sample sources to the hpctoolkit.
53 //******************************************************************************
54 
55 
56 /******************************************************************************
57  * system includes
58  *****************************************************************************/
59 
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <ucontext.h>
64 #include <pthread.h>
65 #include <stdbool.h>
66 
67 /******************************************************************************
68  * libmonitor
69  *****************************************************************************/
70 
71 #include <monitor.h>
72 
73 
74 // *****************************************************************************
75 // local includes
76 // *****************************************************************************
77 
78 #include "simple_oo.h"
79 #include "sample_source_obj.h"
80 #include "common.h"
81 #include "ss-errno.h"
82 
83 #include <hpcrun/hpcrun_options.h>
84 #include <hpcrun/hpcrun_stats.h>
85 #include <hpcrun/metrics.h>
86 #include <hpcrun/safe-sampling.h>
88 #include <hpcrun/sample_event.h>
89 #include <hpcrun/thread_data.h>
90 #include <utilities/tokenize.h>
92 #include <messages/messages.h>
93 #include <lush/lush-backtrace.h>
95 
96 // *****************************************************************************
97 // (file) local variables
98 //
99 // *****************************************************************************
100 
101 //
102 // Sample source specific control info
103 // (example: itimer uses itimerval)
104 // Some sample sources may not need this kind of local variable
105 //
106 static struct SOME_STRUCT ss_specific_data;
107 
108 //
109 // Almost all sample sources have events. The local data below keeps track of
110 // event info, and metric info.
111 //
112 // NOTE: some very unusual sample sources may not have any events. (see 'none' sample source)
113 // In this case, the event & metric tracking data structures can likely be dispensed with
114 
115 //
116 // For sample sources that may have multiple events:
117 // You will likely need to keep a count of the specified events, plus thresholds
118 // event codes, & other info
119 //
120 // The sample code below uses a simple array of a fixed size to give the general idea
121 // If you need dynamically sized event info, use hpcrun_malloc instead of regular malloc.
122 //
123 
124 struct event_info { // Typical structure to hold event info
125  int code;
126  long thresh;
127 };
128 
129 static int n_events = 0; // # events for this sample source
130 static const int MAX_EVENTS = SAMPLE_SOURCE_SPECIFIC;
131 static struct event_info local_event[MAX_EVENTS]; // event codes (derived from event names usually)
132 static const long DEFAULT_THRESHOLD = 1000000L; // sample source specific
133 
134 //
135 // Sample source events almost always get at least 1 metric slot.
136 // Some events may have multiple metrics.
137 //
138 // The declarations below show a simple structure with MAX_METRICS per event,
139 // and the same MAX_EVENTS in the sample event data structure above
140 //
141 // NOTE 1: The metric info may be included in the event data structure
142 // It is separated here for illustration
143 //
144 // NOTE 2: If a sample source has no events (highly unusual, but see 'none' sample source),
145 // then the data structures below are likely unnecessary
146 
147 int metrics [MAX_EVENTS] [MAX_METRICS];
148 
149 //***********************************************************
150 // forward definitions:
151 //
152 // see comments with the handler source
153 // (further down in this file) for more info
154 //***********************************************************
155 
156 static int
157 generic_signal_handler(int sig, siginfo_t* siginfo, void* context);
158 
159 //******************************************************************************
160 // The method definitions listed below are all required. They do not have to
161 // actually do anything (except where noted), but they must all be present.
162 //******************************************************************************
163 
164 
165 // ******* METHOD DEFINITIONS ***********
166 
167 static void
169 {
170  //
171  // This method covers LIBRARY init operations only.
172  // Other init takes place in subsequent operations
173  //
174  // There may be no library init actions for some sample sources
175  // (itimer for example).
176  // See papi.c for an example of non-trivial library init requirements
177  //
178 
179  // the following statement must always appears at the end of the init method
180  self->state = INIT;
181 }
182 
183 //
184 // Many sample sources require additional initialization when employed in
185 // threaded programs.
186 // The 'thread_init' method is the hook to supply the additional initialization
187 //
188 
189 static void
190 METHOD_FN(thread_init)
191 {
192  // sample source thread init code here
193 }
194 
195 //
196 // Some sample sources may require each thread function to take some 'thread_init_action'
197 // whenever a thread is started
198 // [ For example, PAPI source uses 'PAPI_register_thread' function ]
199 //
200 
201 static void
202 METHOD_FN(thread_init_action)
203 {
204 }
205 
206 static void
207 METHOD_FN(start)
208 {
209 
210  // The following test MUST appear in all start methods
211 
212  if (! hpcrun_td_avail()){
213  return; // in the unlikely event that we are trying to start, but thread data is unavailable,
214  // assume that all sample source ops are suspended.
215  }
216 
217 
218  // (Optional) Debug message
219  // You are not limited in any way here. You may liberally sprinkle various
220  // debug messages throughout this (and any other) method definition.
221  //
222  TMSG(YOUR_MSG_CLASS, "your debug message about the sample source being started");
223 
224  //
225  // Sample-source specific code goes here.
226  //
227  // If there are any auxilliary data that the start mechanism needs,
228  // declare some static local variables (see the local variables section
229  // near the top of the file).
230  // The values for these local variables can be set in either the 'gen_event_set'
231  // method or the 'process_event_list' method
232  // examples:
233  // itimer uses a 'struct itimerval' local variable
234 
235 
236  // if your sample source returns some success/fail status, then you can
237  // test it here, and log an error message
238  //
239  if (sample_source_start == FAIL) {
240  EMSG("YOUR ERROR MESSAGE HERE: (%d): %s", YOUR_errno, YOUR_errorstring);
241  hpcrun_ssfail_start("GENERIC");
242  }
243 
244  // This line must always appear at the end of a start method
245  TD_GET(ss_state)[self->sel_idx] = START;
246 }
247 
248 //
249 // Some sample sources may require each thread function to take some 'thread_fini_action'
250 // whenever the thread is shut down.
251 // [ For example, PAPI source uses 'PAPI_unregister_thread' function ]
252 //
253 
254 static void
255 METHOD_FN(thread_fini_action)
256 {
257 }
258 
259 static void
261 {
262  //
263  // sample-source specific stopping code goes here
264  //
265  // Similar to the 'start' method, if the 'stop' method needs any auxilliary data
266  // declare some static local variables (see the local variables section
267  // near the top of the file).
268  // The values for these local variables can be set in either the 'gen_event_set'
269  // method or the 'process_event_list' method
270  // examples:
271  // itimer uses a 'struct itimerval zerotimer' local variable to hold the relevant
272  // itimer information
273 
274  // if your sample source returns some success/fail status, then you can
275  // test it here, and log an error message
276  if (sample_source_stop == FAIL) {
277  EMSG("YOUR ERROR MESSAGE HERE: (%d): %s", YOUR_errno, YOUR_errorstring);
278  hpcrun_ssfail_start("GENERIC");
279  }
280 
281  // (Optional) debug message
282  TMSG(YOUR_MESSAGE_CLASS,"your stop message %p : %s", your_optional_arg1, your_optional_arg2);
283 
284  // This line must always appear at the end of a stop method
285  TD_GET(ss_state)[self->sel_idx] = STOP;
286 }
287 
288 static void
289 METHOD_FN(shutdown)
290 {
291  //
292  // Sample source specific shutdown code goes here
293  //
294  //
295 
296  // debug messages and error messages can go here
297 
298  // These lines must always appear at the end of a shutdown method
299 
300  METHOD_CALL(self, stop); // make sure stop has been called
301  self->state = UNINIT;
302 }
303 
304 static bool
305 METHOD_FN(supports_event, const char *ev_str)
306 {
307  //
308  // The event string argument contains the event specifications from
309  // the command line.
310  //
311  // NOTE: You are guaranteed that the 'init' method for your sample source
312  // has been invoked before any 'supports_event' method calls are invoked
313  //
314  // For simple event specs, a call to "hpcrun_ev_is" is sufficient. (see below)
315  // For a more involved check on events, see papi.c
316 
317  return hpcrun_ev_is(ev_str,"YOUR_SOURCE");
318 }
319 
320 static void
321 METHOD_FN(process_event_list, int lush_metrics)
322 {
323  // The lush_metrics argument is always passed in.
324  // If your sample source does not support lush, then ignore this argument
325  // in your event_list_processing.
326  //
327  // When this method is invoked, previous sample source processing
328  // has concatenated all of the event specs
329  // for this sample_source into 1 string (event specs came from the command line)
330  // The 'process_event_list' method takes care of several things:
331  // * Processing period information [ event specs are of the form NAME@PERIOD ]
332  // * Setting up local variables with the appropriate information for start/stop
333  // (although some of this may be done in 'gen_event_set' method)
334  // * Allocate metrics for each event [ including lush, if appropriate ]
335  // * Enter period, processing function, flags, name, etc
336  // for each metric of each event
337  // [ in general, each sample source MAY HAVE multiple events. Each event
338  // MAY HAVE multiple metrics associated with it ]
339  //
340 
341  // fetch the event string for the sample source
342  char* _p = METHOD_CALL(self, get_event_str);
343 
344 
345  // ** You MAY BE able to pre-allocate metrics for your sample source **
346  // if so, you should do that before the main event processing loop
347  //
348  // Example of preallocation:
349  // hpcrun_pre_allocate_metrics(1 + lush_metrics);
350 
351  //
352  // EVENT: for each event in the event spec
353  //
354  for (char* event = start_tok(_p); more_tok(); event = next_tok()) {
355  // (loop) local variables for useful for decoding event specification strings
356  char name[1024];
357  long thresh;
358 
359  // extract event threshold
360  hpcrun_extract_ev_thresh(event, sizeof(name), name, &thresh, DEFAULT_THRESHOLD);
361 
362  // process events, store whatever is needed for starting/stopping
363  // the sample source in the file local variable
364  //
365  // (The amt of processing may be very small (i.e. itimer) or more involved (i.e. papi)
366 
367  local_event[n_events].code = YOUR_NAME_TO_CODE(event);
369 
370  // for each event, process metrics for that event
371  // If there is only 1 metric for each event, then the loop is unnecessary
372  //
373  // **NOTE: EVERY sample source that has metrics MUST have file (local) storage
374  // to track the metric ids.
375  //
376  for (int i=0; i < NUM_METRICS_FOR_EVENT(event); i++) {
377  int metric_id = hpcrun_new_metric();
378  metrics[n_events][i] = metric_id;
379 
380  if (METRIC_IS_STANDARD) {
381  // For a standard updating metric (add some counts at each sample time), use
382  // hpcrun_set_metric_info_and_period routine, as shown below
383  //
384  hpcrun_set_metric_info_and_period(metric_id, NAME_FOR_EVENT_METRIC(event, i),
385  HPCRUN_MetricFlag_Async, // This is the correct flag value for almost all events
386  thresh, metric_property_none);
387  }
388  else { // NON STANDARD METRIC
389  // For a metric that updates in a NON standard fashion, use
390  // hpcrun_set_metric_info_w_fn, and pass the updating function as the last argument
391  //
392  hpcrun_set_metric_info_w_fn(metric_id, NAME_FOR_EVENT_METRIC(event, i),
393  YOUR_FLAG_VALUES, thresh,
394  YOUR_UPD_FN);
395  }
396  }
397  n_events++;
398  }
399 
400  // NOTE: some lush-aware event list processing may need to be done here ...
401 
402 }
403 
404 static void
405 METHOD_FN(gen_event_set, int lush_metrics)
406 {
407  // The lush_metrics argument is always passed in.
408  // If your sample source does not support lush, then ignore this argument
409  // in your gen_event_set processing.
410  //
411  // When this method is invoked, the event list has been processed, and all of the
412  // event list info is now in local variables.
413  // This method sets up the handlers.
414  // It is called once for each thread.
415  //
416  // Sample code below assumes the handler is a standard unix signal handler.
417  // If that is not true for your sample source, then follow the appropriate protocol
418  // for your source.
419  //
420  // NOTE: use 'monitor_sigaction' instead of the system 'sigaction' when setting up
421  // standard signal handlers.
422  //
423  sigemptyset(&sigset_generic);
424  sigaddset(&sigset_generic, HPCRUN_GENERIC_SIGNAL);
425  monitor_sigaction(HPCRUN_GENERIC_SIGNAL, &generic_signal_handler, 0, NULL);
426 }
427 
428 static void
429 METHOD_FN(display_events)
430 {
431  //
432  // This method displays descriptive text about the sample source
433  // This text is printed whenever the '-L' argument is given to hpcrun
434  //
435  printf("===========================================================================\n");
436  printf("Available generic events\n");
437  printf("===========================================================================\n");
438  printf("Name\t\tDescription\n");
439  printf("---------------------------------------------------------------------------\n");
440  printf("GENERIC EVENT\tWhat the generic event does\n");
441  printf("\n");
442 }
443 
444 //***************************************************************************
445 // object
446 //***************************************************************************
447 
448 //
449 // To integrate a sample source into the simple object system in hpcrun,
450 // #define ss_name to whatever you want your sample source to be named.
451 // (retain the ss_cls definition, unless you have a VERY unusual sample source).
452 //
453 // Finally, retain the #include statement
454 //
455 // For the moment, the #include statement MUST appear after all of the
456 // method definitions. DO NOT MOVE IT.
457 //
458 
459 #define ss_name generic
460 #define ss_cls SS_HARDWARE
461 
462 #include "ss_obj.h"
463 
464 //******************************************************************************
465 // private operations
466 // *****************************************************************************
467 
468 //
469 // Whenever an event triggers, the event handler is invoked
470 // Typically, the event trigger is a unix signal, so a unix signal handler must be installed
471 //
472 // ***** ALL sample source event handlers MUST pass a proper (unix) context ****
473 //
474 // NOTE: PAPI does NOT use a standard unix signal handler.
475 //
476 // The example handler below is a standard unix signal handler.
477 // See papi for an event handler that is NOT a standard unix signal handler
478 //
479 static int
480 generic_signal_handler(int sig, siginfo_t* siginfo, void* context)
481 {
483 
484  // If the interrupt came from inside our code, then drop the sample
485  // and return and avoid any MSG.
486  void* pc = hpcrun_context_pc(context);
487  if (! hpcrun_safe_enter_async(pc)) {
489  }
490  else {
491  //
492  // Determine which events caused this sample
493  //
494  for (EACH _EVENT e IN THIS SAMPLE) {
495  for (EACH METRIC m FOR THIS EVENT) {
496  //
497  // get the relevant data for metric m for event e
498  //
499  cct_metric_data_t datum = MY_SOURCE_FETCH_DATA(e, m);
500  //
501  // Determine the metric id for (e, m)
502  // [ The metric_id for (e, m) should be determinable by the file local data]
503  //
504  int metric_id = MY_METRIC_ID(e, m);
505  //
506  // call hpcrun_sample_callpath with context, metric_id, & datum.
507  // The last 2 arguments to hpcrun_sample_callpath are always 0
508  //
509  hpcrun_sample_callpath(context, metric_id, datum, 0/*skipInner*/, 0/*isSync*/, NULL);
510  }
511  }
512  }
513  // If sampling is disabled, return immediately
514  //
517 
518  return 0; // tell monitor that the signal has been handled
519  }
520 
521  //
522  // If the sample source must be restarted, then
523  // put that code here.
524  //
525  // NOTE: if restart can be accomplished using the exact same code as the start method,
526  // then a method call will work. (See example below)
527  // Otherwise, put the special purpose restart code here
528  //
529  METHOD_CALL(&_generic_obj, start);
530 
531  //
532  // If the sigprocmask must be manipulated to ensure continuing samples, then
533  // be sure to use monitor_real_sigprocmask.
534  //
535  // You do NOT normally have to do this. This manipulation is only called for
536  // if the regular signal handling mechanism is buggy.
537  //
538  // An example of the monitor_real_sigprocmask is shown below, but you will
539  // normally be able omit the example code.
540  //
541  monitor_real_sigprocmask(SIG_UNBLOCK, &sigset_generic, NULL);
542 
544 
545  return 0; // tell monitor that the signal has been handled
546 }
547 
548 //
549 // sample custom metric update procedure
550 //
551 
552 //
553 // replaces the metric data with the average of the datum and the previous entry
554 //
555 void
557 {
558  loc->i = (loc->i + datum) / 2;
559 }
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
#define HPCTOOLKIT_APPLICATION_ERRNO_RESTORE()
Definition: ss-errno.h:64
static const int MAX_EVENTS
Definition: generic.c:130
static bool hpcrun_is_sampling_disabled(void)
Definition: sample_event.h:73
static int generic_signal_handler(int sig, siginfo_t *siginfo, void *context)
Definition: generic.c:480
bool(* hpcrun_td_avail)(void)
Definition: thread_data.c:169
long thresh
Definition: generic.c:126
void hpcrun_stats_num_samples_blocked_async_inc(void)
Definition: hpcrun_stats.c:148
int code
Definition: generic.c:125
static struct SOME_STRUCT ss_specific_data
Definition: generic.c:106
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
void generic_special_metric_update_proc(int metric_id, cct_metric_data_t *loc, cct_metric_data_t datum)
Definition: generic.c:556
#define EMSG
Definition: messages.h:70
static void METHOD_FN(init)
Definition: generic.c:168
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 TMSG(f,...)
Definition: messages.h:93
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)
static struct event_info local_event[MAX_EVENTS]
Definition: generic.c:131
#define METHOD_CALL(obj, meth,...)
Definition: simple_oo.h:87
static const long DEFAULT_THRESHOLD
Definition: generic.c:132
#define NULL
Definition: ElfHelper.cpp:85
int metrics[MAX_EVENTS][MAX_METRICS]
Definition: generic.c:147
metric_desc_t * hpcrun_set_metric_info_w_fn(int metric_id, const char *name, MetricFlags_ValFmt_t valFmt, size_t period, metric_upd_proc_t upd_fn, metric_desc_properties_t prop)
Definition: metrics.c:339
static int n_events
Definition: generic.c:129
int hpcrun_new_metric(void)
Definition: metrics.c:333
#define HPCTOOLKIT_APPLICATION_ERRNO_SAVE()
Definition: ss-errno.h:63
void * hpcrun_context_pc(void *context)
int more_tok(void)
Definition: tokenize.c:78
#define metric_property_none
Definition: hpcrun-fmt.h:202