HPCToolkit
perfmon-util.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // --------------------------------------------------------------------------
6 // Part of HPCToolkit (hpctoolkit.org)
7 //
8 // Information about sources of support for research and development of
9 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
10 // --------------------------------------------------------------------------
11 //
12 // Copyright ((c)) 2002-2019, Rice University
13 // All rights reserved.
14 //
15 // Redistribution and use in source and binary forms, with or without
16 // modification, are permitted provided that the following conditions are
17 // met:
18 //
19 // * Redistributions of source code must retain the above copyright
20 // notice, this list of conditions and the following disclaimer.
21 //
22 // * Redistributions in binary form must reproduce the above copyright
23 // notice, this list of conditions and the following disclaimer in the
24 // documentation and/or other materials provided with the distribution.
25 //
26 // * Neither the name of Rice University (RICE) nor the names of its
27 // contributors may be used to endorse or promote products derived from
28 // this software without specific prior written permission.
29 //
30 // This software is provided by RICE and contributors "as is" and any
31 // express or implied warranties, including, but not limited to, the
32 // implied warranties of merchantability and fitness for a particular
33 // purpose are disclaimed. In no event shall RICE or contributors be
34 // liable for any direct, indirect, incidental, special, exemplary, or
35 // consequential damages (including, but not limited to, procurement of
36 // substitute goods or services; loss of use, data, or profits; or
37 // business interruption) however caused and on any theory of liability,
38 // whether in contract, strict liability, or tort (including negligence
39 // or otherwise) arising in any way out of the use of this software, even
40 // if advised of the possibility of such damage.
41 //
42 // ******************************************************* EndRiceCopyright *
43 
44 //
45 // Utility interface for perfmon
46 //
47 
48 
49 
50 /******************************************************************************
51  * system includes
52  *****************************************************************************/
53 
54 #include <sys/types.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <inttypes.h>
58 #include <stdarg.h>
59 #include <errno.h>
60 #include <unistd.h>
61 #include <string.h>
62 #include <regex.h>
63 
64 /******************************************************************************
65  * linux specific headers
66  *****************************************************************************/
67 #include <linux/perf_event.h>
68 
69 /******************************************************************************
70  * hpcrun includes
71  *****************************************************************************/
72 
74 #include "perf-util.h" // u64, u32 and perf_mmap_data_t
75 #include "perf_event_open.h"
76 #include "sample-sources/display.h"
77 
78 /******************************************************************************
79  * perfmon
80  *****************************************************************************/
81 #include <perfmon/pfmlib.h>
82 
83 
84 //******************************************************************************
85 // data structure
86 //******************************************************************************
87 
88 // taken from perfmon/pfmlib_perf_event.h
89 // we don't want to include this file because it requires perfmon's perf_event.h
90 // which is not compatible with the official perf_event.h
91 /*
92  * use with PFM_OS_PERF, PFM_OS_PERF_EXT for pfm_get_os_event_encoding()
93  */
94 typedef struct {
95  struct perf_event_attr *attr; /* in/out: perf_event struct pointer */
96  char **fstr; /* out/in: fully qualified event string */
97  size_t size; /* sizeof struct */
98  int idx; /* out: opaque event identifier */
99  int cpu; /* out: cpu to program, -1 = not set */
100  int flags; /* out: perf_event_open() flags */
101  int pad0; /* explicit 64-bit mode padding */
103 
104 
105 
106 //******************************************************************************
107 // Constants
108 //******************************************************************************
109 
110 #define MAX_EVENT_NAME_CHARS 256
111 #define MAX_EVENT_DESC_CHARS 4096
112 
113 #define EVENT_IS_PROFILABLE 0
114 #define EVENT_MAY_NOT_PROFILABLE 1
115 #define EVENT_FATAL_ERROR -1
116 
117 //******************************************************************************
118 // forward declarations
119 //******************************************************************************
120 
121 int
122 pfmu_getEventType(const char *eventname, u64 *code, u64 *type);
123 
124 //******************************************************************************
125 // local operations
126 //******************************************************************************
127 
128 
129 
130 static int
132 {
133  char *p;
134  return (p = strchr(s, ':')) && *(p+1) == ':';
135 }
136 
137 
138 /*
139  * test if the kernel can create the given event
140  * @param code: config, @type: type of event
141  * @return: file descriptor if successful, -1 otherwise
142  * caller needs to check errno for the root cause
143  */
144 static int
145 create_event(uint64_t code, uint64_t type)
146 {
147  struct perf_event_attr event_attr;
148  memset(&event_attr, 0, sizeof(event_attr));
149  event_attr.disabled = 1;
150 
151  event_attr.size = sizeof(struct perf_event_attr);
152  event_attr.type = type;
153  event_attr.config = code;
154 
155  // do not check if the event can run with kernel access
156  event_attr.exclude_kernel = 1;
157  event_attr.exclude_hv = 1;
158  event_attr.exclude_idle = 1;
159 
160  int fd = perf_event_open(&event_attr, 0, -1, -1, 0);
161  if (fd == -1) {
162  return -1;
163  }
164  close(fd);
165  return fd;
166 }
167 
168 /******************
169  * test a pmu if it's profilable or not
170  * @return 0 if it's fine. 1 otherwise
171  ******************/
172 static int
173 test_pmu(char *evname)
174 {
175  u64 code, type;
176 
177  if (pfmu_getEventType(evname, &code, &type) >0 ) {
178  if (create_event(code, type)>=0) {
179  return EVENT_IS_PROFILABLE;
180  }
181  }
183 }
184 
185 /******************
186  * show the information of a given pmu event
187  * the display will be formatted by display library
188  *
189  * @param: perf event information
190  * @return:
191  * 0 if profilable,
192  * -1 if there's a fatal error
193  * 1 otherwise
194  ******************/
195 static int
196 show_event_info(pfm_event_info_t *info)
197 {
198  pfm_event_attr_info_t ainfo;
199  pfm_pmu_info_t pinfo;
200  int i, ret;
201 
202  memset(&ainfo, 0, sizeof(ainfo));
203  memset(&pinfo, 0, sizeof(pinfo));
204 
205  pinfo.size = sizeof(pinfo);
206  ainfo.size = sizeof(ainfo);
207 
208  ret = pfm_get_pmu_info(info->pmu, &pinfo);
209  if (ret) {
210  EMSG( "cannot get pmu info: %s", pfm_strerror(ret));
211  return EVENT_FATAL_ERROR;
212  }
213 
214  char buffer[MAX_EVENT_NAME_CHARS];
215  char buffer_desc[MAX_EVENT_DESC_CHARS];
216 
217  sprintf(buffer, "%s::%s", pinfo.name, info->name);
218  int profilable = test_pmu(buffer);
219 
220  display_line_single(stdout);
221 
222  if (profilable == EVENT_IS_PROFILABLE) {
223  display_event_info(stdout, buffer, info->desc);
224  } else {
225  sprintf(buffer_desc, "%s (*)", info->desc);
226  display_event_info(stdout, buffer, buffer_desc);
227  }
228 
229  pfm_for_each_event_attr(i, info) {
230  ret = pfm_get_event_attr_info(info->idx, i, PFM_OS_NONE, &ainfo);
231  if (ret == PFM_SUCCESS)
232  {
233  memset(buffer, 0, MAX_EVENT_NAME_CHARS);
234  sprintf(buffer, "%s::%s:%s", pinfo.name, info->name, ainfo.name);
235 
236  if (test_pmu(buffer) == 0) {
237  display_event_info(stdout, buffer, ainfo.desc);
238  continue;
239  }
240 
241  // the counter may not be profilable. Perhaps requires more attributes/masks
242  // or higher user privilege (like super user)
243  // add a sign to users so they know the event may not be profilable
244  sprintf(buffer_desc, "%s (*)", ainfo.desc);
245  display_event_info(stdout, buffer, buffer_desc);
246 
247  profilable = EVENT_MAY_NOT_PROFILABLE;
248  }
249  }
250  return profilable;
251 }
252 
253 /******************
254  * show the list of supported events
255  ******************/
256 static int
257 show_info(char *event )
258 {
259  pfm_pmu_info_t pinfo;
260  pfm_event_info_t info;
261  int i, j, ret, match = 0, pname;
262  int profilable = 0;
263 
264  memset(&pinfo, 0, sizeof(pinfo));
265  memset(&info, 0, sizeof(info));
266 
267  pinfo.size = sizeof(pinfo);
268  info.size = sizeof(info);
269 
270  pname = event_has_pname(event);
271 
272  /*
273  * scan all supported events, incl. those
274  * from undetected PMU models
275  */
276  pfm_for_all_pmus(j) {
277 
278  ret = pfm_get_pmu_info(j, &pinfo);
279  if (ret != PFM_SUCCESS)
280  continue;
281 
282  /* no pmu prefix, just look for detected PMU models */
283  if (!pname && !pinfo.is_present)
284  continue;
285 
286  for (i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
287  ret = pfm_get_event_info(i, PFM_OS_NONE, &info);
288  if (ret != PFM_SUCCESS)
289  EMSG( "cannot get event info: %s", pfm_strerror(ret));
290  else {
291  profilable |= show_event_info(&info);
292  match++;
293  }
294  }
295  }
296  if (profilable != EVENT_IS_PROFILABLE)
297  printf("(*) The counter may not be profilable.\n\n");
298 
299  return match;
300 }
301 
302 
303 //******************************************************************************
304 // Supported operations
305 //******************************************************************************
306 
312 int
313 pfmu_getEventAttribute(const char *eventname, struct perf_event_attr *event_attr)
314 {
316  char *fqstr = NULL;
317 
318  arg.fstr = &fqstr;
319  arg.size = sizeof(pfm_perf_encode_arg_t);
320  struct perf_event_attr attr;
321  memset(&attr, 0, sizeof(struct perf_event_attr));
322 
323  arg.attr = &attr;
324  int ret = pfm_get_os_event_encoding(eventname, PFM_PLM0|PFM_PLM3, PFM_OS_PERF_EVENT_EXT, &arg);
325 
326  if (ret == PFM_SUCCESS) {
327  memcpy(event_attr, arg.attr, sizeof(struct perf_event_attr));
328  return 1;
329  }
330  return -1;
331 }
332 
333 // return 0 or positive if the event exists, -1 otherwise
334 // if the event exist, code and type are the code and type of the event
335 int
336 pfmu_getEventType(const char *eventname, u64 *code, u64 *type)
337 {
339  char *fqstr = NULL;
340 
341  arg.fstr = &fqstr;
342  arg.size = sizeof(pfm_perf_encode_arg_t);
343  struct perf_event_attr attr;
344  memset(&attr, 0, sizeof(struct perf_event_attr));
345 
346  arg.attr = &attr;
347  int ret = pfm_get_os_event_encoding(eventname, PFM_PLM0|PFM_PLM3, PFM_OS_PERF_EVENT, &arg);
348 
349  if (ret == PFM_SUCCESS) {
350  *type = arg.attr->type;
351  *code = arg.attr->config;
352  return 1;
353  }
354  return -1;
355 }
356 
357 
358 /*
359  * interface to check if an event is "supported"
360  * "supported" here means, it matches with the perfmon PMU event
361  *
362  * return 0 or positive if the event exists, -1 otherwise
363  */
364 int
365 pfmu_isSupported(const char *eventname)
366 {
367  u64 eventcode, eventtype;
368  return pfmu_getEventType(eventname, &eventcode, &eventtype);
369 }
370 
371 
376 int
378 {
379  int ret;
380 #if 0
381  // need to comment this block because it the setenv interferes with
382  // HPCRUN_EVENT_LIST if we start this before the "support_events" step
383 
384  // to allow encoding of events from non detected PMU models
385  ret = setenv("LIBPFM_ENCODE_INACTIVE", "1", 1);
386  if (ret != 0)
387  EMSG( "cannot force inactive encoding");
388 #endif
389 
390  // pfm_initialize is idempotent, so it is not a problem if
391  // another library (e.g., PAPI) also calls this.
392  ret = pfm_initialize();
393 
394  if (ret != PFM_SUCCESS) {
395  EMSG( "libpfm: cannot initialize: %s", pfm_strerror(ret));
396  return -1;
397  }
398 
399  return 1;
400 }
401 
402 void
404 {
405  pfm_terminate();
406 }
407 
408 /*
409  * interface function to print the list of supported PMUs
410  */
411 int
413 {
414  static char *argv_all = ".*";
415 
416  int total_supported_events = 0;
417  int total_available_events = 0;
418  int i, ret;
419  pfm_pmu_info_t pinfo;
420 
421  memset(&pinfo, 0, sizeof(pinfo));
422  pinfo.size = sizeof(pinfo);
423 
424  static const char *pmu_types[]={
425  "unknown type",
426  "core",
427  "uncore",
428  "OS generic",
429  };
430 
431  printf("Detected PMU models:\n");
432 
433  pfm_for_all_pmus(i) {
434  ret = pfm_get_pmu_info(i, &pinfo);
435  if (ret != PFM_SUCCESS)
436  continue;
437 
438  if (pinfo.is_present) {
439  if (pinfo.type >= PFM_PMU_TYPE_MAX)
440  pinfo.type = PFM_PMU_TYPE_UNKNOWN;
441 
442  printf("\t[%d, %s, \"%s\", %d events, %d max encoding, %d counters, %s PMU]\n",
443  i,
444  pinfo.name,
445  pinfo.desc,
446  pinfo.nevents,
447  pinfo.max_encoding,
448  pinfo.num_cntrs + pinfo.num_fixed_cntrs,
449  pmu_types[pinfo.type]);
450 
451  total_supported_events += pinfo.nevents;
452  }
453  total_available_events += pinfo.nevents;
454  }
455  printf("Total events: %d available, %d supported\n", total_available_events, total_supported_events);
456 
457  display_line_single(stdout);
458 
459  show_info(argv_all);
460 
461  return 0;
462 }
463 
static int event_has_pname(char *s)
Definition: perfmon-util.c:131
static int show_event_info(pfm_event_info_t *info)
Definition: perfmon-util.c:196
int pfmu_isSupported(const char *eventname)
Definition: perfmon-util.c:365
#define MAX_EVENT_DESC_CHARS
Definition: perfmon-util.c:111
int pfmu_showEventList()
Definition: perfmon-util.c:412
#define EVENT_FATAL_ERROR
Definition: perfmon-util.c:115
#define MAX_EVENT_NAME_CHARS
Definition: perfmon-util.c:110
long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags)
struct perf_event_attr * attr
Definition: perfmon-util.c:95
void display_event_info(FILE *output, const char *event, const char *desc)
Definition: display.c:142
int pfmu_getEventType(const char *eventname, u64 *code, u64 *type)
Definition: perfmon-util.c:336
#define EVENT_IS_PROFILABLE
Definition: perfmon-util.c:113
#define EMSG
Definition: messages.h:70
static int show_info(char *event)
Definition: perfmon-util.c:257
void display_line_single(FILE *output)
Definition: display.c:115
void pfmu_fini()
Definition: perfmon-util.c:403
int pfmu_getEventAttribute(const char *eventname, struct perf_event_attr *event_attr)
Definition: perfmon-util.c:313
__u64 u64
static int create_event(uint64_t code, uint64_t type)
Definition: perfmon-util.c:145
#define NULL
Definition: ElfHelper.cpp:85
static int test_pmu(char *evname)
Definition: perfmon-util.c:173
int pfmu_init()
Definition: perfmon-util.c:377
#define EVENT_MAY_NOT_PROFILABLE
Definition: perfmon-util.c:114