269 lines
10 KiB
C
269 lines
10 KiB
C
/* Copyright (C) 2021 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 */
|
|
|
|
#ifndef __HWCFUNCS_H
|
|
#define __HWCFUNCS_H
|
|
|
|
#ifdef LIBCOLLECTOR_SRC /* running in libcollector */
|
|
#define hwcfuncs_int_logerr __collector_hwcfuncs_int_logerr
|
|
#define hwcfuncs_parse_ctr __collector_hwcfuncs_parse_ctr
|
|
#define hwcfuncs_parse_attrs __collector_hwcfuncs_parse_attrs
|
|
#define hwcfuncs_bind_descriptor __collector_hwcfuncs_bind_descriptor
|
|
#define hwcfuncs_bind_hwcentry __collector_hwcfuncs_bind_hwcentry
|
|
#define hwcfuncs_assign_regnos __collector_hwcfuncs_assign_regnos
|
|
#define regno_is_valid __collector_regno_is_valid
|
|
#define hwcfuncs_get_ctrs __collector_hwcfuncs_get_ctrs
|
|
#define hwcfuncs_errmsg_get __collector_hwcfuncs_errmsg_get
|
|
#endif /* --- LIBCOLLECTOR_SRC --- */
|
|
|
|
#include <signal.h> /* siginfo_t */
|
|
#include <limits.h> /* UINT64_t */
|
|
#include <sys/types.h>
|
|
#include <stdint.h>
|
|
|
|
#include "hwcentry.h" /* for Hwcentry type */
|
|
#include "gp-time.h"
|
|
|
|
typedef unsigned int uint_t;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* compile options */
|
|
|
|
#define HWC_DEBUG 0 /* 0/1 to enable extra HWC debug */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* typedefs */
|
|
/* generic hw event */
|
|
typedef struct _hwc_event_t
|
|
{ /* generalized counter event */
|
|
hrtime_t ce_hrt; /* gethrtime() */
|
|
uint64_t ce_pic[MAX_PICS]; /* counter samples or start values */
|
|
} hwc_event_t;
|
|
|
|
/* supplementary data that accompanies some hw events */
|
|
typedef struct
|
|
{ /* supplementary data fields */
|
|
uint64_t smpl_pc; /* pc related to event */
|
|
uint64_t smpl_data_source; /* chip-specific data source encoding */
|
|
uint64_t smpl_latency; /* latency related to event */
|
|
uint64_t smpl_mem_addr; /* memory address related to event */
|
|
} hwc_sample_t;
|
|
#define HWCFUNCS_INVALID_U64 0xFEEDBEEFDEADBEEFllu /* identifies fields as unused */
|
|
|
|
typedef struct { /* supplementary data fields */
|
|
hwc_sample_t sample[MAX_PICS]; /* counter samples or start values */
|
|
} hwc_event_samples_t;
|
|
|
|
#define HWCFUNCS_SAMPLE_RESET(sample) \
|
|
do { \
|
|
(sample)->smpl_pc =HWCFUNCS_INVALID_U64; \
|
|
(sample)->smpl_data_source =HWCFUNCS_INVALID_U64; \
|
|
(sample)->smpl_latency =HWCFUNCS_INVALID_U64; \
|
|
(sample)->smpl_mem_addr =HWCFUNCS_INVALID_U64; \
|
|
} while(0)
|
|
|
|
#define HWCFUNCS_SAMPLE_IS_RESET(sample) \
|
|
( \
|
|
(sample)->smpl_pc ==HWCFUNCS_INVALID_U64 && \
|
|
(sample)->smpl_data_source==HWCFUNCS_INVALID_U64 && \
|
|
(sample)->smpl_latency ==HWCFUNCS_INVALID_U64 && \
|
|
(sample)->smpl_mem_addr ==HWCFUNCS_INVALID_U64 \
|
|
)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* macros */
|
|
|
|
#define HW_INTERVAL_MAX UINT64_MAX
|
|
#define HW_INTERVAL_PRESET(x) (HW_INTERVAL_MAX - ((uint64_t)(x) - 1))
|
|
#define HW_INTERVAL_TYPE(x) ((uint64_t) (x)
|
|
|
|
/* parsing */
|
|
#define HWCFUNCS_MAX_ATTRS 20
|
|
#define HWCFUNCS_PARSE_ATTR '~'
|
|
#define HWCFUNCS_PARSE_EQUAL '='
|
|
#define HWCFUNCS_PARSE_BACKTRACK '+'
|
|
#define HWCFUNCS_PARSE_BACKTRACK_OFF '-'
|
|
#define HWCFUNCS_PARSE_REGNUM '/'
|
|
#define HWCFUNCS_PARSE_VALUE ','
|
|
|
|
/* error codes */
|
|
#define HWCFUNCS_ERROR_GENERIC (-1)
|
|
#define HWCFUNCS_ERROR_NOT_SUPPORTED (-2)
|
|
#define HWCFUNCS_ERROR_ALREADY_CALLED (-3)
|
|
#define HWCFUNCS_ERROR_HWCINIT (-4)
|
|
#define HWCFUNCS_ERROR_HWCARGS (-5)
|
|
#define HWCFUNCS_ERROR_MEMORY (-6)
|
|
#define HWCFUNCS_ERROR_UNAVAIL (-7)
|
|
#define HWCFUNCS_ERROR_ERRNO_ZERO (-8)
|
|
#define HWCFUNCS_ERROR_UNEXPECTED (-99)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* prototypes */
|
|
|
|
typedef void (*hwcfuncs_abort_fn_t) (int errnum, const char *msg);
|
|
|
|
extern void hwcfuncs_int_logerr(const char *format,...);
|
|
/* Log an error to the internal error buffer. See hwcfuncs_errmsg_get().
|
|
Note: Not MT-safe; don't even enable logging in an MT environment.
|
|
Recommend using this call only during init.
|
|
Note: when a libcpc call fails, it may automatically call
|
|
cpcN_capture_errmsg() to log the error message in the same internal buffer.
|
|
Recommend using this call only for non-cpc failures.
|
|
*/
|
|
|
|
#define HWCFUNCS_SUPPORT_OVERFLOW_PROFILING 0x01llu
|
|
#define HWCFUNCS_SUPPORT_PEBS_SAMPLING 0x02llu
|
|
#define HWCFUNCS_SUPPORT_OVERFLOW_CTR_ID 0x04llu // OS identifies which counter overflowed
|
|
/* 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 above) of hwc support
|
|
Return: none
|
|
*/
|
|
|
|
typedef void* (*hwcfuncs_tsd_get_fn_t) (void);
|
|
typedef void (hwcf_hwc_cb_t) (uint_t cpcregno, const char *name);
|
|
typedef void (hwcf_attr_cb_t) (const char *attr);
|
|
|
|
extern void
|
|
hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
|
|
char **pattrs, char **pregstr, regno_t *pregno);
|
|
/* Parse a counter definition string (value must already be stripped off).
|
|
Input:
|
|
<counter_def>: input whose format is
|
|
[+|-]<countername>[~attrs...][/<regno>]
|
|
pointers to return values: Any can be NULL.
|
|
Return:
|
|
<plus>: 1 if [+] is found, -1 if [-] is found, 0 otherwise
|
|
<pnameonly>: strdup(<countername>)
|
|
<pattrs>: strdup([~attrs...]) if specified, NULL otherwise.
|
|
<pregstr>: strdup(/<regno>) if specified, NULL otherwise.
|
|
<pregno>: <regno> if readable, REGNO_ANY if not specd, or -2 otherwise.
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
char *ca_name;
|
|
uint64_t ca_val;
|
|
} hwcfuncs_attr_t; /* matches cpc_attr_t */
|
|
|
|
void * hwcfuncs_parse_attrs (const char *countername,
|
|
hwcfuncs_attr_t attrs[], unsigned max_attrs,
|
|
uint_t *pnum_attrs, char **errstring);
|
|
/* Extract the attribute fields from <countername>.
|
|
Input:
|
|
<countername>: string whose format is
|
|
[+]<ctrname>[~attributes...][/<regno>][,...]
|
|
<attrs>: array of attributes to be returned
|
|
<max_attrs>: number of elements in <attrs>
|
|
<pnum_attrs>: if not NULL, will return how many attrs were found.
|
|
<errstring>: pointer to a buffer for storing error info, or NULL.
|
|
Return: upon success, a pointer to an allocated copy of <countername>, or
|
|
NULL if there's a failure. (A copy is made in order to provide storage
|
|
for the ca_name fields in the <attrs> array.)
|
|
|
|
The pointer should be freed when <attrs> is no longer in use.
|
|
<attrs> will be filled in data from countername.
|
|
<pnum_attrs> will have the number of elements in <attrs>. May be
|
|
non-zero even if return value indicates an error.
|
|
<errstring> NULL if no error, otherwise, a malloc'd GTXT string.
|
|
*/
|
|
|
|
extern int hwcfuncs_bind_descriptor (const char *defstring);
|
|
/* Bind counters to resources.
|
|
Input:
|
|
<defstring>: string whose format is
|
|
:%s:%s:0x%x:%d:%d,0x%x[:%s...repeat for each ctr]
|
|
where the fields are:
|
|
:<userName>:<internalCtr>:<register>:<timeoutVal>:<tag>:<memop>
|
|
Return: 0 if successful
|
|
HWCFUNCS_ERROR_HWCINIT if resources unavailable
|
|
HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
|
|
*/
|
|
|
|
extern int hwcfuncs_bind_hwcentry (const Hwcentry *entries[],
|
|
unsigned numctrs);
|
|
/* Bind counters to resources.
|
|
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
|
|
*/
|
|
|
|
extern int hwcfuncs_assign_regnos (Hwcentry *entries[], unsigned numctrs);
|
|
/* Assign entries[]->reg_num values as needed by platform
|
|
Note: modifies <entries> by supplying a regno to each counter
|
|
Input:
|
|
<entries>: array of counters
|
|
<numctrs>: number of items in <entries>
|
|
Output:
|
|
<entries>: array of counters is modified
|
|
Return: 0 if successful
|
|
HWCFUNCS_ERROR_HWCINIT if resources unavailable
|
|
HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
|
|
*/
|
|
|
|
extern int regno_is_valid (const Hwcentry *pctr, regno_t regno);
|
|
/* return 1 if <regno> is in Hwcentry's list
|
|
Input:
|
|
<pctr>: counter definition, reg_list[] should be initialized
|
|
<regno>: register to check
|
|
Return: 1 if <regno> is in Hwcentry's list, 0 otherwise
|
|
*/
|
|
|
|
extern Hwcentry **hwcfuncs_get_ctrs (unsigned *defcnt);
|
|
/* Get descriptions of the currently bound counters.
|
|
Input:
|
|
<defcnt>: if not NULL, returns number of counter definitions.
|
|
Return:
|
|
table of counter definition pointers
|
|
*/
|
|
|
|
extern char *hwcfuncs_errmsg_get (char * buf, size_t bufsize,
|
|
int enable_capture);
|
|
/* Gets a recent HWC error message.
|
|
To clear previous error messages and insure error message is enabled,
|
|
call hwcfuncs_errmsg_get(NULL,0,1).
|
|
Once enabled, one error is stored in an internal buffer. A call to this
|
|
function will clear the buffer and allow a new message to be captured.
|
|
Note: Not MT-safe - don't enable this feature in an MT environment.
|
|
Input:
|
|
<buf>: pointer to buffer or NULL.
|
|
<bufsize>: size of <buf>
|
|
<enable_capture>: 0 - disable buffering, 1 - enable buffering.
|
|
Return: error string or an empty string.
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* ! __HWCFUNCS_H */
|