diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-06-13 02:19:06 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-06-13 02:19:06 -0400 |
commit | 4ba96195051be30160af6d5f5f83f9a055ab1f23 (patch) | |
tree | 7af7f287ce8c723393fa014288da900eb03a3641 /tools/perf/util | |
parent | 7184062b94b4bfac08715fb786fd2df399c5d6ee (diff) | |
parent | 45dc1bb5c1d47f9519e2101f6b073bb4bb1d1f99 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core
Pull perf/core improvements and fixes from Jiri Olsa:
* Honor user freq/interval properly in record command (Namhyung Kim)
* Speedup DWARF unwind (Jiri Olsa)
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/dso.c | 279 | ||||
-rw-r--r-- | tools/perf/util/dso.h | 50 | ||||
-rw-r--r-- | tools/perf/util/event.h | 5 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 4 | ||||
-rw-r--r-- | tools/perf/util/perf_regs.c | 10 | ||||
-rw-r--r-- | tools/perf/util/perf_regs.h | 4 | ||||
-rw-r--r-- | tools/perf/util/unwind-libunwind.c | 2 |
7 files changed, 322 insertions, 32 deletions
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 64453d63b971..819f10414f08 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -1,3 +1,6 @@ | |||
1 | #include <asm/bug.h> | ||
2 | #include <sys/time.h> | ||
3 | #include <sys/resource.h> | ||
1 | #include "symbol.h" | 4 | #include "symbol.h" |
2 | #include "dso.h" | 5 | #include "dso.h" |
3 | #include "machine.h" | 6 | #include "machine.h" |
@@ -136,7 +139,48 @@ int dso__read_binary_type_filename(const struct dso *dso, | |||
136 | return ret; | 139 | return ret; |
137 | } | 140 | } |
138 | 141 | ||
139 | static int open_dso(struct dso *dso, struct machine *machine) | 142 | /* |
143 | * Global list of open DSOs and the counter. | ||
144 | */ | ||
145 | static LIST_HEAD(dso__data_open); | ||
146 | static long dso__data_open_cnt; | ||
147 | |||
148 | static void dso__list_add(struct dso *dso) | ||
149 | { | ||
150 | list_add_tail(&dso->data.open_entry, &dso__data_open); | ||
151 | dso__data_open_cnt++; | ||
152 | } | ||
153 | |||
154 | static void dso__list_del(struct dso *dso) | ||
155 | { | ||
156 | list_del(&dso->data.open_entry); | ||
157 | WARN_ONCE(dso__data_open_cnt <= 0, | ||
158 | "DSO data fd counter out of bounds."); | ||
159 | dso__data_open_cnt--; | ||
160 | } | ||
161 | |||
162 | static void close_first_dso(void); | ||
163 | |||
164 | static int do_open(char *name) | ||
165 | { | ||
166 | int fd; | ||
167 | |||
168 | do { | ||
169 | fd = open(name, O_RDONLY); | ||
170 | if (fd >= 0) | ||
171 | return fd; | ||
172 | |||
173 | pr_debug("dso open failed, mmap: %s\n", strerror(errno)); | ||
174 | if (!dso__data_open_cnt || errno != EMFILE) | ||
175 | break; | ||
176 | |||
177 | close_first_dso(); | ||
178 | } while (1); | ||
179 | |||
180 | return -1; | ||
181 | } | ||
182 | |||
183 | static int __open_dso(struct dso *dso, struct machine *machine) | ||
140 | { | 184 | { |
141 | int fd; | 185 | int fd; |
142 | char *root_dir = (char *)""; | 186 | char *root_dir = (char *)""; |
@@ -154,11 +198,130 @@ static int open_dso(struct dso *dso, struct machine *machine) | |||
154 | return -EINVAL; | 198 | return -EINVAL; |
155 | } | 199 | } |
156 | 200 | ||
157 | fd = open(name, O_RDONLY); | 201 | fd = do_open(name); |
158 | free(name); | 202 | free(name); |
159 | return fd; | 203 | return fd; |
160 | } | 204 | } |
161 | 205 | ||
206 | static void check_data_close(void); | ||
207 | |||
208 | /** | ||
209 | * dso_close - Open DSO data file | ||
210 | * @dso: dso object | ||
211 | * | ||
212 | * Open @dso's data file descriptor and updates | ||
213 | * list/count of open DSO objects. | ||
214 | */ | ||
215 | static int open_dso(struct dso *dso, struct machine *machine) | ||
216 | { | ||
217 | int fd = __open_dso(dso, machine); | ||
218 | |||
219 | if (fd > 0) { | ||
220 | dso__list_add(dso); | ||
221 | /* | ||
222 | * Check if we crossed the allowed number | ||
223 | * of opened DSOs and close one if needed. | ||
224 | */ | ||
225 | check_data_close(); | ||
226 | } | ||
227 | |||
228 | return fd; | ||
229 | } | ||
230 | |||
231 | static void close_data_fd(struct dso *dso) | ||
232 | { | ||
233 | if (dso->data.fd >= 0) { | ||
234 | close(dso->data.fd); | ||
235 | dso->data.fd = -1; | ||
236 | dso->data.file_size = 0; | ||
237 | dso__list_del(dso); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * dso_close - Close DSO data file | ||
243 | * @dso: dso object | ||
244 | * | ||
245 | * Close @dso's data file descriptor and updates | ||
246 | * list/count of open DSO objects. | ||
247 | */ | ||
248 | static void close_dso(struct dso *dso) | ||
249 | { | ||
250 | close_data_fd(dso); | ||
251 | } | ||
252 | |||
253 | static void close_first_dso(void) | ||
254 | { | ||
255 | struct dso *dso; | ||
256 | |||
257 | dso = list_first_entry(&dso__data_open, struct dso, data.open_entry); | ||
258 | close_dso(dso); | ||
259 | } | ||
260 | |||
261 | static rlim_t get_fd_limit(void) | ||
262 | { | ||
263 | struct rlimit l; | ||
264 | rlim_t limit = 0; | ||
265 | |||
266 | /* Allow half of the current open fd limit. */ | ||
267 | if (getrlimit(RLIMIT_NOFILE, &l) == 0) { | ||
268 | if (l.rlim_cur == RLIM_INFINITY) | ||
269 | limit = l.rlim_cur; | ||
270 | else | ||
271 | limit = l.rlim_cur / 2; | ||
272 | } else { | ||
273 | pr_err("failed to get fd limit\n"); | ||
274 | limit = 1; | ||
275 | } | ||
276 | |||
277 | return limit; | ||
278 | } | ||
279 | |||
280 | static bool may_cache_fd(void) | ||
281 | { | ||
282 | static rlim_t limit; | ||
283 | |||
284 | if (!limit) | ||
285 | limit = get_fd_limit(); | ||
286 | |||
287 | if (limit == RLIM_INFINITY) | ||
288 | return true; | ||
289 | |||
290 | return limit > (rlim_t) dso__data_open_cnt; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Check and close LRU dso if we crossed allowed limit | ||
295 | * for opened dso file descriptors. The limit is half | ||
296 | * of the RLIMIT_NOFILE files opened. | ||
297 | */ | ||
298 | static void check_data_close(void) | ||
299 | { | ||
300 | bool cache_fd = may_cache_fd(); | ||
301 | |||
302 | if (!cache_fd) | ||
303 | close_first_dso(); | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * dso__data_close - Close DSO data file | ||
308 | * @dso: dso object | ||
309 | * | ||
310 | * External interface to close @dso's data file descriptor. | ||
311 | */ | ||
312 | void dso__data_close(struct dso *dso) | ||
313 | { | ||
314 | close_dso(dso); | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * dso__data_fd - Get dso's data file descriptor | ||
319 | * @dso: dso object | ||
320 | * @machine: machine object | ||
321 | * | ||
322 | * External interface to find dso's file, open it and | ||
323 | * returns file descriptor. | ||
324 | */ | ||
162 | int dso__data_fd(struct dso *dso, struct machine *machine) | 325 | int dso__data_fd(struct dso *dso, struct machine *machine) |
163 | { | 326 | { |
164 | enum dso_binary_type binary_type_data[] = { | 327 | enum dso_binary_type binary_type_data[] = { |
@@ -168,8 +331,13 @@ int dso__data_fd(struct dso *dso, struct machine *machine) | |||
168 | }; | 331 | }; |
169 | int i = 0; | 332 | int i = 0; |
170 | 333 | ||
171 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) | 334 | if (dso->data.fd >= 0) |
172 | return open_dso(dso, machine); | 335 | return dso->data.fd; |
336 | |||
337 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { | ||
338 | dso->data.fd = open_dso(dso, machine); | ||
339 | return dso->data.fd; | ||
340 | } | ||
173 | 341 | ||
174 | do { | 342 | do { |
175 | int fd; | 343 | int fd; |
@@ -178,7 +346,7 @@ int dso__data_fd(struct dso *dso, struct machine *machine) | |||
178 | 346 | ||
179 | fd = open_dso(dso, machine); | 347 | fd = open_dso(dso, machine); |
180 | if (fd >= 0) | 348 | if (fd >= 0) |
181 | return fd; | 349 | return dso->data.fd = fd; |
182 | 350 | ||
183 | } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); | 351 | } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); |
184 | 352 | ||
@@ -260,16 +428,10 @@ dso_cache__memcpy(struct dso_cache *cache, u64 offset, | |||
260 | } | 428 | } |
261 | 429 | ||
262 | static ssize_t | 430 | static ssize_t |
263 | dso_cache__read(struct dso *dso, struct machine *machine, | 431 | dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size) |
264 | u64 offset, u8 *data, ssize_t size) | ||
265 | { | 432 | { |
266 | struct dso_cache *cache; | 433 | struct dso_cache *cache; |
267 | ssize_t ret; | 434 | ssize_t ret; |
268 | int fd; | ||
269 | |||
270 | fd = dso__data_fd(dso, machine); | ||
271 | if (fd < 0) | ||
272 | return -1; | ||
273 | 435 | ||
274 | do { | 436 | do { |
275 | u64 cache_offset; | 437 | u64 cache_offset; |
@@ -283,16 +445,16 @@ dso_cache__read(struct dso *dso, struct machine *machine, | |||
283 | cache_offset = offset & DSO__DATA_CACHE_MASK; | 445 | cache_offset = offset & DSO__DATA_CACHE_MASK; |
284 | ret = -EINVAL; | 446 | ret = -EINVAL; |
285 | 447 | ||
286 | if (-1 == lseek(fd, cache_offset, SEEK_SET)) | 448 | if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET)) |
287 | break; | 449 | break; |
288 | 450 | ||
289 | ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); | 451 | ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE); |
290 | if (ret <= 0) | 452 | if (ret <= 0) |
291 | break; | 453 | break; |
292 | 454 | ||
293 | cache->offset = cache_offset; | 455 | cache->offset = cache_offset; |
294 | cache->size = ret; | 456 | cache->size = ret; |
295 | dso_cache__insert(&dso->cache, cache); | 457 | dso_cache__insert(&dso->data.cache, cache); |
296 | 458 | ||
297 | ret = dso_cache__memcpy(cache, offset, data, size); | 459 | ret = dso_cache__memcpy(cache, offset, data, size); |
298 | 460 | ||
@@ -301,24 +463,27 @@ dso_cache__read(struct dso *dso, struct machine *machine, | |||
301 | if (ret <= 0) | 463 | if (ret <= 0) |
302 | free(cache); | 464 | free(cache); |
303 | 465 | ||
304 | close(fd); | ||
305 | return ret; | 466 | return ret; |
306 | } | 467 | } |
307 | 468 | ||
308 | static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, | 469 | static ssize_t dso_cache_read(struct dso *dso, u64 offset, |
309 | u64 offset, u8 *data, ssize_t size) | 470 | u8 *data, ssize_t size) |
310 | { | 471 | { |
311 | struct dso_cache *cache; | 472 | struct dso_cache *cache; |
312 | 473 | ||
313 | cache = dso_cache__find(&dso->cache, offset); | 474 | cache = dso_cache__find(&dso->data.cache, offset); |
314 | if (cache) | 475 | if (cache) |
315 | return dso_cache__memcpy(cache, offset, data, size); | 476 | return dso_cache__memcpy(cache, offset, data, size); |
316 | else | 477 | else |
317 | return dso_cache__read(dso, machine, offset, data, size); | 478 | return dso_cache__read(dso, offset, data, size); |
318 | } | 479 | } |
319 | 480 | ||
320 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | 481 | /* |
321 | u64 offset, u8 *data, ssize_t size) | 482 | * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks |
483 | * in the rb_tree. Any read to already cached data is served | ||
484 | * by cached data. | ||
485 | */ | ||
486 | static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size) | ||
322 | { | 487 | { |
323 | ssize_t r = 0; | 488 | ssize_t r = 0; |
324 | u8 *p = data; | 489 | u8 *p = data; |
@@ -326,7 +491,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | |||
326 | do { | 491 | do { |
327 | ssize_t ret; | 492 | ssize_t ret; |
328 | 493 | ||
329 | ret = dso_cache_read(dso, machine, offset, p, size); | 494 | ret = dso_cache_read(dso, offset, p, size); |
330 | if (ret < 0) | 495 | if (ret < 0) |
331 | return ret; | 496 | return ret; |
332 | 497 | ||
@@ -346,6 +511,67 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | |||
346 | return r; | 511 | return r; |
347 | } | 512 | } |
348 | 513 | ||
514 | static int data_file_size(struct dso *dso) | ||
515 | { | ||
516 | struct stat st; | ||
517 | |||
518 | if (!dso->data.file_size) { | ||
519 | if (fstat(dso->data.fd, &st)) { | ||
520 | pr_err("dso mmap failed, fstat: %s\n", strerror(errno)); | ||
521 | return -1; | ||
522 | } | ||
523 | dso->data.file_size = st.st_size; | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static ssize_t data_read_offset(struct dso *dso, u64 offset, | ||
530 | u8 *data, ssize_t size) | ||
531 | { | ||
532 | if (data_file_size(dso)) | ||
533 | return -1; | ||
534 | |||
535 | /* Check the offset sanity. */ | ||
536 | if (offset > dso->data.file_size) | ||
537 | return -1; | ||
538 | |||
539 | if (offset + size < offset) | ||
540 | return -1; | ||
541 | |||
542 | return cached_read(dso, offset, data, size); | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * dso__data_read_offset - Read data from dso file offset | ||
547 | * @dso: dso object | ||
548 | * @machine: machine object | ||
549 | * @offset: file offset | ||
550 | * @data: buffer to store data | ||
551 | * @size: size of the @data buffer | ||
552 | * | ||
553 | * External interface to read data from dso file offset. Open | ||
554 | * dso data file and use cached_read to get the data. | ||
555 | */ | ||
556 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
557 | u64 offset, u8 *data, ssize_t size) | ||
558 | { | ||
559 | if (dso__data_fd(dso, machine) < 0) | ||
560 | return -1; | ||
561 | |||
562 | return data_read_offset(dso, offset, data, size); | ||
563 | } | ||
564 | |||
565 | /** | ||
566 | * dso__data_read_addr - Read data from dso address | ||
567 | * @dso: dso object | ||
568 | * @machine: machine object | ||
569 | * @add: virtual memory address | ||
570 | * @data: buffer to store data | ||
571 | * @size: size of the @data buffer | ||
572 | * | ||
573 | * External interface to read data from dso address. | ||
574 | */ | ||
349 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | 575 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, |
350 | struct machine *machine, u64 addr, | 576 | struct machine *machine, u64 addr, |
351 | u8 *data, ssize_t size) | 577 | u8 *data, ssize_t size) |
@@ -473,7 +699,8 @@ struct dso *dso__new(const char *name) | |||
473 | dso__set_short_name(dso, dso->name, false); | 699 | dso__set_short_name(dso, dso->name, false); |
474 | for (i = 0; i < MAP__NR_TYPES; ++i) | 700 | for (i = 0; i < MAP__NR_TYPES; ++i) |
475 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | 701 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; |
476 | dso->cache = RB_ROOT; | 702 | dso->data.cache = RB_ROOT; |
703 | dso->data.fd = -1; | ||
477 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | 704 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
478 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; | 705 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; |
479 | dso->loaded = 0; | 706 | dso->loaded = 0; |
@@ -485,6 +712,7 @@ struct dso *dso__new(const char *name) | |||
485 | dso->kernel = DSO_TYPE_USER; | 712 | dso->kernel = DSO_TYPE_USER; |
486 | dso->needs_swap = DSO_SWAP__UNSET; | 713 | dso->needs_swap = DSO_SWAP__UNSET; |
487 | INIT_LIST_HEAD(&dso->node); | 714 | INIT_LIST_HEAD(&dso->node); |
715 | INIT_LIST_HEAD(&dso->data.open_entry); | ||
488 | } | 716 | } |
489 | 717 | ||
490 | return dso; | 718 | return dso; |
@@ -506,7 +734,8 @@ void dso__delete(struct dso *dso) | |||
506 | dso->long_name_allocated = false; | 734 | dso->long_name_allocated = false; |
507 | } | 735 | } |
508 | 736 | ||
509 | dso_cache__free(&dso->cache); | 737 | dso__data_close(dso); |
738 | dso_cache__free(&dso->data.cache); | ||
510 | dso__free_a2l(dso); | 739 | dso__free_a2l(dso); |
511 | zfree(&dso->symsrc_filename); | 740 | zfree(&dso->symsrc_filename); |
512 | free(dso); | 741 | free(dso); |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 38efe95a7fdd..ad553ba257bf 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -76,7 +76,6 @@ struct dso { | |||
76 | struct list_head node; | 76 | struct list_head node; |
77 | struct rb_root symbols[MAP__NR_TYPES]; | 77 | struct rb_root symbols[MAP__NR_TYPES]; |
78 | struct rb_root symbol_names[MAP__NR_TYPES]; | 78 | struct rb_root symbol_names[MAP__NR_TYPES]; |
79 | struct rb_root cache; | ||
80 | void *a2l; | 79 | void *a2l; |
81 | char *symsrc_filename; | 80 | char *symsrc_filename; |
82 | unsigned int a2l_fails; | 81 | unsigned int a2l_fails; |
@@ -99,6 +98,15 @@ struct dso { | |||
99 | const char *long_name; | 98 | const char *long_name; |
100 | u16 long_name_len; | 99 | u16 long_name_len; |
101 | u16 short_name_len; | 100 | u16 short_name_len; |
101 | |||
102 | /* dso data file */ | ||
103 | struct { | ||
104 | struct rb_root cache; | ||
105 | int fd; | ||
106 | size_t file_size; | ||
107 | struct list_head open_entry; | ||
108 | } data; | ||
109 | |||
102 | char name[0]; | 110 | char name[0]; |
103 | }; | 111 | }; |
104 | 112 | ||
@@ -141,7 +149,47 @@ char dso__symtab_origin(const struct dso *dso); | |||
141 | int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, | 149 | int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, |
142 | char *root_dir, char *filename, size_t size); | 150 | char *root_dir, char *filename, size_t size); |
143 | 151 | ||
152 | /* | ||
153 | * The dso__data_* external interface provides following functions: | ||
154 | * dso__data_fd | ||
155 | * dso__data_close | ||
156 | * dso__data_read_offset | ||
157 | * dso__data_read_addr | ||
158 | * | ||
159 | * Please refer to the dso.c object code for each function and | ||
160 | * arguments documentation. Following text tries to explain the | ||
161 | * dso file descriptor caching. | ||
162 | * | ||
163 | * The dso__data* interface allows caching of opened file descriptors | ||
164 | * to speed up the dso data accesses. The idea is to leave the file | ||
165 | * descriptor opened ideally for the whole life of the dso object. | ||
166 | * | ||
167 | * The current usage of the dso__data_* interface is as follows: | ||
168 | * | ||
169 | * Get DSO's fd: | ||
170 | * int fd = dso__data_fd(dso, machine); | ||
171 | * USE 'fd' SOMEHOW | ||
172 | * | ||
173 | * Read DSO's data: | ||
174 | * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE); | ||
175 | * n = dso__data_read_addr(dso_0, &machine, 0, buf, BUFSIZE); | ||
176 | * | ||
177 | * Eventually close DSO's fd: | ||
178 | * dso__data_close(dso); | ||
179 | * | ||
180 | * It is not necessary to close the DSO object data file. Each time new | ||
181 | * DSO data file is opened, the limit (RLIMIT_NOFILE/2) is checked. Once | ||
182 | * it is crossed, the oldest opened DSO object is closed. | ||
183 | * | ||
184 | * The dso__delete function calls close_dso function to ensure the | ||
185 | * data file descriptor gets closed/unmapped before the dso object | ||
186 | * is freed. | ||
187 | * | ||
188 | * TODO | ||
189 | */ | ||
144 | int dso__data_fd(struct dso *dso, struct machine *machine); | 190 | int dso__data_fd(struct dso *dso, struct machine *machine); |
191 | void dso__data_close(struct dso *dso); | ||
192 | |||
145 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | 193 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, |
146 | u64 offset, u8 *data, ssize_t size); | 194 | u64 offset, u8 *data, ssize_t size); |
147 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | 195 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 9ba2eb3bdcfd..e5dd40addb30 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "../perf.h" | 7 | #include "../perf.h" |
8 | #include "map.h" | 8 | #include "map.h" |
9 | #include "build-id.h" | 9 | #include "build-id.h" |
10 | #include "perf_regs.h" | ||
10 | 11 | ||
11 | struct mmap_event { | 12 | struct mmap_event { |
12 | struct perf_event_header header; | 13 | struct perf_event_header header; |
@@ -89,6 +90,10 @@ struct regs_dump { | |||
89 | u64 abi; | 90 | u64 abi; |
90 | u64 mask; | 91 | u64 mask; |
91 | u64 *regs; | 92 | u64 *regs; |
93 | |||
94 | /* Cached values/mask filled by first register access. */ | ||
95 | u64 cache_regs[PERF_REGS_MAX]; | ||
96 | u64 cache_mask; | ||
92 | }; | 97 | }; |
93 | 98 | ||
94 | struct stack_dump { | 99 | struct stack_dump { |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 21154dabc5fa..8606175fe1e8 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -589,10 +589,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
589 | } | 589 | } |
590 | 590 | ||
591 | /* | 591 | /* |
592 | * We default some events to a 1 default interval. But keep | 592 | * We default some events to have a default interval. But keep |
593 | * it a weak assumption overridable by the user. | 593 | * it a weak assumption overridable by the user. |
594 | */ | 594 | */ |
595 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && | 595 | if (!attr->sample_period || (opts->user_freq != UINT_MAX || |
596 | opts->user_interval != ULLONG_MAX)) { | 596 | opts->user_interval != ULLONG_MAX)) { |
597 | if (opts->freq) { | 597 | if (opts->freq) { |
598 | perf_evsel__set_sample_bit(evsel, PERIOD); | 598 | perf_evsel__set_sample_bit(evsel, PERIOD); |
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index a3539ef30b15..43168fb0d9a2 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c | |||
@@ -1,11 +1,15 @@ | |||
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include "perf_regs.h" | 2 | #include "perf_regs.h" |
3 | #include "event.h" | ||
3 | 4 | ||
4 | int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) | 5 | int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) |
5 | { | 6 | { |
6 | int i, idx = 0; | 7 | int i, idx = 0; |
7 | u64 mask = regs->mask; | 8 | u64 mask = regs->mask; |
8 | 9 | ||
10 | if (regs->cache_mask & (1 << id)) | ||
11 | goto out; | ||
12 | |||
9 | if (!(mask & (1 << id))) | 13 | if (!(mask & (1 << id))) |
10 | return -EINVAL; | 14 | return -EINVAL; |
11 | 15 | ||
@@ -14,6 +18,10 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) | |||
14 | idx++; | 18 | idx++; |
15 | } | 19 | } |
16 | 20 | ||
17 | *valp = regs->regs[idx]; | 21 | regs->cache_mask |= (1 << id); |
22 | regs->cache_regs[id] = regs->regs[idx]; | ||
23 | |||
24 | out: | ||
25 | *valp = regs->cache_regs[id]; | ||
18 | return 0; | 26 | return 0; |
19 | } | 27 | } |
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 79c78f74e0cf..980dbf76bc98 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h | |||
@@ -2,7 +2,8 @@ | |||
2 | #define __PERF_REGS_H | 2 | #define __PERF_REGS_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include "event.h" | 5 | |
6 | struct regs_dump; | ||
6 | 7 | ||
7 | #ifdef HAVE_PERF_REGS_SUPPORT | 8 | #ifdef HAVE_PERF_REGS_SUPPORT |
8 | #include <perf_regs.h> | 9 | #include <perf_regs.h> |
@@ -11,6 +12,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id); | |||
11 | 12 | ||
12 | #else | 13 | #else |
13 | #define PERF_REGS_MASK 0 | 14 | #define PERF_REGS_MASK 0 |
15 | #define PERF_REGS_MAX 0 | ||
14 | 16 | ||
15 | static inline const char *perf_reg_name(int id __maybe_unused) | 17 | static inline const char *perf_reg_name(int id __maybe_unused) |
16 | { | 18 | { |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index bd5768d74f01..25578b98f5c5 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -250,7 +250,6 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, | |||
250 | 250 | ||
251 | /* Check the .eh_frame section for unwinding info */ | 251 | /* Check the .eh_frame section for unwinding info */ |
252 | offset = elf_section_offset(fd, ".eh_frame_hdr"); | 252 | offset = elf_section_offset(fd, ".eh_frame_hdr"); |
253 | close(fd); | ||
254 | 253 | ||
255 | if (offset) | 254 | if (offset) |
256 | ret = unwind_spec_ehframe(dso, machine, offset, | 255 | ret = unwind_spec_ehframe(dso, machine, offset, |
@@ -271,7 +270,6 @@ static int read_unwind_spec_debug_frame(struct dso *dso, | |||
271 | 270 | ||
272 | /* Check the .debug_frame section for unwinding info */ | 271 | /* Check the .debug_frame section for unwinding info */ |
273 | *offset = elf_section_offset(fd, ".debug_frame"); | 272 | *offset = elf_section_offset(fd, ".debug_frame"); |
274 | close(fd); | ||
275 | 273 | ||
276 | if (*offset) | 274 | if (*offset) |
277 | return 0; | 275 | return 0; |