1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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)
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.
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. */
21 /* Hardware counter profiling */
30 #include <sys/syscall.h>
35 #define _STRING_H 1 /* XXX MEZ: temporary workaround */
37 #include "collector_module.h"
38 #include "gp-experiment.h"
39 #include "libcol_util.h"
40 #include "hwprofile.h"
44 /* TprintfT(<level>,...) definitions. Adjust per module as needed */
45 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
46 #define DBG_LT1 1 // for configuration details, warnings
52 #define SD_OFF 0 /* before start or after close she shut down process */
53 #define SD_PENDING 1 /* before running real_detach_experiment() */
54 #define SD_COMPLETE 2 /* after running real_detach_experiment() */
56 static int init_interface (CollectorInterface
*);
57 static int open_experiment (const char *);
58 static int start_data_collection (void);
59 static int stop_data_collection (void);
60 static int close_experiment (void);
61 static int detach_experiment (void);
62 static int real_detach_experiment (void);
64 static ModuleInterface module_interface
={
65 SP_HWCNTR_FILE
, /* description */
66 init_interface
, /* initInterface */
67 open_experiment
, /* openExperiment */
68 start_data_collection
, /* startDataCollection */
69 stop_data_collection
, /* stopDataCollection */
70 close_experiment
, /* closeExperiment */
71 detach_experiment
/* detachExperiment (fork child) */
74 static CollectorInterface
*collector_interface
= NULL
;
77 /*---------------------------------------------------------------------------*/
78 /* compile options and workarounds */
80 /* Solaris: We set ITIMER_REALPROF to ensure that counters get started on
81 * LWPs that existed before the collector initialization.
83 * In addition, if the appropriate #define's are set, we check for:
84 * lost-hw-overflow -- the HW counters rollover, but the overflow
85 * interrupt is not generated (counters keep running)
86 * lost-sigemt -- the interrupt is received by the kernel,
87 * which stops the counters, but the kernel fails
88 * to deliver the signal.
91 /*---------------------------------------------------------------------------*/
95 HWCMODE_OFF
, /* before start or after close */
96 HWCMODE_SUSPEND
, /* stop_data_collection called */
97 HWCMODE_ACTIVE
, /* counters are defined and after start_data_collection() */
98 HWCMODE_ABORT
/* fatal error occured. Log a message, stop recording */
101 /*---------------------------------------------------------------------------*/
103 static void init_ucontexts (void);
104 static int hwc_initialize_handlers (void);
105 static void collector_record_counter (ucontext_t
*,
109 static void collector_hwc_ABORT (int errnum
, const char *msg
);
110 static void hwclogwrite0 ();
111 static void hwclogwrite (Hwcentry
*);
112 static void set_hwc_mode (hwc_mode_t
);
113 static void collector_sigemt_handler (int sig
, siginfo_t
*si
, void *puc
);
115 /*---------------------------------------------------------------------------*/
116 /* static variables */
118 /* --- user counter selections and options */
119 static int hwcdef_has_memspace
; /* true to indicate use of extened packets */
120 static unsigned hwcdef_cnt
; /* number of *active* hardware counters */
121 static unsigned hwcdef_num_sampling_ctrdefs
; /* ctrs that use sampling */
122 static unsigned hwcdef_num_overflow_ctrdefs
; /* ctrs that use overflow */
123 static Hwcentry
**hwcdef
; /* HWC definitions */
124 static int cpcN_cpuver
= CPUVER_UNDEFINED
;
125 static int hwcdrv_inited
; /* Don't call hwcdrv_init() in fork_child */
126 static hwcdrv_api_t
*hwc_driver
= NULL
;
127 static unsigned hwprofile_tsd_key
= COLLECTOR_TSD_INVALID_KEY
;
128 static int hwprofile_tsd_sz
= 0;
129 static volatile hwc_mode_t hwc_mode
= HWCMODE_OFF
;
130 static volatile unsigned int nthreads_in_sighandler
= 0;
131 static volatile unsigned int sd_state
= SD_OFF
;
133 /* --- experiment logging state */
134 static CollectorModule expr_hndl
= COLLECTOR_MODULE_ERR
;
135 static ucontext_t expr_dummy_uc
; // used for hacked "collector" frames
136 static ucontext_t expr_out_of_range_uc
; // used for "out-of-range" frames
137 static ucontext_t expr_frozen_uc
; // used for "frozen" frames
138 static ucontext_t expr_nopc_uc
; // used for not-program-related frames
139 static ucontext_t expr_lostcounts_uc
; // used for lost_counts frames
141 /* --- signal handler state */
142 static struct sigaction old_sigemt_handler
; //overwritten in fork-child
144 /*---------------------------------------------------------------------------*/
146 #define COUNTERS_ENABLED() (hwcdef_cnt)
147 #define gethrtime collector_interface->getHiResTime
150 #define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
151 #define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
154 #define TprintfT(...)
158 /*---------------------------------------------------------------------------*/
160 /* Initialization routines */
161 static hwcdrv_api_t
*
164 if (hwc_driver
== NULL
)
165 hwc_driver
= __collector_get_hwcdrv ();
169 static void init_module () __attribute__ ((constructor
));
173 __collector_dlsym_guard
= 1;
174 RegModuleFunc reg_module
= (RegModuleFunc
) dlsym (RTLD_DEFAULT
, "__collector_register_module");
175 __collector_dlsym_guard
= 0;
176 if (reg_module
== NULL
)
178 TprintfT (0, "hwprofile: init_module FAILED - reg_module = NULL\n");
181 expr_hndl
= reg_module (&module_interface
);
182 if (expr_hndl
== COLLECTOR_MODULE_ERR
)
184 TprintfT (0, "hwprofile: ERROR: handle not created.\n");
185 if (collector_interface
)
186 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
187 SP_JCMD_CERROR
, COL_ERROR_HWCINIT
);
192 init_interface (CollectorInterface
*_collector_interface
)
194 collector_interface
= _collector_interface
;
195 return COL_ERROR_NONE
;
201 return collector_interface
->getKey (hwprofile_tsd_key
);
205 open_experiment (const char *exp
)
207 if (collector_interface
== NULL
)
209 TprintfT (0, "hwprofile: ERROR: collector_interface is null.\n");
210 return COL_ERROR_HWCINIT
;
212 const char *params
= collector_interface
->getParams ();
215 if (__collector_strStartWith (params
, "h:*") == 0)
217 /* HWC counters set by default */
218 collector_interface
->writeLog ("<%s %s=\"1\"/>\n",
219 SP_TAG_SETTING
, SP_JCMD_HWC_DEFAULT
);
223 else if (__collector_strStartWith (params
, "h:") == 0)
228 params
= CALL_UTIL (strchr
)(params
, ';');
232 if (params
== NULL
) /* HWC profiling not specified */
233 return COL_ERROR_HWCINIT
;
234 char *s
= CALL_UTIL (strchr
)(params
, (int) ';');
235 int sz
= s
? s
- params
: CALL_UTIL (strlen
)(params
);
236 char *defstring
= (char*) alloca (sz
+ 1);
237 CALL_UTIL (strlcpy
)(defstring
, params
, sz
+ 1);
238 TprintfT (0, "hwprofile: open_experiment %s -- %s\n", exp
, defstring
);
240 int err
= COL_ERROR_NONE
;
241 /* init counter library */
243 { /* do not call hwcdrv_init() from fork-child */
246 if (hwc_driver
->hwcdrv_init (collector_hwc_ABORT
, &hwprofile_tsd_sz
) == 0)
248 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
249 SP_JCMD_CERROR
, COL_ERROR_HWCINIT
, defstring
);
250 TprintfT (0, "hwprofile: ERROR: hwcfuncs_init() failed\n");
251 return COL_ERROR_HWCINIT
;
254 if (hwc_driver
->hwcdrv_enable_mt (hwprofile_get_tsd
))
256 // It is OK to call hwcdrv_enable_mt() before tsd key is created
257 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
258 SP_JCMD_CERROR
, COL_ERROR_HWCINIT
, defstring
);
259 TprintfT (0, "hwprofile: ERROR: hwcdrv_enable_mt() failed\n");
260 return COL_ERROR_HWCINIT
;
263 hwc_driver
->hwcdrv_get_info (&cpcN_cpuver
, NULL
, NULL
, NULL
, NULL
);
266 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
267 SP_JCMD_CERROR
, COL_ERROR_HWCINIT
, defstring
);
268 TprintfT (0, "hwprofile: ERROR: hwcdrv_get_info() failed\n");
269 return COL_ERROR_HWCINIT
;
273 if (hwprofile_tsd_sz
)
275 hwprofile_tsd_key
= collector_interface
->createKey (hwprofile_tsd_sz
, NULL
, NULL
);
276 if (hwprofile_tsd_key
== COLLECTOR_TSD_INVALID_KEY
)
278 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
279 SP_JCMD_CERROR
, COL_ERROR_HWCINIT
, defstring
);
280 TprintfT (0, "hwprofile: ERROR: TSD createKey failed\n");
281 return COL_ERROR_HWCINIT
;
285 hwcdef_has_memspace
= 0;
287 /* create counters based on hwcdef[] */
288 err
= __collector_hwcfuncs_bind_descriptor (defstring
);
291 err
= err
== HWCFUNCS_ERROR_HWCINIT
? COL_ERROR_HWCINIT
: COL_ERROR_HWCARGS
;
292 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
293 SP_JCMD_CERROR
, err
, defstring
);
294 TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err
);
298 /* generate an array of counter structures for each requested counter */
299 hwcdef
= __collector_hwcfuncs_get_ctrs (&hwcdef_cnt
);
300 hwcdef_num_sampling_ctrdefs
= hwcdef_num_overflow_ctrdefs
= 0;
302 for (idx
= 0; idx
< hwcdef_cnt
; idx
++)
304 if (HWCENTRY_USES_SAMPLING (hwcdef
[idx
]))
306 hwcdef_num_sampling_ctrdefs
++;
310 hwcdef_num_overflow_ctrdefs
++;
316 /* initialize the SIGEMT handler, and the periodic HWC checker */
317 err
= hwc_initialize_handlers ();
318 if (err
!= COL_ERROR_NONE
)
321 TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err
);
322 /* log written by hwc_initialize_handlers() */
326 for (idx
= 0; idx
< hwcdef_cnt
; idx
++)
327 if (ABST_BACKTRACK_ENABLED (hwcdef
[idx
]->memop
))
328 hwcdef_has_memspace
= 1;
330 /* record the hwc definitions in the log, based on the counter array */
332 for (idx
= 0; idx
< hwcdef_cnt
; idx
++)
333 hwclogwrite (hwcdef
[idx
]);
334 return COL_ERROR_NONE
;
338 __collector_ext_hwc_lwp_init ()
340 return get_hwc_driver ()->hwcdrv_lwp_init ();
344 __collector_ext_hwc_lwp_fini ()
346 get_hwc_driver ()->hwcdrv_lwp_fini ();
350 __collector_ext_hwc_lwp_suspend ()
352 return get_hwc_driver ()->hwcdrv_lwp_suspend ();
356 __collector_ext_hwc_lwp_resume ()
358 return get_hwc_driver ()->hwcdrv_lwp_resume ();
361 /* Dummy routine, used to provide a context for non-program related profiles */
363 __collector_not_program_related () { }
365 /* Dummy routine, used to provide a context for lost counts (perf_events) */
367 __collector_hwc_samples_lost () { }
369 /* Dummy routine, used to provide a context */
371 __collector_hwcs_frozen () { }
373 /* Dummy routine, used to provide a context */
375 __collector_hwcs_out_of_range () { }
376 /* initialize some structures */
378 init_ucontexts (void)
380 /* initialize dummy context for "collector" frames */
381 getcontext (&expr_dummy_uc
);
382 SETFUNCTIONCONTEXT (&expr_dummy_uc
, NULL
);
384 /* initialize dummy context for "out-of-range" frames */
385 getcontext (&expr_out_of_range_uc
);
386 SETFUNCTIONCONTEXT (&expr_out_of_range_uc
, &__collector_hwcs_out_of_range
);
388 /* initialize dummy context for "frozen" frames */
389 getcontext (&expr_frozen_uc
);
390 SETFUNCTIONCONTEXT (&expr_frozen_uc
, &__collector_hwcs_frozen
);
392 /* initialize dummy context for non-program-related frames */
393 getcontext (&expr_nopc_uc
);
394 SETFUNCTIONCONTEXT (&expr_nopc_uc
, &__collector_not_program_related
);
396 /* initialize dummy context for lost-counts-related frames */
397 getcontext (&expr_lostcounts_uc
);
398 SETFUNCTIONCONTEXT (&expr_lostcounts_uc
, &__collector_hwc_samples_lost
);
400 /* initialize the signal handler */
402 hwc_initialize_handlers (void)
404 /* install the signal handler for SIGEMT */
405 struct sigaction oact
;
406 if (__collector_sigaction (HWCFUNCS_SIGNAL
, NULL
, &oact
) != 0)
408 TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to get oact\n");
409 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">old handler could not be determined</event>\n", SP_JCMD_CERROR
, COL_ERROR_HWCINIT
);
410 return COL_ERROR_HWCINIT
;
412 if (oact
.sa_sigaction
== collector_sigemt_handler
)
414 /* signal handler is already in place; we are probably in a fork-child */
415 TprintfT (DBG_LT1
, "hwc_initialize_handlers(): hwc_initialize_handlers() collector_sigemt_handler already installed\n");
419 /* set our signal handler */
420 struct sigaction c_act
;
421 CALL_UTIL (memset
)(&c_act
, 0, sizeof c_act
);
422 sigemptyset (&c_act
.sa_mask
);
423 sigaddset (&c_act
.sa_mask
, SIGPROF
); /* block SIGPROF delivery in handler */
424 /* XXXX should probably also block sample_sig & pause_sig */
425 c_act
.sa_sigaction
= collector_sigemt_handler
; /* note: used to set sa_handler instead */
426 c_act
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
427 if (__collector_sigaction (HWCFUNCS_SIGNAL
, &c_act
, &old_sigemt_handler
) != 0)
429 TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to set cact\n");
430 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">event handler could not be installed</event>\n", SP_JCMD_CERROR
, COL_ERROR_HWCINIT
);
431 return COL_ERROR_HWCINIT
;
434 return COL_ERROR_NONE
;
438 close_experiment (void)
440 /* note: stop_data_collection() should have already been called by
441 * collector_close_experiment()
443 if (!COUNTERS_ENABLED ())
444 return COL_ERROR_NONE
;
445 detach_experiment ();
447 /* cpc or libperfctr may still generate sigemts for a while */
448 /* verify that SIGEMT handler is still installed */
449 /* (still required with sigaction interposition and management,
450 since interposition is not done for attach experiments)
452 struct sigaction curr
;
453 if (__collector_sigaction (HWCFUNCS_SIGNAL
, NULL
, &curr
) == -1)
455 TprintfT (0, "hwprofile close_experiment: ERROR: hwc sigaction check failed: errno=%d\n", errno
);
457 else if (curr
.sa_sigaction
!= collector_sigemt_handler
)
459 TprintfT (DBG_LT1
, "hwprofile close_experiment: WARNING: collector sigemt handler replaced by 0x%p!\n", curr
.sa_handler
);
460 (void) collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">0x%p</event>\n",
461 SP_JCMD_CWARN
, COL_WARN_SIGEMT
, curr
.sa_handler
);
464 TprintfT (DBG_LT1
, "hwprofile close_experiment: collector sigemt handler integrity verified!\n");
465 TprintfT (0, "hwprofile: close_experiment\n");
470 detach_experiment (void)
472 /* fork child. Clean up state but don't write to experiment */
473 /* note: stop_data_collection() has already been called by the fork_prologue */
474 // detach_experiment() can be called asynchronously
475 // from anywhere, even from within a sigemt handler
477 // Important: stop_data_collection() _must_ be called
478 // before detach_experiment() is called.
479 if (!COUNTERS_ENABLED ())
480 return COL_ERROR_NONE
;
481 TprintfT (0, "hwprofile: detach_experiment()\n");
482 if (SD_OFF
!= __collector_cas_32 (&sd_state
, SD_OFF
, SD_PENDING
))
484 // one and only one call should ever make it here here.
485 if (hwc_mode
== HWCMODE_ACTIVE
)
487 TprintfT (0, "hwprofile: ERROR: stop_data_collection() should have been called before detach_experiment()\n");
488 stop_data_collection ();
491 // Assumption: The only calls to sigemt_handler
492 // we should see at this point
493 // will be those that were already in-flight before
494 // stop_new_sigemts() was called.
495 if (nthreads_in_sighandler
> 0)
497 // sigemt handlers should see
498 // SD_PENDING and should call real_detach_experiment()
499 // when the last handler is finished.
500 TprintfT (DBG_LT1
, "hwprofile: detach in the middle of signal handler.\n");
504 // If we get here, there should be no remaining
505 // sigemt handlers. However, we don't really know
506 // if there were ever any in flight, so call
507 // real_detach_experiment() here:
508 return real_detach_experiment (); // multiple calls to this OK
512 real_detach_experiment (void)
514 /*multiple calls to this routine are OK.*/
515 if (SD_PENDING
!= __collector_cas_32 (&sd_state
, SD_PENDING
, SD_COMPLETE
))
517 // only the first caller to this routine should get here.
518 hwcdef_cnt
= 0; /* since now deinstalled */
520 set_hwc_mode (HWCMODE_OFF
);
521 if (SD_COMPLETE
!= __collector_cas_32 (&sd_state
, SD_COMPLETE
, SD_OFF
))
523 TprintfT (0, "hwprofile: ERROR: unexpected sd_state in real_detach_experiment()\n");
526 hwprofile_tsd_key
= COLLECTOR_TSD_INVALID_KEY
;
527 TprintfT (DBG_LT0
, "hwprofile: real_detach_experiment() detached from experiment.\n");
531 /*---------------------------------------------------------------------------*/
532 /* Record counter values. */
534 /* <value> should already be adjusted to be "zero-based" (counting up from 0).*/
536 collector_record_counter_internal (ucontext_t
*ucp
, int timecvt
,
537 ABST_type ABS_memop
, hrtime_t time
,
538 unsigned tag
, uint64_t value
, uint64_t pc
,
539 uint64_t va
, uint64_t latency
,
540 uint64_t data_source
)
543 CALL_UTIL (memset
)(&pckt
, 0, sizeof ( MHwcntr_packet
));
544 pckt
.comm
.tstamp
= time
;
548 if (HWCVAL_HAS_ERR (value
))
550 value
= HWCVAL_CLR_ERR (value
);
552 value
= HWCVAL_SET_ERR (value
);
557 pckt
.interval
= value
;
558 pckt
.comm
.type
= HW_PCKT
;
559 pckt
.comm
.tsize
= sizeof (Hwcntr_packet
);
560 TprintfT (DBG_LT4
, "hwprofile: %llu sample %lld tag %u recorded\n",
561 (unsigned long long) time
, (long long) value
, tag
);
562 if (ABS_memop
== ABST_NOPC
)
564 pckt
.comm
.frinfo
= collector_interface
->getFrameInfo (expr_hndl
, pckt
.comm
.tstamp
, FRINFO_FROM_UC
, ucp
);
565 collector_interface
->writeDataRecord (expr_hndl
, (Common_packet
*) & pckt
);
569 collector_record_counter (ucontext_t
*ucp
, int timecvt
, ABST_type ABS_memop
,
570 hrtime_t time
, unsigned tag
, uint64_t value
)
572 collector_record_counter_internal (ucp
, timecvt
, ABS_memop
, time
, tag
, value
,
573 HWCFUNCS_INVALID_U64
, HWCFUNCS_INVALID_U64
,
574 HWCFUNCS_INVALID_U64
, HWCFUNCS_INVALID_U64
);
578 /*---------------------------------------------------------------------------*/
579 /* Signal handlers */
581 /* SIGEMT -- relayed from libcpc, when the counter overflows */
583 /* Generates the appropriate event or events, and resets the counters */
585 collector_sigemt_handler (int sig
, siginfo_t
*si
, void *puc
)
588 hwc_event_t sample
, lost_samples
;
589 if (sig
!= HWCFUNCS_SIGNAL
)
591 TprintfT (0, "hwprofile: ERROR: %s: unexpected signal %d\n", "collector_sigemt_handler", sig
);
594 if (!COUNTERS_ENABLED ())
595 { /* apparently deinstalled */
596 TprintfT (0, "hwprofile: WARNING: SIGEMT detected after close_experiment()\n");
597 /* kills future sigemts since hwcdrv_sighlr_restart() not called */
601 /* Typically, we expect HWC overflow signals to come from the kernel: si_code > 0.
602 * On Linux, however, dbx might be "forwarding" a signal using tkill()/tgkill().
603 * For more information on what si_code values can be expected on Linux, check:
604 * cmn_components/Collector_Interface/hwcdrv_pcl.c hwcdrv_overflow()
605 * cmn_components/Collector_Interface/hwcdrv_perfctr.c hdrv_perfctr_overflow()
607 if (puc
== NULL
|| si
== NULL
|| (si
->si_code
<= 0 && si
->si_code
!= SI_TKILL
))
609 TprintfT (DBG_LT3
, "hwprofile: collector_sigemt_handler SIG%02d\n", sig
);
610 if (old_sigemt_handler
.sa_handler
== SIG_DFL
)
611 __collector_SIGDFL_handler (HWCFUNCS_SIGNAL
);
612 else if (old_sigemt_handler
.sa_handler
!= SIG_IGN
&&
613 old_sigemt_handler
.sa_sigaction
!= &collector_sigemt_handler
)
615 /* Redirect the signal to the previous signal handler */
616 (old_sigemt_handler
.sa_sigaction
)(sig
, si
, puc
);
617 TprintfT (DBG_LT1
, "hwprofile: collector_sigemt_handler SIG%02d redirected to original handler\n", sig
);
621 rc
= get_hwc_driver ()->hwcdrv_overflow (si
, &sample
, &lost_samples
);
624 /* hwcdrv_sighlr_restart() should not be called */
625 TprintfT (0, "hwprofile: ERROR: collector_sigemt_handler: hwcdrv_overflow() failed\n");
629 if (hwc_mode
== HWCMODE_ACTIVE
)
631 /* record the event only if counters are active */
632 /* The following has been copied from dispatcher.c */
634 /* 23340823 signal handler third argument should point to a ucontext_t */
635 /* Convert sigcontext to ucontext_t on sparc-Linux */
637 struct sigcontext
*sctx
= (struct sigcontext
*) puc
;
638 ucontext_t
*uctx
= &uctxmem
;
639 uctx
->uc_link
= NULL
;
641 uctx
->uc_mcontext
.gregs
[REG_PC
] = sctx
->si_regs
.pc
;
642 __collector_memcpy (&uctx
->uc_mcontext
.gregs
[3],
643 sctx
->si_regs
.u_regs
,
644 sizeof (sctx
->si_regs
.u_regs
));
646 uctx
->uc_mcontext
.mc_gregs
[MC_PC
] = sctx
->sigc_regs
.tpc
;
647 __collector_memcpy (&uctx
->uc_mcontext
.mc_gregs
[3],
648 sctx
->sigc_regs
.u_regs
,
649 sizeof (sctx
->sigc_regs
.u_regs
));
652 ucontext_t
*uctx
= (ucontext_t
*) puc
;
655 for (int ii
= 0; ii
< hwcdef_cnt
; ii
++)
656 if (lost_samples
.ce_pic
[ii
])
657 collector_record_counter (&expr_lostcounts_uc
, hwcdef
[ii
]->timecvt
,
658 hwcdef
[ii
]->memop
, lost_samples
.ce_hrt
,
659 hwcdef
[ii
]->sort_order
, lost_samples
.ce_pic
[ii
]);
660 for (int ii
= 0; ii
< hwcdef_cnt
; ii
++)
661 if (sample
.ce_pic
[ii
])
662 collector_record_counter (uctx
, hwcdef
[ii
]->timecvt
,
663 hwcdef
[ii
]->memop
, sample
.ce_hrt
,
664 hwcdef
[ii
]->sort_order
, sample
.ce_pic
[ii
]);
666 rc
= get_hwc_driver ()->hwcdrv_sighlr_restart (NULL
);
668 /* SIGPROF -- not installed as handler, but
669 * __collector_ext_hwc_check: called by (SIGPROF) dispatcher.
670 * Periodical check of integrity of HWC count/signal mechanism,
671 * as required for various chip/system bugs/workarounds.
674 __collector_ext_hwc_check (siginfo_t
*info
, ucontext_t
*vcontext
) { }
676 /*---------------------------------------------------------------------------*/
678 collector_sigemt_sigaction (const struct sigaction
*nact
,
679 struct sigaction
*oact
)
681 struct sigaction oact_check
;
682 /* Error codes and messages that refer to HWC are tricky.
683 * E.g., HWC profiling might not even be on; we might
684 * encounter an error here simply because the user is
685 * trying to set a handler for a signal that happens to
686 * be HWCFUNCS_SIGNAL, which we aren't even using.
688 if (__collector_sigaction (HWCFUNCS_SIGNAL
, NULL
, &oact_check
) != 0)
690 TprintfT (0, "hwprofile: ERROR: collector_sigemt_sigaction(): request to set handler for signal %d, but check on existing handler failed\n", HWCFUNCS_SIGNAL
);
691 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
);
692 return COL_ERROR_HWCINIT
;
695 if (oact_check
.sa_sigaction
== collector_sigemt_handler
)
697 /* dispatcher is in place, so nact/oact apply to old_sigemt_handler */
700 oact
->sa_handler
= old_sigemt_handler
.sa_handler
;
701 oact
->sa_mask
= old_sigemt_handler
.sa_mask
;
702 oact
->sa_flags
= old_sigemt_handler
.sa_flags
;
706 old_sigemt_handler
.sa_handler
= nact
->sa_handler
;
707 old_sigemt_handler
.sa_mask
= nact
->sa_mask
;
708 old_sigemt_handler
.sa_flags
= nact
->sa_flags
;
710 return COL_ERROR_NONE
;
712 else /* no dispatcher in place, so just act like normal sigaction() */
713 return __collector_sigaction (HWCFUNCS_SIGNAL
, nact
, oact
);
717 collector_hwc_ABORT (int errnum
, const char *msg
)
719 TprintfT (0, "hwprofile: collector_hwc_ABORT: [%d] %s\n", errnum
, msg
);
720 if (hwc_mode
== HWCMODE_ABORT
) /* HWC collection already aborted! */
722 set_hwc_mode (HWCMODE_ABORT
); /* set global flag to disable handlers and indicate abort */
724 /* Write the error message to the experiment */
725 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
726 SP_JCMD_CERROR
, COL_ERROR_HWCFAIL
, msg
, errnum
);
731 TprintfT (0, "hwprofile: Continuing without HWC collection...\n");
736 start_data_collection (void)
738 hwc_mode_t old_mode
= hwc_mode
;
739 if (!COUNTERS_ENABLED ())
740 return COL_ERROR_NONE
;
741 TprintfT (0, "hwprofile: start_data_collection (hwc_mode=%d)\n", old_mode
);
745 if (get_hwc_driver ()->hwcdrv_start ())
747 TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_start()\n");
748 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
749 SP_JCMD_CERROR
, COL_ERROR_HWCFAIL
,
750 "start_data_collection()", errno
);
751 return COL_ERROR_HWCINIT
;
753 set_hwc_mode (HWCMODE_ACTIVE
); /* start handling events on signals */
755 case HWCMODE_SUSPEND
:
756 if (get_hwc_driver ()->hwcdrv_lwp_resume ())
758 TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_lwp_resume()\n");
759 /* ignore errors from lwp_resume() */
761 set_hwc_mode (HWCMODE_ACTIVE
); /* start handling events on signals */
764 TprintfT (0, "hwprofile: ERROR: start_data_collection() invalid mode\n");
765 return COL_ERROR_HWCINIT
;
767 return COL_ERROR_NONE
;
771 stop_data_collection (void)
773 hwc_mode_t old_mode
= hwc_mode
;
774 if (!COUNTERS_ENABLED ())
775 return COL_ERROR_NONE
;
776 TprintfT (0, "hwprofile: stop_data_collection (hwc_mode=%d)\n", old_mode
);
779 case HWCMODE_SUSPEND
:
780 return COL_ERROR_NONE
;
782 set_hwc_mode (HWCMODE_SUSPEND
); /* stop handling signals */
785 /* Don't change the mode, but attempt to suspend anyway... */
789 if (get_hwc_driver ()->hwcdrv_lwp_suspend ())
790 /* ignore errors from lwp_suspend() */
791 TprintfT (0, "hwprofile: ERROR: stop_data_collection() failed in hwcdrv_lwp_suspend()\n");
794 * hwcdrv_lwp_suspend() cannot guarantee that all SIGEMTs will stop
795 * but hwc_mode will prevent logging and counters will overflow once
798 /* There may still be pending SIGEMTs so don't reset the SIG_DFL handler.
800 /* see comment in dispatcher.c */
801 /* ret = __collector_sigaction( SIGEMT, &old_sigemt_handler, NULL ); */
802 return COL_ERROR_NONE
;
805 /*---------------------------------------------------------------------------*/
809 set_hwc_mode (hwc_mode_t md
)
811 TprintfT (DBG_LT1
, "hwprofile: set_hwc_mode(%d)\n", md
);
816 __collector_ext_hwc_active ()
818 return (hwc_mode
== HWCMODE_ACTIVE
);
824 collector_interface
->writeLog ("<profdata fname=\"%s\"/>\n",
825 module_interface
.description
);
826 /* Record Hwcntr_packet description */
827 Hwcntr_packet
*pp
= NULL
;
828 collector_interface
->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", HW_PCKT
);
829 collector_interface
->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
830 &pp
->comm
.lwp_id
, sizeof (pp
->comm
.lwp_id
) == 4 ? "INT32" : "INT64");
831 collector_interface
->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
832 &pp
->comm
.thr_id
, sizeof (pp
->comm
.thr_id
) == 4 ? "INT32" : "INT64");
833 collector_interface
->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
834 &pp
->comm
.cpu_id
, sizeof (pp
->comm
.cpu_id
) == 4 ? "INT32" : "INT64");
835 collector_interface
->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
836 &pp
->comm
.tstamp
, sizeof (pp
->comm
.tstamp
) == 4 ? "INT32" : "INT64");
837 collector_interface
->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
838 &pp
->comm
.frinfo
, sizeof (pp
->comm
.frinfo
) == 4 ? "INT32" : "INT64");
839 collector_interface
->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
840 &pp
->tag
, sizeof (pp
->tag
) == 4 ? "INT32" : "INT64");
841 collector_interface
->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
842 &pp
->interval
, sizeof (pp
->interval
) == 4 ? "INT32" : "INT64");
843 collector_interface
->writeLog ("</profpckt>\n");
844 if (hwcdef_has_memspace
)
846 /* Record MHwcntr_packet description */
847 MHwcntr_packet
*xpp
= NULL
;
848 collector_interface
->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", MHWC_PCKT
);
849 collector_interface
->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
850 &xpp
->comm
.lwp_id
, sizeof (xpp
->comm
.lwp_id
) == 4 ? "INT32" : "INT64");
851 collector_interface
->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
852 &xpp
->comm
.thr_id
, sizeof (xpp
->comm
.thr_id
) == 4 ? "INT32" : "INT64");
853 collector_interface
->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
854 &xpp
->comm
.cpu_id
, sizeof (xpp
->comm
.cpu_id
) == 4 ? "INT32" : "INT64");
855 collector_interface
->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
856 &xpp
->comm
.tstamp
, sizeof (xpp
->comm
.tstamp
) == 4 ? "INT32" : "INT64");
857 collector_interface
->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
858 &xpp
->comm
.frinfo
, sizeof (xpp
->comm
.frinfo
) == 4 ? "INT32" : "INT64");
859 collector_interface
->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
860 &xpp
->tag
, sizeof (xpp
->tag
) == 4 ? "INT32" : "INT64");
861 collector_interface
->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
862 &xpp
->interval
, sizeof (xpp
->interval
) == 4 ? "INT32" : "INT64");
863 collector_interface
->writeLog (" <field name=\"VADDR\" uname=\"" STXT ("Virtual address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
864 &xpp
->ea_vaddr
, sizeof (xpp
->ea_vaddr
) == 4 ? "UINT32" : "UINT64");
865 collector_interface
->writeLog (" <field name=\"PADDR\" uname=\"" STXT ("Physical address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
866 &xpp
->ea_paddr
, sizeof (xpp
->ea_paddr
) == 4 ? "UINT32" : "UINT64");
867 collector_interface
->writeLog (" <field name=\"VIRTPC\" uname=\"" STXT ("Virtual address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
868 &xpp
->pc_vaddr
, sizeof (xpp
->pc_vaddr
) == 4 ? "UINT32" : "UINT64");
869 collector_interface
->writeLog (" <field name=\"PHYSPC\" uname=\"" STXT ("Physical address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
870 &xpp
->pc_paddr
, sizeof (xpp
->pc_paddr
) == 4 ? "UINT32" : "UINT64");
871 collector_interface
->writeLog (" <field name=\"EA_PAGESIZE\" uname=\"" STXT ("Page size (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
872 &xpp
->ea_pagesz
, sizeof (xpp
->ea_pagesz
) == 4 ? "INT32" : "INT64");
873 collector_interface
->writeLog (" <field name=\"PC_PAGESIZE\" uname=\"" STXT ("Page size (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
874 &xpp
->pc_pagesz
, sizeof (xpp
->pc_pagesz
) == 4 ? "INT32" : "INT64");
875 collector_interface
->writeLog (" <field name=\"EA_LGRP\" uname=\"" STXT ("Page locality group (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
876 &xpp
->ea_lgrp
, sizeof (xpp
->ea_lgrp
) == 4 ? "INT32" : "INT64");
877 collector_interface
->writeLog (" <field name=\"PC_LGRP\" uname=\"" STXT ("Page locality group (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
878 &xpp
->pc_lgrp
, sizeof (xpp
->pc_lgrp
) == 4 ? "INT32" : "INT64");
879 collector_interface
->writeLog (" <field name=\"LWP_LGRP_HOME\" uname=\"" STXT ("LWP home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
880 &xpp
->lgrp_lwp
, sizeof (xpp
->lgrp_lwp
) == 4 ? "INT32" : "INT64");
881 collector_interface
->writeLog (" <field name=\"PS_LGRP_HOME\" uname=\"" STXT ("Process home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
882 &xpp
->lgrp_ps
, sizeof (xpp
->lgrp_ps
) == 4 ? "INT32" : "INT64");
883 collector_interface
->writeLog (" <field name=\"MEM_LAT\" uname=\"" STXT ("Memory Latency Cycles") "\" offset=\"%d\" type=\"%s\"/>\n",
884 &xpp
->latency
, sizeof (xpp
->latency
) == 4 ? "INT32" : "INT64");
885 collector_interface
->writeLog (" <field name=\"MEM_SRC\" uname=\"" STXT ("Memory Data Source") "\" offset=\"%d\" type=\"%s\"/>\n",
886 &xpp
->data_source
, sizeof (xpp
->data_source
) == 4 ? "INT32" : "INT64");
887 collector_interface
->writeLog ("</profpckt>\n");
892 hwclogwrite (Hwcentry
* ctr
)
894 TprintfT (DBG_LT1
, "hwprofile: writeLog(%s %u %s %d %u %d)\n",
895 SP_JCMD_HW_COUNTER
, cpcN_cpuver
, ctr
->name
? ctr
->name
: "NULL",
896 ctr
->val
, ctr
->sort_order
, ctr
->memop
);
897 collector_interface
->writeLog ("<profile name=\"%s\"", SP_JCMD_HW_COUNTER
);
898 collector_interface
->writeLog (" cpuver=\"%u\"", cpcN_cpuver
);
899 collector_interface
->writeLog (" hwcname=\"%s\"", ctr
->name
);
900 collector_interface
->writeLog (" int_name=\"%s\"", ctr
->int_name
);
901 collector_interface
->writeLog (" interval=\"%d\"", ctr
->val
);
902 collector_interface
->writeLog (" tag=\"%u\"", ctr
->sort_order
);
903 collector_interface
->writeLog (" memop=\"%d\"", ctr
->memop
);
904 collector_interface
->writeLog ("/>\n");