| /* Copyright (C) 2021-2024 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 <string.h> |
| |
| #else /* running in libcollector */ |
| #include "collector_module.h" |
| #include "libcol_util.h" |
| |
| #define get_hwcdrv __collector_get_hwcdrv |
| |
| #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(<level>,...) 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: |
| <abort_ftn>: NULL or callback function to be used for fatal errors |
| <tsd_sz>: 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: |
| <cpuver>: if not NULL, returns value of CPC cpu version |
| <cciname>: if not NULL, returns name of CPU |
| <npics>: if not NULL, returns maximum # of HWCs |
| <docref>: if not NULL, returns documentation reference |
| <support>: 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: |
| <tsd_ftn>: If <tsd_sz>==0, this parameter is ignored. |
| Otherwise: |
| tsd_ftn() must be able to return a pointer to thread-specific |
| memory of <tsd_sz> 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, |
| Hwcentry *raw_hwc_tbl); |
| /* Initiate callbacks with all available HWC names and HWC attributes. |
| Input: |
| <hwc_find_action>: if not NULL, will be called once for each HWC |
| <attr_find_action>: if not NULL, will be called once for each attribute |
| <raw_hwc_tbl>: counter definitions. |
| 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: |
| <entries>: array of counters |
| <numctrs>: number of items in <entries> |
| 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: |
| <defcnt>: number of counter definitions. |
| <hwcdef>: 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: |
| <si>: signal handler context information |
| <sample>: returns non-zero values for counters that overflowed |
| <lost_samples>: 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. |
| <overflow_data>: returns snapshot of counter values |
| <sampled_data>: 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: |
| <startVals>: 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); |
| |
| /* 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; |
| |
| #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; |
| 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, Hwcentry *raw_hwc_tbl); |
| 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 |