/* Copyright (C) 2021-2023 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* Hardware counter profiling driver's header */ #ifndef __HWCDRV_H #define __HWCDRV_H #include "hwcfuncs.h" #ifdef linux #define HWCFUNCS_SIGNAL SIGIO #define HWCFUNCS_SIGNAL_STRING "SIGIO" #else #define HWCFUNCS_SIGNAL SIGEMT #define HWCFUNCS_SIGNAL_STRING "SIGEMT" #endif #ifndef LIBCOLLECTOR_SRC /* not running in libcollector */ #include #else /* running in libcollector */ #include "collector_module.h" #include "libcol_util.h" #define get_hwcdrv __collector_get_hwcdrv #define hwcdrv_drivers __collector_hwcdrv_drivers #define hwcdrv_cpc1_api __collector_hwcdrv_cpc1_api #define hwcdrv_cpc2_api __collector_hwcdrv_cpc2_api #define hwcdrv_default __collector_hwcdrv_default #define hwcdrv_driver __collector_hwcdrv_driver #define hwcdrv_init __collector_hwcdrv_init #define hwcdrv_get_info __collector_hwcdrv_get_info #define hwcdrv_enable_mt __collector_hwcdrv_enable_mt #define hwcdrv_get_descriptions __collector_hwcdrv_get_descriptions #define hwcdrv_assign_regnos __collector_hwcdrv_assign_regnos #define hwcdrv_create_counters __collector_hwcdrv_create_counters #define hwcdrv_start __collector_hwcdrv_start #define hwcdrv_overflow __collector_hwcdrv_overflow #define hwcdrv_read_events __collector_hwcdrv_read_events #define hwcdrv_sighlr_restart __collector_hwcdrv_sighlr_restart #define hwcdrv_lwp_suspend __collector_hwcdrv_lwp_suspend #define hwcdrv_lwp_resume __collector_hwcdrv_lwp_resume #define hwcdrv_free_counters __collector_hwcdrv_free_counters #define hwcdrv_lwp_init __collector_hwcdrv_lwp_init #define hwcdrv_lwp_fini __collector_hwcdrv_lwp_fini #define hwcdrv_assign_all_regnos __collector_hwcdrv_assign_all_regnos #define hwcdrv_lookup_cpuver __collector_hwcdrv_lookup_cpuver #define hwcfuncs_int_capture_errmsg __collector_hwcfuncs_int_capture_errmsg #define GTXT(x) x /* Implemented by libcollector */ #define calloc __collector_calloc #define close CALL_UTIL(close) #define fcntl CALL_UTIL(fcntl) #define fprintf CALL_UTIL(fprintf) //#define free __collector_free #define free(...) #define gethrtime __collector_gethrtime #define ioctl CALL_UTIL(ioctl) #define malloc __collector_malloc #define memcpy __collector_memcpy #define memset CALL_UTIL(memset) #define mmap CALL_UTIL(mmap) #define snprintf CALL_UTIL(snprintf) #define strchr CALL_UTIL(strchr) #define strcmp CALL_UTIL(strcmp) #define strncmp CALL_UTIL(strncmp) #define strcpy CALL_UTIL(strcpy) #define strdup __collector_strdup #define strncpy CALL_UTIL(strncpy) #define strerror CALL_UTIL(strerror) #define strlen CALL_UTIL(strlen) #define strstr CALL_UTIL(strstr) #define strtol CALL_UTIL(strtol) #define strtoll CALL_UTIL(strtoll) #define strtoul CALL_UTIL(strtoul) #define strtoull CALL_UTIL(strtoull) #define syscall CALL_UTIL(syscall) #define sysconf CALL_UTIL(sysconf) #define vsnprintf CALL_UTIL(vsnprintf) #endif /* --- LIBCOLLECTOR_SRC --- */ /* TprintfT(,...) definitions. Adjust per module as needed */ #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings #define DBG_LT1 1 // for configuration details, warnings #define DBG_LT2 2 #define DBG_LT3 3 #define DBG_LT4 4 #ifdef __cplusplus extern "C" { #endif /* hwcdrv api */ typedef struct { int (*hwcdrv_init)(hwcfuncs_abort_fn_t abort_ftn, int * tsd_sz); /* Initialize hwc counter library (do not call again after fork) Must be called before other functions. Input: : NULL or callback function to be used for fatal errors : If not NULL, returns size in bytes required for thread-specific storage Return: 0 if successful */ void (*hwcdrv_get_info)(int *cpuver, const char **cciname, uint_t *npics, const char **docref, uint64_t *support); /* get info about session Input: : if not NULL, returns value of CPC cpu version : if not NULL, returns name of CPU : if not NULL, returns maximum # of HWCs : if not NULL, returns documentation reference : if not NULL, returns bitmask (see hwcfuncs.h) of hwc support Return: 0 if successful, nonzero otherwise */ int (*hwcdrv_enable_mt)(hwcfuncs_tsd_get_fn_t tsd_ftn); /* Enables multi-threaded mode (do not need to call again after fork) Input: : If ==0, this parameter is ignored. Otherwise: tsd_ftn() must be able to return a pointer to thread-specific memory of bytes. For a given thread, tsd_ftn() must always return the same pointer. Return: none */ int (*hwcdrv_get_descriptions)(hwcf_hwc_cb_t *hwc_find_action, hwcf_attr_cb_t *attr_find_action); /* Initiate callbacks with all available HWC names and and HWC attributes. Input: : if not NULL, will be called once for each HWC : if not NULL, will be called once for each attribute Return: 0 if successful or a cpc return code upon error */ int (*hwcdrv_assign_regnos)(Hwcentry* entries[], unsigned numctrs); /* Assign entries[]->reg_num values as needed by platform Input: : array of counters : number of items in Return: 0 if successful HWCFUNCS_ERROR_HWCINIT if resources unavailable HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly */ int (*hwcdrv_create_counters)(unsigned hwcdef_cnt, Hwcentry *hwcdef); /* Create the counters, but don't start them. call this once in main thread to create counters. Input: : number of counter definitions. : counter definitions. Return: 0 if successful or a cpc return code upon error */ int (*hwcdrv_start)(void); /* Start the counters. call this once in main thread to start counters. Return: 0 if successful or a cpc return code upon error */ int (*hwcdrv_overflow)(siginfo_t *si, hwc_event_t *sample, hwc_event_t *lost_samples); /* Linux only. Capture current counter values. This is intended to be called from SIGEMT handler; Input: : signal handler context information : returns non-zero values for counters that overflowed : returns non-zero values for counters that "lost" counts Return: 0 if successful or a cpc return code upon error. */ int (*hwcdrv_read_events)(hwc_event_t *overflow_data, hwc_event_samples_t *sampled_data); /* Read current counter values and samples. Read of samples is destructive. Note: hwcdrv_read_events is not supported on Linux. : returns snapshot of counter values : returns sampled data Return: 0 if successful HWCFUNCS_ERROR_UNAVAIL if resource unavailable(e.g. called before initted) (other values may be possible) */ int (*hwcdrv_sighlr_restart)(const hwc_event_t* startVals); /* Restarts the counters at the given value. This is intended to be called from SIGEMT handler; Input: : Solaris: new start values. Linux: pointer may be NULL; startVals is ignored. Return: 0 if successful or a cpc return code upon error. */ int (*hwcdrv_lwp_suspend)(void); /* Attempt to stop counters on this lwp only. hwcdrv_lwp_resume() should be used to restart counters. Return: 0 if successful or a cpc return code upon error. */ int (*hwcdrv_lwp_resume)(void); /* Attempt to restart counters on this lwp when counters were stopped with hwcdrv_lwp_suspend(). Return: 0 if successful or a cpc return code upon error. */ int (*hwcdrv_free_counters)(void); /* Stops counters on this lwp only and frees resources. This will fail w/ unpredictable results if other lwps's are still running. After this call returns, hwcdrv_create_counters() may be called with new values. Return: 0 if successful or a cpc return code upon error. */ int (*hwcdrv_lwp_init)(void); /* per-thread counter init. Solaris: nop. Linux: just after thread creation call this from inside thread to create context and start counters. Return: 0 if successful or a perfctr return code upon error */ void (*hwcdrv_lwp_fini)(void); /* per-thread counter cleanup. Solaris: nop. Linux: call in each thread upon thread destruction. */ int hwcdrv_init_status; } hwcdrv_api_t; extern hwcdrv_api_t *get_hwcdrv (); extern hwcdrv_api_t *__collector_get_hwcdrv (); extern int __collector_hwcfuncs_bind_descriptor (const char *defstring); extern Hwcentry **__collector_hwcfuncs_get_ctrs (unsigned *defcnt); extern hwcdrv_api_t *hwcdrv_drivers[]; // array of available drivers /* prototypes for internal use by hwcdrv drivers */ typedef struct { // see hwcdrv_get_info() for field definitions int cpcN_cpuver; uint_t cpcN_npics; const char *cpcN_docref; const char *cpcN_cciname; } hwcdrv_about_t; extern int hwcdrv_assign_all_regnos (Hwcentry* entries[], unsigned numctrs); /* assign user's counters to specific CPU registers */ extern int hwcdrv_lookup_cpuver (const char * cpcN_cciname); /* returns hwc_cpus.h ID for a given string. */ extern void hwcfuncs_int_capture_errmsg (const char *fn, int subcode, const char *fmt, va_list ap); #define logerr hwcfuncs_int_logerr /*---------------------------------------------------------------------------*/ /* prototypes for internal use by linux hwcdrv drivers */ #define PERFCTR_FIXED_MAGIC 0x40000000 /* tells perfctr to use intel fixed pmcs */ #define PERFCTR_UMASK_SHIFT 8 #define EXTENDED_EVNUM_2_EVSEL(evnum) \ ( (((eventsel_t)(evnum) & 0x0f00ULL) << 24) | ((eventsel_t)(evnum) & ~0x0f00ULL) ) typedef uint64_t eventsel_t; extern int hwcfuncs_get_x86_eventsel (unsigned int regno, const char *int_name, eventsel_t *return_event, uint_t *return_pmc_sel); typedef int (hwcdrv_get_events_fn_t) (hwcf_hwc_cb_t *hwc_cb); typedef int (hwcdrv_get_eventnum_fn_t) (const char *eventname, uint_t pmc, eventsel_t *eventnum, eventsel_t *valid_umask, uint_t *pmc_sel); extern hwcdrv_get_eventnum_fn_t *hwcdrv_get_x86_eventnum; typedef struct { const char * attrname; // user-visible name of attribute int is_inverted; // nonzero means boolean attribute is inverted eventsel_t mask; // which attribute bits can be set? eventsel_t shift; // how far to shift bits for use in x86 register } attr_info_t; extern const attr_info_t *perfctr_attrs_table; /* hdrv_pcbe api: cpu-specific drivers for Linux */ typedef struct { int (*hdrv_pcbe_init)(void); uint_t (*hdrv_pcbe_ncounters)(void); const char *(*hdrv_pcbe_impl_name)(void); const char *(*hdrv_pcbe_cpuref)(void); int (*hdrv_pcbe_get_events)(hwcf_hwc_cb_t *hwc_cb); int (*hdrv_pcbe_get_eventnum)(const char * eventname, uint_t pmc, eventsel_t *eventnum, eventsel_t *valid_umask, uint_t *pmc_sel); } hdrv_pcbe_api_t; #ifdef __cplusplus } #endif #endif