aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/dso.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/dso.c')
-rw-r--r--tools/perf/util/dso.c279
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
139static int open_dso(struct dso *dso, struct machine *machine) 142/*
143 * Global list of open DSOs and the counter.
144 */
145static LIST_HEAD(dso__data_open);
146static long dso__data_open_cnt;
147
148static 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
154static 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
162static void close_first_dso(void);
163
164static 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
183static 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
206static 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 */
215static 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
231static 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 */
248static void close_dso(struct dso *dso)
249{
250 close_data_fd(dso);
251}
252
253static 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
261static 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
280static 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*/
298static 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 */
312void 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 */
162int dso__data_fd(struct dso *dso, struct machine *machine) 325int 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
262static ssize_t 430static ssize_t
263dso_cache__read(struct dso *dso, struct machine *machine, 431dso_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
308static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 469static 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
320ssize_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 */
486static 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
514static 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
529static 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 */
556ssize_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 */
349ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 575ssize_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);