]>
Commit | Line | Data |
---|---|---|
1aed2671 | 1 | #include "../perf.h" |
4cf40131 | 2 | #include "util.h" |
69e3f52d | 3 | #include <sys/mman.h> |
89fe808a | 4 | #ifdef HAVE_BACKTRACE_SUPPORT |
dc4552bf | 5 | #include <execinfo.h> |
c9f08bee | 6 | #endif |
dc4552bf ACM |
7 | #include <stdio.h> |
8 | #include <stdlib.h> | |
4cf40131 | 9 | |
1aed2671 JR |
10 | /* |
11 | * XXX We need to find a better place for these things... | |
12 | */ | |
0c1fe6b2 ACM |
13 | unsigned int page_size; |
14 | ||
0c6332e9 ACM |
15 | bool test_attr__enabled; |
16 | ||
1aed2671 | 17 | bool perf_host = true; |
c4a7dca9 | 18 | bool perf_guest = false; |
1aed2671 | 19 | |
1355915a BP |
20 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; |
21 | ||
1aed2671 JR |
22 | void event_attr_init(struct perf_event_attr *attr) |
23 | { | |
24 | if (!perf_host) | |
25 | attr->exclude_host = 1; | |
26 | if (!perf_guest) | |
27 | attr->exclude_guest = 1; | |
7e1ccd38 SE |
28 | /* to capture ABI version */ |
29 | attr->size = sizeof(*attr); | |
1aed2671 JR |
30 | } |
31 | ||
4cf40131 ACM |
32 | int mkdir_p(char *path, mode_t mode) |
33 | { | |
34 | struct stat st; | |
35 | int err; | |
36 | char *d = path; | |
37 | ||
38 | if (*d != '/') | |
39 | return -1; | |
40 | ||
41 | if (stat(path, &st) == 0) | |
42 | return 0; | |
43 | ||
44 | while (*++d == '/'); | |
45 | ||
46 | while ((d = strchr(d, '/'))) { | |
47 | *d = '\0'; | |
48 | err = stat(path, &st) && mkdir(path, mode); | |
49 | *d++ = '/'; | |
50 | if (err) | |
51 | return -1; | |
52 | while (*d == '/') | |
53 | ++d; | |
54 | } | |
55 | return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; | |
56 | } | |
57 | ||
9a17d726 | 58 | static int slow_copyfile(const char *from, const char *to, mode_t mode) |
9e201442 | 59 | { |
9a17d726 | 60 | int err = -1; |
9e201442 ACM |
61 | char *line = NULL; |
62 | size_t n; | |
63 | FILE *from_fp = fopen(from, "r"), *to_fp; | |
9a17d726 | 64 | mode_t old_umask; |
9e201442 ACM |
65 | |
66 | if (from_fp == NULL) | |
67 | goto out; | |
68 | ||
9a17d726 | 69 | old_umask = umask(mode ^ 0777); |
9e201442 | 70 | to_fp = fopen(to, "w"); |
9a17d726 | 71 | umask(old_umask); |
9e201442 ACM |
72 | if (to_fp == NULL) |
73 | goto out_fclose_from; | |
74 | ||
75 | while (getline(&line, &n, from_fp) > 0) | |
76 | if (fputs(line, to_fp) == EOF) | |
77 | goto out_fclose_to; | |
78 | err = 0; | |
79 | out_fclose_to: | |
80 | fclose(to_fp); | |
81 | free(line); | |
82 | out_fclose_from: | |
83 | fclose(from_fp); | |
84 | out: | |
85 | return err; | |
86 | } | |
87 | ||
9a17d726 | 88 | int copyfile_mode(const char *from, const char *to, mode_t mode) |
4cf40131 ACM |
89 | { |
90 | int fromfd, tofd; | |
91 | struct stat st; | |
92 | void *addr; | |
93 | int err = -1; | |
94 | ||
95 | if (stat(from, &st)) | |
96 | goto out; | |
97 | ||
9e201442 | 98 | if (st.st_size == 0) /* /proc? do it slowly... */ |
9a17d726 | 99 | return slow_copyfile(from, to, mode); |
9e201442 | 100 | |
4cf40131 ACM |
101 | fromfd = open(from, O_RDONLY); |
102 | if (fromfd < 0) | |
103 | goto out; | |
104 | ||
9a17d726 | 105 | tofd = creat(to, mode); |
4cf40131 ACM |
106 | if (tofd < 0) |
107 | goto out_close_from; | |
108 | ||
109 | addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0); | |
110 | if (addr == MAP_FAILED) | |
111 | goto out_close_to; | |
112 | ||
113 | if (write(tofd, addr, st.st_size) == st.st_size) | |
114 | err = 0; | |
115 | ||
116 | munmap(addr, st.st_size); | |
117 | out_close_to: | |
118 | close(tofd); | |
119 | if (err) | |
120 | unlink(to); | |
121 | out_close_from: | |
122 | close(fromfd); | |
123 | out: | |
124 | return err; | |
125 | } | |
c82ee828 | 126 | |
9a17d726 AH |
127 | int copyfile(const char *from, const char *to) |
128 | { | |
129 | return copyfile_mode(from, to, 0755); | |
130 | } | |
131 | ||
c82ee828 ACM |
132 | unsigned long convert_unit(unsigned long value, char *unit) |
133 | { | |
134 | *unit = ' '; | |
135 | ||
136 | if (value > 1000) { | |
137 | value /= 1000; | |
138 | *unit = 'K'; | |
139 | } | |
140 | ||
141 | if (value > 1000) { | |
142 | value /= 1000; | |
143 | *unit = 'M'; | |
144 | } | |
145 | ||
146 | if (value > 1000) { | |
147 | value /= 1000; | |
148 | *unit = 'G'; | |
149 | } | |
150 | ||
151 | return value; | |
152 | } | |
1e7972cc | 153 | |
727ebd54 | 154 | ssize_t readn(int fd, void *buf, size_t n) |
1e7972cc ACM |
155 | { |
156 | void *buf_start = buf; | |
157 | ||
158 | while (n) { | |
727ebd54 | 159 | ssize_t ret = read(fd, buf, n); |
1e7972cc ACM |
160 | |
161 | if (ret <= 0) | |
162 | return ret; | |
163 | ||
164 | n -= ret; | |
165 | buf += ret; | |
166 | } | |
167 | ||
168 | return buf - buf_start; | |
169 | } | |
61e04b33 ACM |
170 | |
171 | size_t hex_width(u64 v) | |
172 | { | |
173 | size_t n = 1; | |
174 | ||
175 | while ((v >>= 4)) | |
176 | ++n; | |
177 | ||
178 | return n; | |
179 | } | |
dc4552bf | 180 | |
b2aff5f6 JO |
181 | static int hex(char ch) |
182 | { | |
183 | if ((ch >= '0') && (ch <= '9')) | |
184 | return ch - '0'; | |
185 | if ((ch >= 'a') && (ch <= 'f')) | |
186 | return ch - 'a' + 10; | |
187 | if ((ch >= 'A') && (ch <= 'F')) | |
188 | return ch - 'A' + 10; | |
189 | return -1; | |
190 | } | |
191 | ||
192 | /* | |
193 | * While we find nice hex chars, build a long_val. | |
194 | * Return number of chars processed. | |
195 | */ | |
196 | int hex2u64(const char *ptr, u64 *long_val) | |
197 | { | |
198 | const char *p = ptr; | |
199 | *long_val = 0; | |
200 | ||
201 | while (*p) { | |
202 | const int hex_val = hex(*p); | |
203 | ||
204 | if (hex_val < 0) | |
205 | break; | |
206 | ||
207 | *long_val = (*long_val << 4) | hex_val; | |
208 | p++; | |
209 | } | |
210 | ||
211 | return p - ptr; | |
212 | } | |
213 | ||
dc4552bf | 214 | /* Obtain a backtrace and print it to stdout. */ |
89fe808a | 215 | #ifdef HAVE_BACKTRACE_SUPPORT |
dc4552bf ACM |
216 | void dump_stack(void) |
217 | { | |
218 | void *array[16]; | |
219 | size_t size = backtrace(array, ARRAY_SIZE(array)); | |
220 | char **strings = backtrace_symbols(array, size); | |
221 | size_t i; | |
222 | ||
223 | printf("Obtained %zd stack frames.\n", size); | |
224 | ||
225 | for (i = 0; i < size; i++) | |
226 | printf("%s\n", strings[i]); | |
227 | ||
228 | free(strings); | |
229 | } | |
c9f08bee IT |
230 | #else |
231 | void dump_stack(void) {} | |
232 | #endif | |
2c803e52 DA |
233 | |
234 | void get_term_dimensions(struct winsize *ws) | |
235 | { | |
236 | char *s = getenv("LINES"); | |
237 | ||
238 | if (s != NULL) { | |
239 | ws->ws_row = atoi(s); | |
240 | s = getenv("COLUMNS"); | |
241 | if (s != NULL) { | |
242 | ws->ws_col = atoi(s); | |
243 | if (ws->ws_row && ws->ws_col) | |
244 | return; | |
245 | } | |
246 | } | |
247 | #ifdef TIOCGWINSZ | |
248 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | |
249 | ws->ws_row && ws->ws_col) | |
250 | return; | |
251 | #endif | |
252 | ws->ws_row = 25; | |
253 | ws->ws_col = 80; | |
254 | } | |
1355915a BP |
255 | |
256 | static void set_tracing_events_path(const char *mountpoint) | |
257 | { | |
258 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | |
259 | mountpoint, "tracing/events"); | |
260 | } | |
261 | ||
262 | const char *perf_debugfs_mount(const char *mountpoint) | |
263 | { | |
264 | const char *mnt; | |
265 | ||
266 | mnt = debugfs_mount(mountpoint); | |
267 | if (!mnt) | |
268 | return NULL; | |
269 | ||
270 | set_tracing_events_path(mnt); | |
271 | ||
272 | return mnt; | |
273 | } | |
274 | ||
275 | void perf_debugfs_set_path(const char *mntpt) | |
276 | { | |
277 | snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); | |
278 | set_tracing_events_path(mntpt); | |
279 | } | |
167aedc4 NK |
280 | |
281 | static const char *find_debugfs(void) | |
282 | { | |
283 | const char *path = perf_debugfs_mount(NULL); | |
284 | ||
285 | if (!path) | |
286 | fprintf(stderr, "Your kernel does not support the debugfs filesystem"); | |
287 | ||
288 | return path; | |
289 | } | |
290 | ||
291 | /* | |
292 | * Finds the path to the debugfs/tracing | |
293 | * Allocates the string and stores it. | |
294 | */ | |
295 | const char *find_tracing_dir(void) | |
296 | { | |
297 | static char *tracing; | |
298 | static int tracing_found; | |
299 | const char *debugfs; | |
300 | ||
301 | if (tracing_found) | |
302 | return tracing; | |
303 | ||
304 | debugfs = find_debugfs(); | |
305 | if (!debugfs) | |
306 | return NULL; | |
307 | ||
308 | tracing = malloc(strlen(debugfs) + 9); | |
309 | if (!tracing) | |
310 | return NULL; | |
311 | ||
312 | sprintf(tracing, "%s/tracing", debugfs); | |
313 | ||
314 | tracing_found = 1; | |
315 | return tracing; | |
316 | } | |
317 | ||
318 | char *get_tracing_file(const char *name) | |
319 | { | |
320 | const char *tracing; | |
321 | char *file; | |
322 | ||
323 | tracing = find_tracing_dir(); | |
324 | if (!tracing) | |
325 | return NULL; | |
326 | ||
327 | file = malloc(strlen(tracing) + strlen(name) + 2); | |
328 | if (!file) | |
329 | return NULL; | |
330 | ||
331 | sprintf(file, "%s/%s", tracing, name); | |
332 | return file; | |
333 | } | |
334 | ||
335 | void put_tracing_file(char *file) | |
336 | { | |
337 | free(file); | |
338 | } | |
3b47abe1 NK |
339 | |
340 | int parse_nsec_time(const char *str, u64 *ptime) | |
341 | { | |
342 | u64 time_sec, time_nsec; | |
343 | char *end; | |
344 | ||
345 | time_sec = strtoul(str, &end, 10); | |
346 | if (*end != '.' && *end != '\0') | |
347 | return -1; | |
348 | ||
349 | if (*end == '.') { | |
350 | int i; | |
351 | char nsec_buf[10]; | |
352 | ||
353 | if (strlen(++end) > 9) | |
354 | return -1; | |
355 | ||
356 | strncpy(nsec_buf, end, 9); | |
357 | nsec_buf[9] = '\0'; | |
358 | ||
359 | /* make it nsec precision */ | |
360 | for (i = strlen(nsec_buf); i < 9; i++) | |
361 | nsec_buf[i] = '0'; | |
362 | ||
363 | time_nsec = strtoul(nsec_buf, &end, 10); | |
364 | if (*end != '\0') | |
365 | return -1; | |
366 | } else | |
367 | time_nsec = 0; | |
368 | ||
369 | *ptime = time_sec * NSEC_PER_SEC + time_nsec; | |
370 | return 0; | |
371 | } | |
27050f53 JO |
372 | |
373 | unsigned long parse_tag_value(const char *str, struct parse_tag *tags) | |
374 | { | |
375 | struct parse_tag *i = tags; | |
376 | ||
377 | while (i->tag) { | |
378 | char *s; | |
379 | ||
380 | s = strchr(str, i->tag); | |
381 | if (s) { | |
382 | unsigned long int value; | |
383 | char *endptr; | |
384 | ||
385 | value = strtoul(str, &endptr, 10); | |
386 | if (s != endptr) | |
387 | break; | |
388 | ||
56921bec AH |
389 | if (value > ULONG_MAX / i->mult) |
390 | break; | |
27050f53 JO |
391 | value *= i->mult; |
392 | return value; | |
393 | } | |
394 | i++; | |
395 | } | |
396 | ||
397 | return (unsigned long) -1; | |
398 | } | |
97a07f10 ACM |
399 | |
400 | int filename__read_int(const char *filename, int *value) | |
401 | { | |
402 | char line[64]; | |
403 | int fd = open(filename, O_RDONLY), err = -1; | |
404 | ||
405 | if (fd < 0) | |
406 | return -1; | |
407 | ||
408 | if (read(fd, line, sizeof(line)) > 0) { | |
409 | *value = atoi(line); | |
410 | err = 0; | |
411 | } | |
412 | ||
413 | close(fd); | |
414 | return err; | |
415 | } |