diff options
Diffstat (limited to 'tools/perf/util/dso.c')
-rw-r--r-- | tools/perf/util/dso.c | 279 |
1 files changed, 254 insertions, 25 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); |