Home | History | Annotate | Line # | Download | only in libcollector
hwprofile.c revision 1.1
      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 #include <ucontext.h>
     33 
     34 #include "gp-defs.h"
     35 #define _STRING_H 1  /* XXX MEZ: temporary workaround */
     36 #include "hwcdrv.h"
     37 #include "collector_module.h"
     38 #include "gp-experiment.h"
     39 #include "libcol_util.h"
     40 #include "hwprofile.h"
     41 #include "ABS.h"
     42 #include "tsd.h"
     43 
     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
     47 #define DBG_LT2 2
     48 #define DBG_LT3 3
     49 #define DBG_LT4 4
     50 #define DBG_LT5 5
     51 
     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() */
     55 
     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);
     63 
     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) */
     72 };
     73 
     74 static CollectorInterface *collector_interface = NULL;
     75 
     76 
     77 /*---------------------------------------------------------------------------*/
     78 /* compile options and workarounds */
     79 
     80 /* Solaris: We set ITIMER_REALPROF to ensure that counters get started on
     81  *      LWPs that existed before the collector initialization.
     82  *
     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.
     89  */
     90 
     91 /*---------------------------------------------------------------------------*/
     92 /* typedefs */
     93 
     94 typedef enum {
     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 */
     99 } hwc_mode_t;
    100 
    101 /*---------------------------------------------------------------------------*/
    102 /* prototypes */
    103 static void init_ucontexts (void);
    104 static int hwc_initialize_handlers (void);
    105 static void collector_record_counter (ucontext_t*,
    106 				      int timecvt,
    107 				      ABST_type, hrtime_t,
    108 				      unsigned, uint64_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);
    114 
    115 /*---------------------------------------------------------------------------*/
    116 /* static variables */
    117 
    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;
    132 
    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
    140 
    141 /* --- signal handler state */
    142 static struct sigaction old_sigemt_handler;  //overwritten in fork-child
    143 
    144 /*---------------------------------------------------------------------------*/
    145 /* macros */
    146 #define COUNTERS_ENABLED()  (hwcdef_cnt)
    147 #define gethrtime           collector_interface->getHiResTime
    148 
    149 #ifdef DEBUG
    150 #define Tprintf(...)   if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
    151 #define TprintfT(...)  if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
    152 #else
    153 #define Tprintf(...)
    154 #define TprintfT(...)
    155 #endif
    156 
    157 
    158 /*---------------------------------------------------------------------------*/
    159 
    160 /* Initialization routines */
    161 static hwcdrv_api_t *
    162 get_hwc_driver ()
    163 {
    164   if (hwc_driver == NULL)
    165     hwc_driver = __collector_get_hwcdrv ();
    166   return hwc_driver;
    167 }
    168 
    169 static void init_module () __attribute__ ((constructor));
    170 static void
    171 init_module ()
    172 {
    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)
    177     {
    178       TprintfT (0, "hwprofile: init_module FAILED - reg_module = NULL\n");
    179       return;
    180     }
    181   expr_hndl = reg_module (&module_interface);
    182   if (expr_hndl == COLLECTOR_MODULE_ERR)
    183     {
    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);
    188     }
    189 }
    190 
    191 static int
    192 init_interface (CollectorInterface *_collector_interface)
    193 {
    194   collector_interface = _collector_interface;
    195   return COL_ERROR_NONE;
    196 }
    197 
    198 static void *
    199 hwprofile_get_tsd ()
    200 {
    201   return collector_interface->getKey (hwprofile_tsd_key);
    202 }
    203 
    204 static int
    205 open_experiment (const char *exp)
    206 {
    207   if (collector_interface == NULL)
    208     {
    209       TprintfT (0, "hwprofile: ERROR: collector_interface is null.\n");
    210       return COL_ERROR_HWCINIT;
    211     }
    212   const char *params = collector_interface->getParams ();
    213   while (params)
    214     {
    215       if (__collector_strStartWith (params, "h:*") == 0)
    216 	{
    217 	  /* HWC counters set by default */
    218 	  collector_interface->writeLog ("<%s %s=\"1\"/>\n",
    219 					 SP_TAG_SETTING, SP_JCMD_HWC_DEFAULT);
    220 	  params += 3;
    221 	  break;
    222 	}
    223       else if (__collector_strStartWith (params, "h:") == 0)
    224 	{
    225 	  params += 2;
    226 	  break;
    227 	}
    228       params = CALL_UTIL (strchr)(params, ';');
    229       if (params)
    230 	params++;
    231     }
    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);
    239 
    240   int err = COL_ERROR_NONE;
    241   /* init counter library */
    242   if (!hwcdrv_inited)
    243     { /* do not call hwcdrv_init() from fork-child */
    244       hwcdrv_inited = 1;
    245       get_hwc_driver ();
    246       if (hwc_driver->hwcdrv_init (collector_hwc_ABORT, &hwprofile_tsd_sz) == 0)
    247 	{
    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;
    252 	}
    253 
    254       if (hwc_driver->hwcdrv_enable_mt (hwprofile_get_tsd))
    255 	{
    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;
    261 	}
    262 
    263       hwc_driver->hwcdrv_get_info (&cpcN_cpuver, NULL, NULL, NULL, NULL);
    264       if (cpcN_cpuver < 0)
    265 	{
    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;
    270 	}
    271     }
    272 
    273   if (hwprofile_tsd_sz)
    274     {
    275       hwprofile_tsd_key = collector_interface->createKey (hwprofile_tsd_sz, NULL, NULL);
    276       if (hwprofile_tsd_key == COLLECTOR_TSD_INVALID_KEY)
    277 	{
    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;
    282 	}
    283     }
    284   hwcdef_cnt = 0;
    285   hwcdef_has_memspace = 0;
    286 
    287   /* create counters based on hwcdef[] */
    288   err = __collector_hwcfuncs_bind_descriptor (defstring);
    289   if (err)
    290     {
    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);
    295       return err;
    296     }
    297 
    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;
    301   int idx;
    302   for (idx = 0; idx < hwcdef_cnt; idx++)
    303     {
    304       if (HWCENTRY_USES_SAMPLING (hwcdef[idx]))
    305 	{
    306 	  hwcdef_num_sampling_ctrdefs++;
    307 	}
    308       else
    309 	{
    310 	  hwcdef_num_overflow_ctrdefs++;
    311 	}
    312     }
    313 
    314   init_ucontexts ();
    315 
    316   /* initialize the SIGEMT handler, and the periodic HWC checker */
    317   err = hwc_initialize_handlers ();
    318   if (err != COL_ERROR_NONE)
    319     {
    320       hwcdef_cnt = 0;
    321       TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
    322       /* log written by hwc_initialize_handlers() */
    323       return err;
    324     }
    325 
    326   for (idx = 0; idx < hwcdef_cnt; idx++)
    327     if (ABST_BACKTRACK_ENABLED (hwcdef[idx]->memop))
    328       hwcdef_has_memspace = 1;
    329 
    330   /* record the hwc definitions in the log, based on the counter array */
    331   hwclogwrite0 ();
    332   for (idx = 0; idx < hwcdef_cnt; idx++)
    333     hwclogwrite (hwcdef[idx]);
    334   return COL_ERROR_NONE;
    335 }
    336 
    337 int
    338 __collector_ext_hwc_lwp_init ()
    339 {
    340   return get_hwc_driver ()->hwcdrv_lwp_init ();
    341 }
    342 
    343 void
    344 __collector_ext_hwc_lwp_fini ()
    345 {
    346   get_hwc_driver ()->hwcdrv_lwp_fini ();
    347 }
    348 
    349 int
    350 __collector_ext_hwc_lwp_suspend ()
    351 {
    352   return get_hwc_driver ()->hwcdrv_lwp_suspend ();
    353 }
    354 
    355 int
    356 __collector_ext_hwc_lwp_resume ()
    357 {
    358   return get_hwc_driver ()->hwcdrv_lwp_resume ();
    359 }
    360 
    361 /* Dummy routine, used to provide a context for non-program related profiles */
    362 void
    363 __collector_not_program_related () { }
    364 
    365 /* Dummy routine, used to provide a context for lost counts (perf_events) */
    366 void
    367 __collector_hwc_samples_lost () { }
    368 
    369 /* Dummy routine, used to provide a context */
    370 void
    371 __collector_hwcs_frozen () { }
    372 
    373 /* Dummy routine, used to provide a context */
    374 void
    375 __collector_hwcs_out_of_range () { }
    376 /* initialize some structures */
    377 static void
    378 init_ucontexts (void)
    379 {
    380   /* initialize dummy context for "collector" frames */
    381   getcontext (&expr_dummy_uc);
    382   SETFUNCTIONCONTEXT (&expr_dummy_uc, NULL);
    383 
    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);
    387 
    388   /* initialize dummy context for "frozen" frames */
    389   getcontext (&expr_frozen_uc);
    390   SETFUNCTIONCONTEXT (&expr_frozen_uc, &__collector_hwcs_frozen);
    391 
    392   /* initialize dummy context for non-program-related frames */
    393   getcontext (&expr_nopc_uc);
    394   SETFUNCTIONCONTEXT (&expr_nopc_uc, &__collector_not_program_related);
    395 
    396   /* initialize dummy context for lost-counts-related frames */
    397   getcontext (&expr_lostcounts_uc);
    398   SETFUNCTIONCONTEXT (&expr_lostcounts_uc, &__collector_hwc_samples_lost);
    399 }
    400 /* initialize the signal handler */
    401 static int
    402 hwc_initialize_handlers (void)
    403 {
    404   /* install the signal handler for SIGEMT */
    405   struct sigaction oact;
    406   if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact) != 0)
    407     {
    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;
    411     }
    412   if (oact.sa_sigaction == collector_sigemt_handler)
    413     {
    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");
    416     }
    417   else
    418     {
    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)
    428 	{
    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;
    432 	}
    433     }
    434   return COL_ERROR_NONE;
    435 }
    436 
    437 static int
    438 close_experiment (void)
    439 {
    440   /* note: stop_data_collection() should have already been called by
    441    * collector_close_experiment()
    442    */
    443   if (!COUNTERS_ENABLED ())
    444     return COL_ERROR_NONE;
    445   detach_experiment ();
    446 
    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)
    451    */
    452   struct sigaction curr;
    453   if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &curr) == -1)
    454     {
    455       TprintfT (0, "hwprofile close_experiment: ERROR: hwc sigaction check failed: errno=%d\n", errno);
    456     }
    457   else if (curr.sa_sigaction != collector_sigemt_handler)
    458     {
    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);
    462     }
    463   else
    464     TprintfT (DBG_LT1, "hwprofile close_experiment: collector sigemt handler integrity verified!\n");
    465   TprintfT (0, "hwprofile: close_experiment\n");
    466   return 0;
    467 }
    468 
    469 static int
    470 detach_experiment (void)
    471 {
    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
    476   // via DBX detach.
    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))
    483     return 0;
    484   // one and only one call should ever make it here here.
    485   if (hwc_mode == HWCMODE_ACTIVE)
    486     {
    487       TprintfT (0, "hwprofile: ERROR: stop_data_collection() should have been called before detach_experiment()\n");
    488       stop_data_collection ();
    489     }
    490 
    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)
    496     {
    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");
    501       return 0;
    502     }
    503 
    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
    509 }
    510 
    511 static int
    512 real_detach_experiment (void)
    513 {
    514   /*multiple calls to this routine are OK.*/
    515   if (SD_PENDING != __collector_cas_32 (&sd_state, SD_PENDING, SD_COMPLETE))
    516     return 0;
    517   // only the first caller to this routine should get here.
    518   hwcdef_cnt = 0; /* since now deinstalled */
    519   hwcdef = NULL;
    520   set_hwc_mode (HWCMODE_OFF);
    521   if (SD_COMPLETE != __collector_cas_32 (&sd_state, SD_COMPLETE, SD_OFF))
    522     {
    523       TprintfT (0, "hwprofile: ERROR: unexpected sd_state in real_detach_experiment()\n");
    524       sd_state = SD_OFF;
    525     }
    526   hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
    527   TprintfT (DBG_LT0, "hwprofile: real_detach_experiment() detached from experiment.\n");
    528   return 0;
    529 }
    530 
    531 /*---------------------------------------------------------------------------*/
    532 /* Record counter values. */
    533 
    534 /* <value> should already be adjusted to be "zero-based" (counting up from 0).*/
    535 static void
    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)
    541 {
    542   MHwcntr_packet pckt;
    543   CALL_UTIL (memset)(&pckt, 0, sizeof ( MHwcntr_packet));
    544   pckt.comm.tstamp = time;
    545   pckt.tag = tag;
    546   if (timecvt > 1)
    547     {
    548       if (HWCVAL_HAS_ERR (value))
    549 	{
    550 	  value = HWCVAL_CLR_ERR (value);
    551 	  value *= timecvt;
    552 	  value = HWCVAL_SET_ERR (value);
    553 	}
    554       else
    555 	value *= timecvt;
    556     }
    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)
    563     ucp = &expr_nopc_uc;
    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);
    566 }
    567 
    568 static void
    569 collector_record_counter (ucontext_t *ucp, int timecvt, ABST_type ABS_memop,
    570 			  hrtime_t time, unsigned tag, uint64_t value)
    571 {
    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);
    575 }
    576 
    577 
    578 /*---------------------------------------------------------------------------*/
    579 /* Signal handlers */
    580 
    581 /* SIGEMT -- relayed from libcpc, when the counter overflows */
    582 
    583 /*   Generates the appropriate event or events, and resets the counters */
    584 static void
    585 collector_sigemt_handler (int sig, siginfo_t *si, void *puc)
    586 {
    587   int rc;
    588   hwc_event_t sample, lost_samples;
    589   if (sig != HWCFUNCS_SIGNAL)
    590     {
    591       TprintfT (0, "hwprofile: ERROR: %s: unexpected signal %d\n", "collector_sigemt_handler", sig);
    592       return;
    593     }
    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 */
    598       return;
    599     }
    600 
    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()
    606    */
    607   if (puc == NULL || si == NULL || (si->si_code <= 0 && si->si_code != SI_TKILL))
    608     {
    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)
    614 	{
    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);
    618 	}
    619       return;
    620     }
    621   rc = get_hwc_driver ()->hwcdrv_overflow (si, &sample, &lost_samples);
    622   if (rc)
    623     {
    624       /* hwcdrv_sighlr_restart() should not be called */
    625       TprintfT (0, "hwprofile: ERROR: collector_sigemt_handler: hwcdrv_overflow() failed\n");
    626       return;
    627     }
    628 
    629   if (hwc_mode == HWCMODE_ACTIVE)
    630     {
    631       /* record the event only if counters are active */
    632       /* The following has been copied from dispatcher.c */
    633 #if ARCH(SPARC)
    634       /* 23340823 signal handler third argument should point to a ucontext_t */
    635       /* Convert sigcontext to ucontext_t on sparc-Linux */
    636       ucontext_t uctxmem;
    637       struct sigcontext *sctx = (struct sigcontext*) puc;
    638       ucontext_t *uctx = &uctxmem;
    639       uctx->uc_link = NULL;
    640 #if WSIZE(32)
    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));
    645 #else
    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));
    650 #endif /* WSIZE() */
    651 #else
    652       ucontext_t *uctx = (ucontext_t*) puc;
    653 #endif /* ARCH() */
    654 
    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]);
    665     }
    666   rc = get_hwc_driver ()->hwcdrv_sighlr_restart (NULL);
    667 }
    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.
    672  */
    673 void
    674 __collector_ext_hwc_check (siginfo_t *info, ucontext_t *vcontext) { }
    675 
    676 /*---------------------------------------------------------------------------*/
    677 int
    678 collector_sigemt_sigaction (const struct sigaction *nact,
    679 			    struct sigaction *oact)
    680 {
    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.
    687    */
    688   if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact_check) != 0)
    689     {
    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;
    693     }
    694 
    695   if (oact_check.sa_sigaction == collector_sigemt_handler)
    696     {
    697       /* dispatcher is in place, so nact/oact apply to old_sigemt_handler */
    698       if (oact != NULL)
    699 	{
    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;
    703 	}
    704       if (nact != NULL)
    705 	{
    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;
    709 	}
    710       return COL_ERROR_NONE;
    711     }
    712   else /* no dispatcher in place, so just act like normal sigaction() */
    713     return __collector_sigaction (HWCFUNCS_SIGNAL, nact, oact);
    714 }
    715 
    716 static void
    717 collector_hwc_ABORT (int errnum, const char *msg)
    718 {
    719   TprintfT (0, "hwprofile: collector_hwc_ABORT: [%d] %s\n", errnum, msg);
    720   if (hwc_mode == HWCMODE_ABORT) /* HWC collection already aborted! */
    721     return;
    722   set_hwc_mode (HWCMODE_ABORT); /* set global flag to disable handlers and indicate abort */
    723 
    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);
    727 
    728 #ifdef REAL_DEBUG
    729   abort ();
    730 #else
    731   TprintfT (0, "hwprofile: Continuing without HWC collection...\n");
    732 #endif
    733 }
    734 
    735 static int
    736 start_data_collection (void)
    737 {
    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);
    742   switch (old_mode)
    743     {
    744     case HWCMODE_OFF:
    745       if (get_hwc_driver ()->hwcdrv_start ())
    746 	{
    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;
    752 	}
    753       set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
    754       break;
    755     case HWCMODE_SUSPEND:
    756       if (get_hwc_driver ()->hwcdrv_lwp_resume ())
    757 	{
    758 	  TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_lwp_resume()\n");
    759 	  /* ignore errors from lwp_resume() */
    760 	}
    761       set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
    762       break;
    763     default:
    764       TprintfT (0, "hwprofile: ERROR: start_data_collection() invalid mode\n");
    765       return COL_ERROR_HWCINIT;
    766     }
    767   return COL_ERROR_NONE;
    768 }
    769 
    770 static int
    771 stop_data_collection (void)
    772 {
    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);
    777   switch (old_mode)
    778     {
    779     case HWCMODE_SUSPEND:
    780       return COL_ERROR_NONE;
    781     case HWCMODE_ACTIVE:
    782       set_hwc_mode (HWCMODE_SUSPEND); /* stop handling signals */
    783       break;
    784     default:
    785       /* Don't change the mode, but attempt to suspend anyway... */
    786       break;
    787     }
    788 
    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");
    792 
    793   /*
    794    * hwcdrv_lwp_suspend() cannot guarantee that all SIGEMTs will stop
    795    * but hwc_mode will prevent logging and counters will overflow once
    796    * then stay frozen.
    797    */
    798   /*   There may still be pending SIGEMTs so don't reset the SIG_DFL handler.
    799    */
    800   /* see comment in dispatcher.c */
    801   /* ret = __collector_sigaction( SIGEMT, &old_sigemt_handler, NULL ); */
    802   return COL_ERROR_NONE;
    803 }
    804 
    805 /*---------------------------------------------------------------------------*/
    806 
    807 /* utilities */
    808 static void
    809 set_hwc_mode (hwc_mode_t md)
    810 {
    811   TprintfT (DBG_LT1, "hwprofile: set_hwc_mode(%d)\n", md);
    812   hwc_mode = md;
    813 }
    814 
    815 int
    816 __collector_ext_hwc_active ()
    817 {
    818   return (hwc_mode == HWCMODE_ACTIVE);
    819 }
    820 
    821 static void
    822 hwclogwrite0 ()
    823 {
    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)
    845     {
    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");
    888     }
    889 }
    890 
    891 static void
    892 hwclogwrite (Hwcentry * ctr)
    893 {
    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");
    905 }
    906