]> Git Repo - binutils.git/blob - gprofng/libcollector/hwprofile.c
Automatic date update in version.in
[binutils.git] / gprofng / libcollector / hwprofile.c
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3
4    This file is part of GNU Binutils.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 /* Hardware counter profiling */
22
23 #include "config.h"
24 #include <alloca.h>
25 #include <dlfcn.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <sys/syscall.h>
31 #include <signal.h>
32
33 #include "gp-defs.h"
34 #define _STRING_H 1  /* XXX MEZ: temporary workaround */
35 #include "hwcdrv.h"
36 #include "collector_module.h"
37 #include "gp-experiment.h"
38 #include "libcol_util.h"
39 #include "hwprofile.h"
40 #include "ABS.h"
41 #include "tsd.h"
42
43 /* TprintfT(<level>,...) definitions.  Adjust per module as needed */
44 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
45 #define DBG_LT1 1 // for configuration details, warnings
46 #define DBG_LT2 2
47 #define DBG_LT3 3
48 #define DBG_LT4 4
49 #define DBG_LT5 5
50
51 #define  SD_OFF 0       /* before start or after close she shut down process */
52 #define  SD_PENDING 1   /* before running real_detach_experiment() */
53 #define  SD_COMPLETE 2  /* after running real_detach_experiment() */
54
55 static int init_interface (CollectorInterface*);
56 static int open_experiment (const char *);
57 static int start_data_collection (void);
58 static int stop_data_collection (void);
59 static int close_experiment (void);
60 static int detach_experiment (void);
61 static int real_detach_experiment (void);
62
63 static ModuleInterface module_interface ={
64   SP_HWCNTR_FILE,           /* description */
65   init_interface,           /* initInterface */
66   open_experiment,          /* openExperiment */
67   start_data_collection,    /* startDataCollection */
68   stop_data_collection,     /* stopDataCollection */
69   close_experiment,         /* closeExperiment */
70   detach_experiment         /* detachExperiment (fork child) */
71 };
72
73 static CollectorInterface *collector_interface = NULL;
74
75
76 /*---------------------------------------------------------------------------*/
77 /* compile options and workarounds */
78
79 /* Solaris: We set ITIMER_REALPROF to ensure that counters get started on
80  *      LWPs that existed before the collector initialization.
81  *
82  * In addition, if the appropriate #define's are set, we check for:
83  *      lost-hw-overflow -- the HW counters rollover, but the overflow
84  *            interrupt is not generated (counters keep running)
85  *      lost-sigemt -- the interrupt is received by the kernel,
86  *            which stops the counters, but the kernel fails
87  *            to deliver the signal.
88  */
89
90 /*---------------------------------------------------------------------------*/
91 /* typedefs */
92
93 typedef enum {
94   HWCMODE_OFF,       /* before start or after close */
95   HWCMODE_SUSPEND,  /* stop_data_collection called */
96   HWCMODE_ACTIVE,   /* counters are defined and after start_data_collection() */
97   HWCMODE_ABORT     /* fatal error occured. Log a message, stop recording */
98 } hwc_mode_t;
99
100 /*---------------------------------------------------------------------------*/
101 /* prototypes */
102 static void init_ucontexts (void);
103 static int hwc_initialize_handlers (void);
104 static void collector_record_counter (ucontext_t*,
105                                       int timecvt,
106                                       ABST_type, hrtime_t,
107                                       unsigned, uint64_t);
108 static void collector_hwc_ABORT (int errnum, const char *msg);
109 static void hwclogwrite0 ();
110 static void hwclogwrite (Hwcentry *);
111 static void set_hwc_mode (hwc_mode_t);
112 static void collector_sigemt_handler (int sig, siginfo_t *si, void *puc);
113
114 /*---------------------------------------------------------------------------*/
115 /* static variables */
116
117 /* --- user counter selections and options */
118 static int hwcdef_has_memspace;     /* true to indicate use of extened packets */
119 static unsigned hwcdef_cnt;         /* number of *active* hardware counters */
120 static unsigned hwcdef_num_sampling_ctrdefs; /* ctrs that use sampling */
121 static unsigned hwcdef_num_overflow_ctrdefs; /* ctrs that use overflow */
122 static Hwcentry **hwcdef;           /* HWC definitions */
123 static int cpcN_cpuver = CPUVER_UNDEFINED;
124 static int hwcdrv_inited;           /* Don't call hwcdrv_init() in fork_child */
125 static hwcdrv_api_t *hwc_driver = NULL;
126 static unsigned hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
127 static int hwprofile_tsd_sz = 0;
128 static volatile hwc_mode_t hwc_mode = HWCMODE_OFF;
129 static volatile unsigned int nthreads_in_sighandler = 0;
130 static volatile unsigned int sd_state = SD_OFF;
131
132 /* --- experiment logging state */
133 static CollectorModule expr_hndl = COLLECTOR_MODULE_ERR;
134 static ucontext_t expr_dummy_uc;        // used for hacked "collector" frames
135 static ucontext_t expr_out_of_range_uc; // used for "out-of-range" frames
136 static ucontext_t expr_frozen_uc;       // used for "frozen" frames
137 static ucontext_t expr_nopc_uc;         // used for not-program-related frames
138 static ucontext_t expr_lostcounts_uc;   // used for lost_counts frames
139
140 /* --- signal handler state */
141 static struct sigaction old_sigemt_handler;  //overwritten in fork-child
142
143 /*---------------------------------------------------------------------------*/
144 /* macros */
145 #define COUNTERS_ENABLED()  (hwcdef_cnt)
146 #define gethrtime           collector_interface->getHiResTime
147
148 #ifdef DEBUG
149 #define Tprintf(...)   if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
150 #define TprintfT(...)  if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
151 #else
152 #define Tprintf(...)
153 #define TprintfT(...)
154 #endif
155
156
157 /*---------------------------------------------------------------------------*/
158
159 /* Initialization routines */
160 static hwcdrv_api_t *
161 get_hwc_driver ()
162 {
163   if (hwc_driver == NULL)
164     hwc_driver = __collector_get_hwcdrv ();
165   return hwc_driver;
166 }
167
168 static void init_module () __attribute__ ((constructor));
169 static void
170 init_module ()
171 {
172   __collector_dlsym_guard = 1;
173   RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
174   __collector_dlsym_guard = 0;
175   if (reg_module == NULL)
176     {
177       TprintfT (0, "hwprofile: init_module FAILED - reg_module = NULL\n");
178       return;
179     }
180   expr_hndl = reg_module (&module_interface);
181   if (expr_hndl == COLLECTOR_MODULE_ERR)
182     {
183       TprintfT (0, "hwprofile: ERROR: handle not created.\n");
184       if (collector_interface)
185         collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
186                                        SP_JCMD_CERROR, COL_ERROR_HWCINIT);
187     }
188 }
189
190 static int
191 init_interface (CollectorInterface *_collector_interface)
192 {
193   collector_interface = _collector_interface;
194   return COL_ERROR_NONE;
195 }
196
197 static void *
198 hwprofile_get_tsd ()
199 {
200   return collector_interface->getKey (hwprofile_tsd_key);
201 }
202
203 static int
204 open_experiment (const char *exp)
205 {
206   if (collector_interface == NULL)
207     {
208       TprintfT (0, "hwprofile: ERROR: collector_interface is null.\n");
209       return COL_ERROR_HWCINIT;
210     }
211   const char *params = collector_interface->getParams ();
212   while (params)
213     {
214       if (__collector_strStartWith (params, "h:*") == 0)
215         {
216           /* HWC counters set by default */
217           collector_interface->writeLog ("<%s %s=\"1\"/>\n",
218                                          SP_TAG_SETTING, SP_JCMD_HWC_DEFAULT);
219           params += 3;
220           break;
221         }
222       else if (__collector_strStartWith (params, "h:") == 0)
223         {
224           params += 2;
225           break;
226         }
227       params = CALL_UTIL (strchr)(params, ';');
228       if (params)
229         params++;
230     }
231   if (params == NULL)  /* HWC profiling not specified */
232     return COL_ERROR_HWCINIT;
233   char *s = CALL_UTIL (strchr)(params, (int) ';');
234   int sz = s ? s - params : CALL_UTIL (strlen)(params);
235   char *defstring = (char*) alloca (sz + 1);
236   CALL_UTIL (strlcpy)(defstring, params, sz + 1);
237   TprintfT (0, "hwprofile: open_experiment %s -- %s\n", exp, defstring);
238
239   int err = COL_ERROR_NONE;
240   /* init counter library */
241   if (!hwcdrv_inited)
242     { /* do not call hwcdrv_init() from fork-child */
243       hwcdrv_inited = 1;
244       get_hwc_driver ();
245       if (hwc_driver->hwcdrv_init (collector_hwc_ABORT, &hwprofile_tsd_sz) == 0)
246         {
247           collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
248                                          SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
249           TprintfT (0, "hwprofile: ERROR: hwcfuncs_init() failed\n");
250           return COL_ERROR_HWCINIT;
251         }
252
253       if (hwc_driver->hwcdrv_enable_mt (hwprofile_get_tsd))
254         {
255           // It is OK to call hwcdrv_enable_mt() before tsd key is created
256           collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
257                                          SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
258           TprintfT (0, "hwprofile: ERROR: hwcdrv_enable_mt() failed\n");
259           return COL_ERROR_HWCINIT;
260         }
261
262       hwc_driver->hwcdrv_get_info (&cpcN_cpuver, NULL, NULL, NULL, NULL);
263       if (cpcN_cpuver < 0)
264         {
265           collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
266                                          SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
267           TprintfT (0, "hwprofile: ERROR: hwcdrv_get_info() failed\n");
268           return COL_ERROR_HWCINIT;
269         }
270     }
271
272   if (hwprofile_tsd_sz)
273     {
274       hwprofile_tsd_key = collector_interface->createKey (hwprofile_tsd_sz, NULL, NULL);
275       if (hwprofile_tsd_key == COLLECTOR_TSD_INVALID_KEY)
276         {
277           collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
278                                          SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
279           TprintfT (0, "hwprofile: ERROR: TSD createKey failed\n");
280           return COL_ERROR_HWCINIT;
281         }
282     }
283   hwcdef_cnt = 0;
284   hwcdef_has_memspace = 0;
285
286   /* create counters based on hwcdef[] */
287   err = __collector_hwcfuncs_bind_descriptor (defstring);
288   if (err)
289     {
290       err = err == HWCFUNCS_ERROR_HWCINIT ? COL_ERROR_HWCINIT : COL_ERROR_HWCARGS;
291       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
292                                      SP_JCMD_CERROR, err, defstring);
293       TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
294       return err;
295     }
296
297   /* generate an array of counter structures for each requested counter */
298   hwcdef = __collector_hwcfuncs_get_ctrs (&hwcdef_cnt);
299   hwcdef_num_sampling_ctrdefs = hwcdef_num_overflow_ctrdefs = 0;
300   int idx;
301   for (idx = 0; idx < hwcdef_cnt; idx++)
302     {
303       if (HWCENTRY_USES_SAMPLING (hwcdef[idx]))
304         {
305           hwcdef_num_sampling_ctrdefs++;
306         }
307       else
308         {
309           hwcdef_num_overflow_ctrdefs++;
310         }
311     }
312
313   init_ucontexts ();
314
315   /* initialize the SIGEMT handler, and the periodic HWC checker */
316   err = hwc_initialize_handlers ();
317   if (err != COL_ERROR_NONE)
318     {
319       hwcdef_cnt = 0;
320       TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
321       /* log written by hwc_initialize_handlers() */
322       return err;
323     }
324
325   for (idx = 0; idx < hwcdef_cnt; idx++)
326     if (ABST_BACKTRACK_ENABLED (hwcdef[idx]->memop))
327       hwcdef_has_memspace = 1;
328
329   /* record the hwc definitions in the log, based on the counter array */
330   hwclogwrite0 ();
331   for (idx = 0; idx < hwcdef_cnt; idx++)
332     hwclogwrite (hwcdef[idx]);
333   return COL_ERROR_NONE;
334 }
335
336 int
337 __collector_ext_hwc_lwp_init ()
338 {
339   return get_hwc_driver ()->hwcdrv_lwp_init ();
340 }
341
342 void
343 __collector_ext_hwc_lwp_fini ()
344 {
345   get_hwc_driver ()->hwcdrv_lwp_fini ();
346 }
347
348 int
349 __collector_ext_hwc_lwp_suspend ()
350 {
351   return get_hwc_driver ()->hwcdrv_lwp_suspend ();
352 }
353
354 int
355 __collector_ext_hwc_lwp_resume ()
356 {
357   return get_hwc_driver ()->hwcdrv_lwp_resume ();
358 }
359
360 /* Dummy routine, used to provide a context for non-program related profiles */
361 void
362 __collector_not_program_related () { }
363
364 /* Dummy routine, used to provide a context for lost counts (perf_events) */
365 void
366 __collector_hwc_samples_lost () { }
367
368 /* Dummy routine, used to provide a context */
369 void
370 __collector_hwcs_frozen () { }
371
372 /* Dummy routine, used to provide a context */
373 void
374 __collector_hwcs_out_of_range () { }
375 /* initialize some structures */
376 static void
377 init_ucontexts (void)
378 {
379   /* initialize dummy context for "collector" frames */
380   CALL_UTIL (getcontext) (&expr_dummy_uc);
381   SETFUNCTIONCONTEXT (&expr_dummy_uc, NULL);
382
383   /* initialize dummy context for "out-of-range" frames */
384   CALL_UTIL (getcontext) (&expr_out_of_range_uc);
385   SETFUNCTIONCONTEXT (&expr_out_of_range_uc, &__collector_hwcs_out_of_range);
386
387   /* initialize dummy context for "frozen" frames */
388   CALL_UTIL (getcontext) (&expr_frozen_uc);
389   SETFUNCTIONCONTEXT (&expr_frozen_uc, &__collector_hwcs_frozen);
390
391   /* initialize dummy context for non-program-related frames */
392   CALL_UTIL (getcontext) (&expr_nopc_uc);
393   SETFUNCTIONCONTEXT (&expr_nopc_uc, &__collector_not_program_related);
394
395   /* initialize dummy context for lost-counts-related frames */
396   CALL_UTIL (getcontext) (&expr_lostcounts_uc);
397   SETFUNCTIONCONTEXT (&expr_lostcounts_uc, &__collector_hwc_samples_lost);
398 }
399 /* initialize the signal handler */
400 static int
401 hwc_initialize_handlers (void)
402 {
403   /* install the signal handler for SIGEMT */
404   struct sigaction oact;
405   if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact) != 0)
406     {
407       TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to get oact\n");
408       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT);
409       return COL_ERROR_HWCINIT;
410     }
411   if (oact.sa_sigaction == collector_sigemt_handler)
412     {
413       /* signal handler is already in place; we are probably in a fork-child */
414       TprintfT (DBG_LT1, "hwc_initialize_handlers(): hwc_initialize_handlers() collector_sigemt_handler already installed\n");
415     }
416   else
417     {
418       /* set our signal handler */
419       struct sigaction c_act;
420       CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
421       sigemptyset (&c_act.sa_mask);
422       sigaddset (&c_act.sa_mask, SIGPROF); /* block SIGPROF delivery in handler */
423       /* XXXX should probably also block sample_sig & pause_sig */
424       c_act.sa_sigaction = collector_sigemt_handler;  /* note: used to set sa_handler instead */
425       c_act.sa_flags = SA_RESTART | SA_SIGINFO;
426       if (__collector_sigaction (HWCFUNCS_SIGNAL, &c_act, &old_sigemt_handler) != 0)
427         {
428           TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to set cact\n");
429           collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">event handler could not be installed</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT);
430           return COL_ERROR_HWCINIT;
431         }
432     }
433   return COL_ERROR_NONE;
434 }
435
436 static int
437 close_experiment (void)
438 {
439   /* note: stop_data_collection() should have already been called by
440    * collector_close_experiment()
441    */
442   if (!COUNTERS_ENABLED ())
443     return COL_ERROR_NONE;
444   detach_experiment ();
445
446   /* cpc or libperfctr may still generate sigemts for a while */
447   /* verify that SIGEMT handler is still installed */
448   /* (still required with sigaction interposition and management,
449      since interposition is not done for attach experiments)
450    */
451   struct sigaction curr;
452   if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &curr) == -1)
453     {
454       TprintfT (0, "hwprofile close_experiment: ERROR: hwc sigaction check failed: errno=%d\n", errno);
455     }
456   else if (curr.sa_sigaction != collector_sigemt_handler)
457     {
458       TprintfT (DBG_LT1, "hwprofile close_experiment: WARNING: collector sigemt handler replaced by 0x%p!\n", curr.sa_handler);
459       (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">0x%p</event>\n",
460                                             SP_JCMD_CWARN, COL_WARN_SIGEMT, curr.sa_handler);
461     }
462   else
463     TprintfT (DBG_LT1, "hwprofile close_experiment: collector sigemt handler integrity verified!\n");
464   TprintfT (0, "hwprofile: close_experiment\n");
465   return 0;
466 }
467
468 static int
469 detach_experiment (void)
470 {
471   /* fork child.  Clean up state but don't write to experiment */
472   /* note: stop_data_collection() has already been called by the fork_prologue */
473   // detach_experiment() can be called asynchronously
474   // from anywhere, even from within a sigemt handler
475   // via DBX detach.
476   // Important: stop_data_collection() _must_ be called
477   // before detach_experiment() is called.
478   if (!COUNTERS_ENABLED ())
479     return COL_ERROR_NONE;
480   TprintfT (0, "hwprofile: detach_experiment()\n");
481   if (SD_OFF != __collector_cas_32 (&sd_state, SD_OFF, SD_PENDING))
482     return 0;
483   // one and only one call should ever make it here here.
484   if (hwc_mode == HWCMODE_ACTIVE)
485     {
486       TprintfT (0, "hwprofile: ERROR: stop_data_collection() should have been called before detach_experiment()\n");
487       stop_data_collection ();
488     }
489
490   // Assumption: The only calls to sigemt_handler
491   // we should see at this point
492   // will be those that were already in-flight before
493   // stop_new_sigemts() was called.
494   if (nthreads_in_sighandler > 0)
495     {
496       // sigemt handlers should see
497       // SD_PENDING and should call real_detach_experiment()
498       // when the last handler is finished.
499       TprintfT (DBG_LT1, "hwprofile: detach in the middle of signal handler.\n");
500       return 0;
501     }
502
503   // If we get here, there should be no remaining
504   // sigemt handlers.  However,  we don't really know
505   // if there were ever any in flight, so call
506   // real_detach_experiment() here:
507   return real_detach_experiment (); // multiple calls to this OK
508 }
509
510 static int
511 real_detach_experiment (void)
512 {
513   /*multiple calls to this routine are OK.*/
514   if (SD_PENDING != __collector_cas_32 (&sd_state, SD_PENDING, SD_COMPLETE))
515     return 0;
516   // only the first caller to this routine should get here.
517   hwcdef_cnt = 0; /* since now deinstalled */
518   hwcdef = NULL;
519   set_hwc_mode (HWCMODE_OFF);
520   if (SD_COMPLETE != __collector_cas_32 (&sd_state, SD_COMPLETE, SD_OFF))
521     {
522       TprintfT (0, "hwprofile: ERROR: unexpected sd_state in real_detach_experiment()\n");
523       sd_state = SD_OFF;
524     }
525   hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
526   TprintfT (DBG_LT0, "hwprofile: real_detach_experiment() detached from experiment.\n");
527   return 0;
528 }
529
530 /*---------------------------------------------------------------------------*/
531 /* Record counter values. */
532
533 /* <value> should already be adjusted to be "zero-based" (counting up from 0).*/
534 static void
535 collector_record_counter_internal (ucontext_t *ucp, int timecvt,
536                                    ABST_type ABS_memop, hrtime_t time,
537                                    unsigned tag, uint64_t value, uint64_t pc,
538                                    uint64_t va, uint64_t latency,
539                                    uint64_t data_source)
540 {
541   MHwcntr_packet pckt;
542   CALL_UTIL (memset)(&pckt, 0, sizeof ( MHwcntr_packet));
543   pckt.comm.tstamp = time;
544   pckt.tag = tag;
545   if (timecvt > 1)
546     {
547       if (HWCVAL_HAS_ERR (value))
548         {
549           value = HWCVAL_CLR_ERR (value);
550           value *= timecvt;
551           value = HWCVAL_SET_ERR (value);
552         }
553       else
554         value *= timecvt;
555     }
556   pckt.interval = value;
557   pckt.comm.type = HW_PCKT;
558   pckt.comm.tsize = sizeof (Hwcntr_packet);
559   TprintfT (DBG_LT4, "hwprofile: %llu sample %lld tag %u recorded\n",
560             (unsigned long long) time, (long long) value, tag);
561   if (ABS_memop == ABST_NOPC)
562     ucp = &expr_nopc_uc;
563   pckt.comm.frinfo = collector_interface->getFrameInfo (expr_hndl, pckt.comm.tstamp, FRINFO_FROM_UC, ucp);
564   collector_interface->writeDataRecord (expr_hndl, (Common_packet*) & pckt);
565 }
566
567 static void
568 collector_record_counter (ucontext_t *ucp, int timecvt, ABST_type ABS_memop,
569                           hrtime_t time, unsigned tag, uint64_t value)
570 {
571   collector_record_counter_internal (ucp, timecvt, ABS_memop, time, tag, value,
572                                      HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64,
573                                      HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64);
574 }
575
576
577 /*---------------------------------------------------------------------------*/
578 /* Signal handlers */
579
580 /* SIGEMT -- relayed from libcpc, when the counter overflows */
581
582 /*   Generates the appropriate event or events, and resets the counters */
583 static void
584 collector_sigemt_handler (int sig, siginfo_t *si, void *puc)
585 {
586   int rc;
587   hwc_event_t sample, lost_samples;
588   if (sig != HWCFUNCS_SIGNAL)
589     {
590       TprintfT (0, "hwprofile: ERROR: %s: unexpected signal %d\n", "collector_sigemt_handler", sig);
591       return;
592     }
593   if (!COUNTERS_ENABLED ())
594     { /* apparently deinstalled */
595       TprintfT (0, "hwprofile: WARNING: SIGEMT detected after close_experiment()\n");
596       /* kills future sigemts since hwcdrv_sighlr_restart() not called */
597       return;
598     }
599
600   /* Typically, we expect HWC overflow signals to come from the kernel: si_code > 0.
601    * On Linux, however, dbx might be "forwarding" a signal using tkill()/tgkill().
602    * For more information on what si_code values can be expected on Linux, check:
603    *     cmn_components/Collector_Interface/hwcdrv_pcl.c     hwcdrv_overflow()
604    *     cmn_components/Collector_Interface/hwcdrv_perfctr.c hdrv_perfctr_overflow()
605    */
606   if (puc == NULL || si == NULL || (si->si_code <= 0 && si->si_code != SI_TKILL))
607     {
608       TprintfT (DBG_LT3, "hwprofile: collector_sigemt_handler SIG%02d\n", sig);
609       if (old_sigemt_handler.sa_handler == SIG_DFL)
610         __collector_SIGDFL_handler (HWCFUNCS_SIGNAL);
611       else if (old_sigemt_handler.sa_handler != SIG_IGN &&
612          old_sigemt_handler.sa_sigaction != &collector_sigemt_handler)
613         {
614           /* Redirect the signal to the previous signal handler */
615           (old_sigemt_handler.sa_sigaction)(sig, si, puc);
616           TprintfT (DBG_LT1, "hwprofile: collector_sigemt_handler SIG%02d redirected to original handler\n", sig);
617         }
618       return;
619     }
620   rc = get_hwc_driver ()->hwcdrv_overflow (si, &sample, &lost_samples);
621   if (rc)
622     {
623       /* hwcdrv_sighlr_restart() should not be called */
624       TprintfT (0, "hwprofile: ERROR: collector_sigemt_handler: hwcdrv_overflow() failed\n");
625       return;
626     }
627
628   if (hwc_mode == HWCMODE_ACTIVE)
629     {
630       /* record the event only if counters are active */
631       /* The following has been copied from dispatcher.c */
632 #if ARCH(SPARC)
633       /* 23340823 signal handler third argument should point to a ucontext_t */
634       /* Convert sigcontext to ucontext_t on sparc-Linux */
635       ucontext_t uctxmem;
636       struct sigcontext *sctx = (struct sigcontext*) puc;
637       ucontext_t *uctx = &uctxmem;
638       uctx->uc_link = NULL;
639 #if WSIZE(32)
640       uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
641       __collector_memcpy (&uctx->uc_mcontext.gregs[3],
642                           sctx->si_regs.u_regs,
643                           sizeof (sctx->si_regs.u_regs));
644 #else
645       uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
646       __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
647                           sctx->sigc_regs.u_regs,
648                           sizeof (sctx->sigc_regs.u_regs));
649 #endif /* WSIZE() */
650 #else
651       ucontext_t *uctx = (ucontext_t*) puc;
652 #endif /* ARCH() */
653
654       for (int ii = 0; ii < hwcdef_cnt; ii++)
655         if (lost_samples.ce_pic[ii])
656           collector_record_counter (&expr_lostcounts_uc, hwcdef[ii]->timecvt,
657                                     hwcdef[ii]->memop, lost_samples.ce_hrt,
658                                     hwcdef[ii]->sort_order, lost_samples.ce_pic[ii]);
659       for (int ii = 0; ii < hwcdef_cnt; ii++)
660         if (sample.ce_pic[ii])
661           collector_record_counter (uctx, hwcdef[ii]->timecvt,
662                                     hwcdef[ii]->memop, sample.ce_hrt,
663                                     hwcdef[ii]->sort_order, sample.ce_pic[ii]);
664     }
665   rc = get_hwc_driver ()->hwcdrv_sighlr_restart (NULL);
666 }
667 /*      SIGPROF -- not installed as handler, but
668  *      __collector_ext_hwc_check: called by (SIGPROF) dispatcher.
669  *       Periodical check of integrity of HWC count/signal mechanism,
670  *       as required for various chip/system bugs/workarounds.
671  */
672 void
673 __collector_ext_hwc_check (siginfo_t *info, ucontext_t *vcontext) { }
674
675 /*---------------------------------------------------------------------------*/
676 int
677 collector_sigemt_sigaction (const struct sigaction *nact,
678                             struct sigaction *oact)
679 {
680   struct sigaction oact_check;
681   /* Error codes and messages that refer to HWC are tricky.
682    * E.g., HWC profiling might not even be on;  we might
683    * encounter an error here simply because the user is
684    * trying to set a handler for a signal that happens to
685    * be HWCFUNCS_SIGNAL, which we aren't even using.
686    */
687   if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact_check) != 0)
688     {
689       TprintfT (0, "hwprofile: ERROR: collector_sigemt_sigaction(): request to set handler for signal %d, but check on existing handler failed\n", HWCFUNCS_SIGNAL);
690       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler for signal %d could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT, HWCFUNCS_SIGNAL);
691       return COL_ERROR_HWCINIT;
692     }
693
694   if (oact_check.sa_sigaction == collector_sigemt_handler)
695     {
696       /* dispatcher is in place, so nact/oact apply to old_sigemt_handler */
697       if (oact != NULL)
698         {
699           oact->sa_handler = old_sigemt_handler.sa_handler;
700           oact->sa_mask = old_sigemt_handler.sa_mask;
701           oact->sa_flags = old_sigemt_handler.sa_flags;
702         }
703       if (nact != NULL)
704         {
705           old_sigemt_handler.sa_handler = nact->sa_handler;
706           old_sigemt_handler.sa_mask = nact->sa_mask;
707           old_sigemt_handler.sa_flags = nact->sa_flags;
708         }
709       return COL_ERROR_NONE;
710     }
711   else /* no dispatcher in place, so just act like normal sigaction() */
712     return __collector_sigaction (HWCFUNCS_SIGNAL, nact, oact);
713 }
714
715 static void
716 collector_hwc_ABORT (int errnum, const char *msg)
717 {
718   TprintfT (0, "hwprofile: collector_hwc_ABORT: [%d] %s\n", errnum, msg);
719   if (hwc_mode == HWCMODE_ABORT) /* HWC collection already aborted! */
720     return;
721   set_hwc_mode (HWCMODE_ABORT); /* set global flag to disable handlers and indicate abort */
722
723   /* Write the error message to the experiment */
724   collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
725                                  SP_JCMD_CERROR, COL_ERROR_HWCFAIL, msg, errnum);
726
727 #ifdef REAL_DEBUG
728   abort ();
729 #else
730   TprintfT (0, "hwprofile: Continuing without HWC collection...\n");
731 #endif
732 }
733
734 static int
735 start_data_collection (void)
736 {
737   hwc_mode_t old_mode = hwc_mode;
738   if (!COUNTERS_ENABLED ())
739     return COL_ERROR_NONE;
740   TprintfT (0, "hwprofile: start_data_collection (hwc_mode=%d)\n", old_mode);
741   switch (old_mode)
742     {
743     case HWCMODE_OFF:
744       if (get_hwc_driver ()->hwcdrv_start ())
745         {
746           TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_start()\n");
747           collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
748                                          SP_JCMD_CERROR, COL_ERROR_HWCFAIL,
749                                          "start_data_collection()", errno);
750           return COL_ERROR_HWCINIT;
751         }
752       set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
753       break;
754     case HWCMODE_SUSPEND:
755       if (get_hwc_driver ()->hwcdrv_lwp_resume ())
756         {
757           TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_lwp_resume()\n");
758           /* ignore errors from lwp_resume() */
759         }
760       set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
761       break;
762     default:
763       TprintfT (0, "hwprofile: ERROR: start_data_collection() invalid mode\n");
764       return COL_ERROR_HWCINIT;
765     }
766   return COL_ERROR_NONE;
767 }
768
769 static int
770 stop_data_collection (void)
771 {
772   hwc_mode_t old_mode = hwc_mode;
773   if (!COUNTERS_ENABLED ())
774     return COL_ERROR_NONE;
775   TprintfT (0, "hwprofile: stop_data_collection (hwc_mode=%d)\n", old_mode);
776   switch (old_mode)
777     {
778     case HWCMODE_SUSPEND:
779       return COL_ERROR_NONE;
780     case HWCMODE_ACTIVE:
781       set_hwc_mode (HWCMODE_SUSPEND); /* stop handling signals */
782       break;
783     default:
784       /* Don't change the mode, but attempt to suspend anyway... */
785       break;
786     }
787
788   if (get_hwc_driver ()->hwcdrv_lwp_suspend ())
789     /* ignore errors from lwp_suspend() */
790     TprintfT (0, "hwprofile: ERROR: stop_data_collection() failed in hwcdrv_lwp_suspend()\n");
791
792   /*
793    * hwcdrv_lwp_suspend() cannot guarantee that all SIGEMTs will stop
794    * but hwc_mode will prevent logging and counters will overflow once
795    * then stay frozen.
796    */
797   /*   There may still be pending SIGEMTs so don't reset the SIG_DFL handler.
798    */
799   /* see comment in dispatcher.c */
800   /* ret = __collector_sigaction( SIGEMT, &old_sigemt_handler, NULL ); */
801   return COL_ERROR_NONE;
802 }
803
804 /*---------------------------------------------------------------------------*/
805
806 /* utilities */
807 static void
808 set_hwc_mode (hwc_mode_t md)
809 {
810   TprintfT (DBG_LT1, "hwprofile: set_hwc_mode(%d)\n", md);
811   hwc_mode = md;
812 }
813
814 int
815 __collector_ext_hwc_active ()
816 {
817   return (hwc_mode == HWCMODE_ACTIVE);
818 }
819
820 static void
821 hwclogwrite0 ()
822 {
823   collector_interface->writeLog ("<profdata fname=\"%s\"/>\n",
824                                  module_interface.description);
825   /* Record Hwcntr_packet description */
826   Hwcntr_packet *pp = NULL;
827   collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", HW_PCKT);
828   collector_interface->writeLog ("    <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
829                                  &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
830   collector_interface->writeLog ("    <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
831                                  &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
832   collector_interface->writeLog ("    <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
833                                  &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
834   collector_interface->writeLog ("    <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
835                                  &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
836   collector_interface->writeLog ("    <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
837                                  &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
838   collector_interface->writeLog ("    <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
839                                  &pp->tag, sizeof (pp->tag) == 4 ? "INT32" : "INT64");
840   collector_interface->writeLog ("    <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
841                                  &pp->interval, sizeof (pp->interval) == 4 ? "INT32" : "INT64");
842   collector_interface->writeLog ("</profpckt>\n");
843   if (hwcdef_has_memspace)
844     {
845       /* Record MHwcntr_packet description */
846       MHwcntr_packet *xpp = NULL;
847       collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", MHWC_PCKT);
848       collector_interface->writeLog ("    <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
849                                      &xpp->comm.lwp_id, sizeof (xpp->comm.lwp_id) == 4 ? "INT32" : "INT64");
850       collector_interface->writeLog ("    <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
851                                      &xpp->comm.thr_id, sizeof (xpp->comm.thr_id) == 4 ? "INT32" : "INT64");
852       collector_interface->writeLog ("    <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
853                                      &xpp->comm.cpu_id, sizeof (xpp->comm.cpu_id) == 4 ? "INT32" : "INT64");
854       collector_interface->writeLog ("    <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
855                                      &xpp->comm.tstamp, sizeof (xpp->comm.tstamp) == 4 ? "INT32" : "INT64");
856       collector_interface->writeLog ("    <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
857                                      &xpp->comm.frinfo, sizeof (xpp->comm.frinfo) == 4 ? "INT32" : "INT64");
858       collector_interface->writeLog ("    <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
859                                      &xpp->tag, sizeof (xpp->tag) == 4 ? "INT32" : "INT64");
860       collector_interface->writeLog ("    <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
861                                      &xpp->interval, sizeof (xpp->interval) == 4 ? "INT32" : "INT64");
862       collector_interface->writeLog ("    <field name=\"VADDR\" uname=\"" STXT ("Virtual address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
863                                      &xpp->ea_vaddr, sizeof (xpp->ea_vaddr) == 4 ? "UINT32" : "UINT64");
864       collector_interface->writeLog ("    <field name=\"PADDR\" uname=\"" STXT ("Physical address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
865                                      &xpp->ea_paddr, sizeof (xpp->ea_paddr) == 4 ? "UINT32" : "UINT64");
866       collector_interface->writeLog ("    <field name=\"VIRTPC\" uname=\"" STXT ("Virtual address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
867                                      &xpp->pc_vaddr, sizeof (xpp->pc_vaddr) == 4 ? "UINT32" : "UINT64");
868       collector_interface->writeLog ("    <field name=\"PHYSPC\" uname=\"" STXT ("Physical address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
869                                      &xpp->pc_paddr, sizeof (xpp->pc_paddr) == 4 ? "UINT32" : "UINT64");
870       collector_interface->writeLog ("    <field name=\"EA_PAGESIZE\" uname=\"" STXT ("Page size (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
871                                      &xpp->ea_pagesz, sizeof (xpp->ea_pagesz) == 4 ? "INT32" : "INT64");
872       collector_interface->writeLog ("    <field name=\"PC_PAGESIZE\" uname=\"" STXT ("Page size (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
873                                      &xpp->pc_pagesz, sizeof (xpp->pc_pagesz) == 4 ? "INT32" : "INT64");
874       collector_interface->writeLog ("    <field name=\"EA_LGRP\" uname=\"" STXT ("Page locality group (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
875                                      &xpp->ea_lgrp, sizeof (xpp->ea_lgrp) == 4 ? "INT32" : "INT64");
876       collector_interface->writeLog ("    <field name=\"PC_LGRP\" uname=\"" STXT ("Page locality group (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
877                                      &xpp->pc_lgrp, sizeof (xpp->pc_lgrp) == 4 ? "INT32" : "INT64");
878       collector_interface->writeLog ("    <field name=\"LWP_LGRP_HOME\" uname=\"" STXT ("LWP home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
879                                      &xpp->lgrp_lwp, sizeof (xpp->lgrp_lwp) == 4 ? "INT32" : "INT64");
880       collector_interface->writeLog ("    <field name=\"PS_LGRP_HOME\" uname=\"" STXT ("Process home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
881                                      &xpp->lgrp_ps, sizeof (xpp->lgrp_ps) == 4 ? "INT32" : "INT64");
882       collector_interface->writeLog ("    <field name=\"MEM_LAT\" uname=\"" STXT ("Memory Latency Cycles") "\" offset=\"%d\" type=\"%s\"/>\n",
883                                      &xpp->latency, sizeof (xpp->latency) == 4 ? "INT32" : "INT64");
884       collector_interface->writeLog ("    <field name=\"MEM_SRC\" uname=\"" STXT ("Memory Data Source") "\" offset=\"%d\" type=\"%s\"/>\n",
885                                      &xpp->data_source, sizeof (xpp->data_source) == 4 ? "INT32" : "INT64");
886       collector_interface->writeLog ("</profpckt>\n");
887     }
888 }
889
890 static void
891 hwclogwrite (Hwcentry * ctr)
892 {
893   TprintfT (DBG_LT1, "hwprofile: writeLog(%s %u %s %d %u %d)\n",
894             SP_JCMD_HW_COUNTER, cpcN_cpuver, ctr->name ? ctr->name : "NULL",
895             ctr->val, ctr->sort_order, ctr->memop);
896   collector_interface->writeLog ("<profile name=\"%s\"", SP_JCMD_HW_COUNTER);
897   collector_interface->writeLog (" cpuver=\"%u\"", cpcN_cpuver);
898   collector_interface->writeLog (" hwcname=\"%s\"", ctr->name);
899   collector_interface->writeLog (" int_name=\"%s\"", ctr->int_name);
900   collector_interface->writeLog (" interval=\"%d\"", ctr->val);
901   collector_interface->writeLog (" tag=\"%u\"", ctr->sort_order);
902   collector_interface->writeLog (" memop=\"%d\"", ctr->memop);
903   collector_interface->writeLog ("/>\n");
904 }
This page took 0.077623 seconds and 4 git commands to generate.