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