aboutsummaryrefslogtreecommitdiff
blob: 739bc4eaf6846cc4df92ec89140d84448af274da (plain)
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
/* 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.  */

#ifndef _HWCENTRY_H
#define _HWCENTRY_H

#ifndef LIBCOLLECTOR_SRC /* not running in libcollector */
#include <stdio.h>  /* FILE */
#endif  /* --- LIBCOLLECTOR_SRC --- */
#include <stdlib.h> /* size_t */
#include "hwc_cpus.h"
#include "gp-time.h"

#ifdef __cplusplus
extern "C"
{
#endif

  /* ABS backtrack types */
  typedef enum
  {
    /* !! Lowest 2 bits are used to indicate load and store, respectively !! */
    /* Example: On SPARC, backtrack.c did this: if (ABS_memop & inst_type) ... */
    ABST_NONE               = 0x0,
    ABST_LOAD               = 0x1,
    ABST_STORE              = 0x2,
    ABST_LDST               = 0x3,
    ABST_COUNT              = 0x4,
    ABST_US_DTLBM           = 0xF,
    ABST_NOPC               = 0x100,
    ABST_CLKDS              = 0x103,     // Obsolete
    ABST_EXACT              = 0x203,
    ABST_LDST_SPARC64       = 0x303,
    ABST_EXACT_PEBS_PLUS1   = 0x403
    /* full description below... */
  } ABST_type;

#define ABST_PLUS_BY_DEFAULT(n) ((n)==ABST_EXACT || (n)==ABST_EXACT_PEBS_PLUS1)
#define ABST_BACKTRACK_ENABLED(n) ((n)!=ABST_NONE && (n)!=ABST_NOPC)
#define ABST_MEMSPACE_ENABLED(n)  ((n)!=ABST_NONE && (n)!=ABST_NOPC && (n)!=ABST_COUNT)

  /* ABS determines the type of backtracking available for a particular metric.
   * Backtracking is enabled with the "+" in "-h +<countername>...".
   *
   * When Backtracking is not possible:
   *
   *  ABST_NONE=0:     Either the user did not specify "+", or backtracking
   *                   is not applicable to the metric, for example:
   *                     clk cycles,
   *                     instruct counts (dispatch + branch + prefetch),
   *                     i$,
   *                     FP ops
   *  ABST_NOPC=0x100  Used for non-program-related external events, for example:
   *                     system interface events,
   *                     memory controller counters
   *                   Of all ABST_type options, only ABST_NOPC prevents hwprofile.c
   *                     from recording PC/stack information.
   *
   * When backtracking is allowed:
   *
   *  ABST_LOAD=1:     data read events, used with metrics like:
   *                     D$, E$, P$ read misses and hits.
   *                     [DC+EC+PC]_rd*, Re_*_miss*,
   *                     EC_snoop_cb(?)
   *  ABST_STORE=2:    data write events, used with metrics like:
   *                     D$ writes and write related misses
   *                     DC_wr/wr-miss, EC_wb, WC=writecache, Rstall_storeQ
   *                     [EC+PC=pcache]_snoop_inv(?), WC_snoop_cb(?),
   *  ABST_LDST=3:     data reads/writes, used with metrics like:
   *                     E$ references, misses.
   *  ABST_COUNT=4:    dedicated assembly instruction: '%hi(0xfc000)'
   *                     See SW_count_n metric on sparc.
   *  ABST_US_DTLBM=0xF: for load-store on Sparc -- seems to be used only
   *                     for "unskidded DTLB_miss" with DTLB_miss metric.
   *                     Checks two adjacent instructions for Data access.
   *  ABST_CLKDS=0x103: data reads/writes, used with Clock-based Dataspace
   *                     profiling.  Ultrasparc T2 and earlier.
   *  ABST_EXACT=0x203: data reads/writes, precise trap with no skid
   *  ABST_LDST_SPARC64=0x303: Fujitsu SPARC64 load/store
   *  ABST_EXACT_PEBS_PLUS1=0x403: data reads/writes, precise sampling with 1 instr. skid
   */

  /* Hwcentry - structure for defining a counter.
   *   Some fields have different usage when returned from
   *   hwc_lookup(), hwc_post_lookup(), or hwc_scan_*().
   *   Each function will describe its return values in more detail.
   */
  typedef struct
  {
    char *name;         /* user HWC specification */
    char *int_name;     /* internal HWC specification */
    regno_t reg_num;    /* register in CPU, aka picnum, or REGNO_ANY */
    char *metric;       /* descriptive name, for well-known counters only */
    volatile int val;   /* default or actual overflow value */
    int timecvt;        /* multiplier to convert metric to time, 0 if N/A */
    ABST_type memop;    /* type of backtracking allowed */
    char *short_desc;   /* optional one-liner description, or NULL */
    int type;           /* Type of perf_event_attr */
    long long config;   /* perf_event_type -specific configuration */
    /* the fields above this line are expected, in order, by the tables in hwctable.c */
    /* ================================================== */
    /* the fields below this line are more flexible */
    int sort_order;     /* "tag" to associate experiment record with HWC def */
    regno_t *reg_list;  /* if not NULL, legal values for <reg_num> field above */
    /* Note: reg_list will be terminated by REGNO_ANY */
    /* Max size of array is MAX_PICS */
    hrtime_t min_time;  /* target minimum time between overflow events.  0 is off.  See HWCTIME_* macros */
    hrtime_t min_time_default; /* if min_time==HWCTIME_AUTO, use this value instead.  0 is off. */
    int ref_val;    /* if min_time==HWCTIME_AUTO, use this time.  0 is off. */
    int lval, hval; /* temporary to allow DBX to build until dbx glue.cc fixed */
  } Hwcentry;

  // Hwcentry.min_time canned values
#define HWCTIME_TBD ((hrtime_t)( -1LL)) /* self-adjusting enabled but nsecs not yet selected */
#define HWCTIME_HI  (   1 * 1000 * 1000LL ) /*   1 msec represented in nsecs */
#define HWCTIME_ON  (  10 * 1000 * 1000LL ) /*  10 msec represented in nsecs */
#define HWCTIME_LO  ( 100 * 1000 * 1000LL ) /* 100 msec represented in nsecs */

#define HWC_VAL_HI(refVal) (((refVal)/10) + 1)
#define HWC_VAL_ON(refVal) (refVal)
#define HWC_VAL_LO(refVal) (((refVal)*10)/100*100 + 1)  // zero's out lower digits, add 1
#define HWC_VAL_CUSTOM(refVal, targetNanoSec) ((double)(refVal)*(targetNanoSec)/HWCTIME_ON)

#define HWCENTRY_USES_SAMPLING(h)   ((h)->memop==ABST_EXACT_PEBS_PLUS1)

  extern int hwc_lookup (int forKernel, hrtime_t min_time_default,
			 const char *uname, Hwcentry *list[], unsigned listsz,
			 char **emsg, char **wmsg);
  /* Parses counter cmdline string.  Returns counter definitions.
   * Input:
   *   <forKernel> lookup using which table: 0-collect or 1-er_kernel
   *   <min_time_default> minimum nseconds between events if Hwcentry.min_time == HWCTIME_TBD.  0 to disable.
   *   <uname> command line HWC definition of format:
   *           <ctr_def>...[{','|(whitespace)}<ctr_n_def>] where
   *           <ctr_def> == [+]<ctr>[/<reg#>][,<interval>]
   *   <list> array of pointers to store counter definitions
   *   <listsz> number of elements in <list>
   * Returns:
   *   Success:
   *     Returns number of valid counters in <list> and <list>'s elements
   *     will be initialized as follows:
   *
   *     <list[]->name>:
   *       Copy of the <uname> with the following modification:
   *         if backtracking is not supported, the + will be removed.
   *     <list[]->int_name>:
   *       For well-known and convenience ctrs, the internal HWC specification,
   *         e.g. BSQ_cache_reference~emask=0x0100.
   *       For raw ctrs, this will be a copy of <name>.
   *     <list[]->reg_num>:
   *       Register number if specified by user or table, REGNO_ANY otherwise.
   *     <list[]->metric>:
   *       For well-known counters, descriptive name, e.g. "D$ Read Misses".
   *       NULL otherwise.
   *     <list[]->val>:
   *       Overflow value selected by user, default value otherwise.
   *     <list[]->timecvt>:
   *       Value from tables.
   *     <list[]->memop>:
   *       If + is selected and backtracking is allowed, value from table.
   *       ABST_NONE or ABST_NOPC otherwise.
   *
   *     It is the responsibility of the caller to free 'name' and 'int_name'.
   *     'metric' is a static string and shouldn't be freed.
   *     'emsg' will point to NULL
   *
   *   Failure:
   *     Frees all allocated elements.
   *     emsg will point to a string with an error message to print
   *     returns -1
   */

  extern char *hwc_validate_ctrs (int forKernel, Hwcentry *list[], unsigned listsz);
  /* Validates that the vector of specified HW counters can be loaded (more-or-less)
   *   Some invalid combinations, especially on Linux will not be detected
   */

  extern int hwc_get_cpc_cpuver ();
  /* Return the cpc_cpuver for this system.  Other possible values:
   *   CPUVER_GENERIC=0,           CPU could not be determined, but HWCs are ok.
   *   CPUVER_UNDEFINED=-1,        HWCs are not available.
   */

  extern char *hwc_get_docref (char *buf, size_t buflen);
  /* Return a CPU HWC document reference, or NULL. */

  // TBR
  extern char *hwc_get_default_cntrs ();
  /* Return a default HW counter string; may be NULL, or zero-length */
  /* NULL means none is defined in the table; or zero-length means string defined could not be loaded */

  extern char *hwc_get_default_cntrs2 (int forKernel, int style);
  /* like hwc_get_default_cntrs() for style==1 */
  /* but allows other styles of formatting as well */
  /* deprecate and eventually remove hwc_get_default_cntrs() */

  extern char *hwc_get_orig_default_cntrs ();
  /* Get the default HW counter string as set in the table */
  /* NULL means none is defined in the table */

  extern void hwc_update_val (Hwcentry *ctr);
  /* Check time-based intervals and update Hwcentry.val as needed */

  extern char *hwc_get_cpuname (char *buf, size_t buflen);
  /* Return the cpc cpu name for this system, or NULL. */

  extern unsigned hwc_get_max_regs ();
  /* Return number of counters registers for this system. */

  extern unsigned hwc_get_max_concurrent (int forKernel);
  /* Return the max number of simultaneous counters for this system. */

  extern char **hwc_get_attrs (int forKernel);
  /* Return:
   *   Array of attributes (strings) supported by this system.
   *   Last element in array is null.
   *   Array and its elements should NOT be freed by the caller.
   */

  extern unsigned hwc_scan_attrs (void (*action)(const char *attr,
						 const char *desc));
  /* Scan the HW counter attributes, and call function for each attribute.
   * Input:
   *   <action>:
   *     If NULL, no action is performed, but count is still returned.
   *     Otherwise called for each type of attributes, or if none exist,
   *       called once with NULL parameter.
   * Return: count of times <action> would have been called w/ non-NULL data.
   */

  extern Hwcentry *hwc_post_lookup (Hwcentry * pret_ctr, char *uname,
				    char * int_name, int cpc_cpuver);
  /* When post-processing a run, look up a Hwcentry for given type of system.
   * Input:
   *   <pret_ctr>: storage for counter definition
   *   <uname>: well-known name, convenience name, or complete HWC defintion.
   *   <int_name>: Hwcentry->int_name or NULL for don't care
   *   <cpc_cpuver>: version of cpu used for experiment.
   * Return:
   *   <pret_ctr>'s elements set as follows:
   *
   *     <pret_ctr->name>:
   *       Copy of <uname> with the following modifications:
   *         1) + and /<regnum> will be stripped off
   *         2) attributes will be sorted and values will shown in hex.
   *     <pret_ctr->int_name>:
   *       For well-known/convenience counters, the internal HWC specification
   *         from the table, e.g. BSQ_cache_reference~emask=0x0100.
   *       Otherwise, a copy of <uname>.
   *     <pret_ctr->reg_num>:
   *       Register number if specified by user or table,
   *       REGNO_ANY othewise.
   *     <pret_ctr->metric>:
   *       For well-known counters, descriptive name, e.g. "D$ Read Misses".
   *       NULL otherwise.
   *     <pret_ctr->timecvt>:
   *       For well-known/convenience/hidden counters, value from table.
   *       0 otherwise.
   *     <pret_ctr->memop>:
   *       For well-known/convenience/hidden counters, value from table.
   *       ABST_NONE otherwise.
   *     <pret_ctr->sort_order>:
   *       Set to 0.
   *
   *     It is the responsibility of the caller to free 'name' and 'int_name'.
   *     'metric' is a static string and shouldn't be freed.
   */

  extern Hwcentry **hwc_get_std_ctrs (int forKernel);
  /* Return:
   *   Array of well-known counters supported by this system.
   *   Last element in array will be NULL.
   *   Array and its elements should NOT be freed by the caller.
   */

  extern unsigned hwc_scan_std_ctrs (void (*action)(const Hwcentry *));
  /* Call <action> for each well-known counter.
   * Input:
   *   <action>:
   *     If NULL, no action is performed, but count is still returned.
   *     Otherwise called for each type of attributes, or if none exist,
   *       called once with NULL parameter.
   * Return:
   *   Count of times <action> would have been called w/ non-NULL data.
   *   If <action> is not NULL, Hwcentry fields will be set as follows:
   *     <ctr->name>:
   *       HWC alias name, e.g. dcrm.
   *     <ctr->int_name>:
   *       The internal HWC specification, e.g. BSQ_cache_reference~emask=0x0100.
   *     <ctr->reg_num>:
   *       Register number if specified by the table, REGNO_ANY otherwise.
   *     <ctr->metric>:
   *       Descriptive name, e.g. "D$ Read Misses".
   *     <ctr->lval>:
   *       Low-resolution overflow value.
   *     <ctr->val>:
   *       Default overflow value.
   *     <ctr->hval>:
   *       High-resolution overflow value.
   *     <ctr->timecvt>:
   *       multiplier to convert metric to time, 0 otherwise.
   *     <ctr->memop>:
   *       ABST_* type for this counter.
   *     <ctr->reg_list>:
   *       Array of legal <reg_num> values.  Terminated by REGNO_ANY.
   *
   *     Note: All fields point to static data, none should be freed.
   */

  extern Hwcentry **hwc_get_raw_ctrs (int forKernel);
  /* Return:
   *   Table of raw (not well-known) counters supported by this system.
   *   Last element in array will be NULL.
   *   Table and its elements should NOT be freed by the caller.
   */

  extern unsigned hwc_scan_raw_ctrs (void (*action)(const Hwcentry *));
  /* Call <action> for each raw counter.
   * Input:
   *   <action>:
   *     If NULL, no action is performed, but count is still returned.
   *     Otherwise called for each type of attributes, or if none exist,
   *       called once with NULL parameter.
   * Return:
   *   Count of times <action> would have been called w/ non-NULL data.
   *   If <action> is not NULL, Hwcentry fields will be set as follows:
   *     <ctr->name>:
   *       HWC raw name without attributes, e.g. BSQ_cache_reference.
   *     <ctr->int_name>:
   *       NULL.
   *     <ctr->metric>:
   *       NULL.
   *     The remainder of the fields are the same as for
   *       hwc_scan_std_ctrs().
   *
   *     Note: All fields point to static data, none should be freed.
   */

  extern void
  hwc_usage (int forKernel, const char *cmd, const char *dataspace_msg);
  /* Print an i18n'd description of "-h" usage, used by collect and er_kernel.
   */

  extern void hwc_usage_f (int forKernel, FILE *f, const char *cmd,
			   const char *dataspace_msg, int show_syntax,
			   int show_short_desc);
  /* Print an i18n'd description of "-h" usage to a FILE.  Used by GUI. */

  extern char *hwc_rate_string (const Hwcentry *pctr, int force_numeric_format);
  /* Returns {"on"|"hi"|"lo"|""|<value>}.  Return value must be freed by caller. */

  extern char *hwc_i18n_metric (const Hwcentry *ctr);
  /* Get a basic lable for a counter, properly i18n'd.
   *   Note: NOT MT SAFE.
   * Examples:
   *   CPU Cycles
   *   DC_rd Events
   * Pseudocode:
   *   if(ctr->metric != NULL) {
   *	    sprintf(metricbuf, PTXT(ctr->metric) );
   *   } else if (ctr->name != NULL) {
   *	    sprintf(metricbuf, GTXT("%s Events"), ctr->name );
   *   } else if (ctr->int_name != NULL) {
   *	    sprintf(metricbuf, GTXT("%s Events"), ctr->int_name );
   *   }
   * Return: pointer to a buffer containing the above description.
   */

  extern char *hwc_hwcentry_string (char *buf, size_t buflen, const Hwcentry *ctr);
  /* Get a i18n'd description of a HW counter's options.
   *   Examples of well-known counters:
   *     cycles[/{0|1}],9999991 ('CPU Cycles', alias for Cycle_cnt; CPU-cycles)
   *     dcr[/0],1000003 ('D$ Read Refs', alias for DC_rd; load events)
   *   Examples of raw counters:
   *     Cycle_cnt[/{0|1}],1000003 (CPU-cycles)
   *     DC_rd[/0],1000003 (load events)
   * Return: <buf>, filled in.
   */

  extern char *hwc_hwcentry_specd_string (char *buf, size_t buflen, const Hwcentry *ctr);
  /* Get a i18n'd description of a HW counter's specific configuration.
   *   Examples of well-known counters:
   *     cycles,9999991 ('CPU Cycles')
   *     +dcr/0,1000003 ('D$ Read Refs')
   *   Examples of raw counters:
   *     Cycle_cnt,1000003
   *     +DC_rd/0,1000003
   * Return: <buf>, filled in.
   */

  extern const char *hwc_memop_string (ABST_type memop);
  /* Get a i18n'd description of a variable of type ABST_type.
   * Return: pointer to static string.
   */

#ifdef __cplusplus
}
#endif

#endif