1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
/* 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 <string.h>
#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(<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);
/* Initiate callbacks with all available HWC names and 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
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);
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
|