HPCToolkit
perf_skid.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 // includes
46 // -----------------------------------------------------
47 
48 #include <stdlib.h>
49 #include <limits.h>
50 #include <ctype.h>
51 
52 #ifdef _PERF_SKID_DEBUG_
53 #define _GNU_SOURCE /* See feature_test_macros(7) */
54 #endif
55 
56 #include <string.h>
57 
58 #include <unistd.h>
59 #include <sys/syscall.h> /* For SYS_xxx definitions */
60 
61 #include <linux/perf_event.h>
62 
63 #include "perf_constants.h"
64 #include "perf_skid.h"
65 #include "perf_event_open.h"
66 
67 // -----------------------------------------------------
68 // precise ip / skid options
69 // -----------------------------------------------------
70 
71 // Possible value of precise ip:
72 // 0 SAMPLE_IP can have arbitrary skid.
73 // 1 SAMPLE_IP must have constant skid.
74 // 2 SAMPLE_IP requested to have 0 skid.
75 // 3 SAMPLE_IP must have 0 skid.
76 // 4 Detect automatically to have the most precise possible (default)
77 #define HPCRUN_OPTION_PRECISE_IP "HPCRUN_PRECISE_IP"
78 
79 #define PRECISE_IP_CHAR_MODIFIER 'p'
80 
81 #define PRECISE_IP_SUFFIX ":p"
82 #define PRECISE_IP_MAX_SUFFIX ":P"
83 
84 #define DELIMITER_HOWOFTEN '@'
85 
86 // -----------------------------------------------------
87 // constants
88 // -----------------------------------------------------
89 
90 // ordered in increasing precision
91 const int perf_skid_precision[] = {
96 };
97 
98 const int perf_skid_flavors = sizeof(perf_skid_precision)/sizeof(int);
99 
100 // -----------------------------------------------------
101 // private methods
102 // -----------------------------------------------------
103 
104 /*
105  * get int long value of variable environment.
106  * If the variable is not set, return the default value
107  */
108 static long
109 getEnvLong(const char *env_var, long default_value)
110 {
111  const char *str_val= getenv(env_var);
112 
113  if (str_val) {
114  char *end_ptr;
115  long val = strtol( str_val, &end_ptr, 10 );
116  if ( end_ptr != env_var && (val < LONG_MAX && val > LONG_MIN) ) {
117  return val;
118  }
119  }
120  // invalid value
121  return default_value;
122 }
123 
124 
125 static char*
126 strlaststr(const char* haystack, const char* needle)
127 {
128  char* loc = 0;
129  char* found = 0;
130  size_t pos = 0;
131 
132  while ((found = strstr(haystack + pos, needle)) != 0)
133  {
134  loc = found;
135  pos = (found - haystack) + 1;
136  }
137 
138  return loc;
139 }
140 
141 
142 static const char *
143 find_precise_suffix(const char *s, const char *suffix, char allowed)
144 {
145  char *ptr_att = strlaststr(s, suffix);
146  if (ptr_att) {
147  const char *end = ptr_att + strlen(suffix);
148 
149  // skip allowable characters after suffix
150  if (allowed) {
151  if (*end == allowed) end++;
152  if (*end == allowed) end++;
153  }
154 
155  // check that either
156  // (1) there is nothing left, or
157  // (2) it is followed by DELIMITER_HOWOFTEN
158  if (*end != 0 && *end != DELIMITER_HOWOFTEN) ptr_att = 0;
159  }
160  return ptr_att;
161 }
162 
163 
164 
165 //===================================================================
166 // INTERFACES
167 //===================================================================
168 
175 int
176 perf_skid_set_max_precise_ip(struct perf_event_attr *attr)
177 {
178  // start with the most restrict skid (3) then 2, 1 and 0
179  // this is specified in perf_event_open man page
180  // if there's a change in the specification, we need to change
181  // this one too (unfortunately)
182  for(int i=perf_skid_flavors-1; i>=0; i--) {
183  attr->precise_ip = perf_skid_precision[i];
184 
185  // ask sys to "create" the event
186  // it returns -1 if it fails.
187  int ret = perf_event_open(attr,
190  if (ret >= 0) {
191  close(ret);
192  // just quit when the returned value is correct
193  return attr->precise_ip;
194  }
195  }
196  return 0;
197 }
198 
199 
200 //----------------------------------------------------------
201 // find the best precise ip value in this platform
202 // @param current perf event attribute. This attribute can be
203 // updated for the default precise ip.
204 // @return the assigned precise ip
205 //----------------------------------------------------------
206 u64
207 perf_skid_get_precise_ip(struct perf_event_attr *attr)
208 {
209  // check if user wants a specific ip-precision
212  {
213  attr->precise_ip = val;
214 
215  // check the validity of the requested precision
216  // if it returns -1 we need to use our own auto-detect precision
217  int ret = perf_event_open(attr,
220  if (ret >= 0) {
221  close(ret);
222  return val;
223  }
224  }
225  // no variable is set or the value is not valid
226  // set to the most arbitrary skid to ensure it works
227  //
228  attr->precise_ip = PERF_EVENT_SKID_ARBITRARY;
229 
230  return attr->precise_ip;
231 }
232 
233 // parse the event into event_name and the type of precise_ip
234 // the name of the event excludes the precise ip suffix
235 // returns:
236 // 4 PERF_EVENT_AUTODETECT_SKID
237 // 3 PERF_EVENT_SKID_ZERO_REQUIRED
238 // 2 PERF_EVENT_SKID_ZERO_REQUESTED
239 // 1 PERF_EVENT_SKID_CONSTANT
240 // 0 PERF_EVENT_SKID_ARBITRARY
241 // -1 PERF_EVENT_SKID_ERROR
242 int
243 perf_skid_parse_event(const char *event_string, char **event_string_without_skidmarks)
244 {
245  int len_suf = strlen(PRECISE_IP_SUFFIX);
246  int len_evt = strlen(event_string);
247  int precise = 0;
248 
249  if (len_evt <= len_suf) {
250  // some events consist only of two letters (e.g,: cs)
251  // Using this event (which has two letters) is not an error,
252  // we just doesn't need to parse it.
253  *event_string_without_skidmarks = strdup(event_string);
255  }
256 
257  const char *ptr_att = find_precise_suffix(event_string, PRECISE_IP_MAX_SUFFIX, 0);
258  if (ptr_att) {
259  char buffer[1024];
260 #ifdef _PERF_SKID_DEBUG_
261  memset(buffer,1, sizeof(buffer));
262 #endif
263  memcpy(buffer, event_string, ptr_att - event_string);
264  buffer[ptr_att - event_string] = 0;
265  strcat(buffer, ptr_att + strlen(PRECISE_IP_MAX_SUFFIX));
266  *event_string_without_skidmarks = strdup(buffer);
268  }
269 
270  // continuously looking for ":p" pattern inside the event_name
271  // if an event has foo::par:peer:p it should return the last ":p"
273 
274  if (!ptr_att) {
275  *event_string_without_skidmarks = strdup(event_string);
276  } else {
277  char buffer[1024];
278 #ifdef _PERF_SKID_DEBUG_
279  memset(buffer,1, sizeof(buffer));
280 #endif
281  memcpy(buffer, event_string, ptr_att - event_string);
282  buffer[ptr_att - event_string] = 0;
283  precise++;
284 
285  const char *ptr_next = ptr_att + len_suf;
286  if (!ptr_next)
287  // shouldn't happen here
288  return precise;
289 
290  // count the number of p in :ppp
291  while (ptr_next && *ptr_next == PRECISE_IP_CHAR_MODIFIER) {
292  ptr_next++;
293  precise++;
294  }
295 
296  if (*ptr_next == DELIMITER_HOWOFTEN) {
297  // next char is period threshold or frequency
298  strcat(buffer, ptr_next);
299  } else if (*ptr_next != '\0') {
300  // the next char is not recognized
301  precise--;
302  }
303 
304  *event_string_without_skidmarks = strdup(buffer);
305  }
306 
307  return precise;
308 }
309 
310 #ifdef _PERF_SKID_DEBUG_
311 #include <stdio.h>
312 
313 #define MAX_NAME_EVENT 128
314 int
315 main (int argc, char *argv[])
316 {
317  char *ev[] = {"cycles:p", "cycles:pp", "cycles", "cycles::popo:peer",
318  "cycles::popo:oeer:ppp", "cycles::popo:peer:p", "cycles@100",
319  "cycles::popo:oeer:p@100", "cycles::popo:peer:p@f10",
320  "cycles::popo:peer:ppp@5050", "cycles::popo:peer:pp",
321  "cs:P", "cs:Pp", "cs:pppp", "cs:P@10000" };
322  int num_events = sizeof(ev)/sizeof(ev[9]);
323  int i;
324 
325  for (i=0; i<num_events; i++) {
326  char *name_event;
327  int r = perf_skid_parse_event(ev[i], &name_event);
328  printf("event: %s name: %s -> %d\n", ev[i], name_event, r);
329  }
330 }
331 
332 #endif
#define GROUP_FD
#define HPCRUN_OPTION_PRECISE_IP
Definition: perf_skid.c:77
int perf_skid_set_max_precise_ip(struct perf_event_attr *attr)
Definition: perf_skid.c:176
#define PERF_EVENT_SKID_ZERO_REQUIRED
Definition: perf_skid.h:50
const int perf_skid_flavors
Definition: perf_skid.c:98
#define PERF_EVENT_AUTODETECT_SKID
Definition: perf_skid.h:49
#define PRECISE_IP_MAX_SUFFIX
Definition: perf_skid.c:82
#define PERF_EVENT_SKID_CONSTANT
Definition: perf_skid.h:52
#define PERF_FLAGS
long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags)
#define PERF_EVENT_SKID_ARBITRARY
Definition: perf_skid.h:53
#define PRECISE_IP_SUFFIX
Definition: perf_skid.c:81
#define CPU_ANY
#define THREAD_SELF
static const char * find_precise_suffix(const char *s, const char *suffix, char allowed)
Definition: perf_skid.c:143
int main(int argc, char *argv[])
Definition: main.cpp:125
#define PERF_EVENT_SKID_ZERO_REQUESTED
Definition: perf_skid.h:51
int perf_skid_parse_event(const char *event_string, char **event_string_without_skidmarks)
Definition: perf_skid.c:243
const int perf_skid_precision[]
Definition: perf_skid.c:91
bool found
Definition: cct.c:129
#define PRECISE_IP_CHAR_MODIFIER
Definition: perf_skid.c:79
__u64 u64
static long getEnvLong(const char *env_var, long default_value)
Definition: perf_skid.c:109
static char * strlaststr(const char *haystack, const char *needle)
Definition: perf_skid.c:126
u64 perf_skid_get_precise_ip(struct perf_event_attr *attr)
Definition: perf_skid.c:207
#define DELIMITER_HOWOFTEN
Definition: perf_skid.c:84