aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorYunlong Song <yunlong.song@huawei.com>2015-03-31 09:46:34 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-04-08 08:07:26 -0400
commit939cda521a24ae4dbf3beec983abd519bce56231 (patch)
tree10b5c4fc04b353051886faffb7bb0929318348ee /tools/perf
parent1aff59be53ef37aa9943fb5f772f03148f789bb6 (diff)
perf sched replay: Fix the EMFILE error caused by the limitation of the maximum open files
The soft maximum number of open files for a calling process is 1024, which is defined as INR_OPEN_CUR in include/uapi/linux/fs.h, and the hard maximum number of open files for a calling process is 4096, which is defined as INR_OPEN_MAX in include/uapi/linux/fs.h. Both INR_OPEN_CUR and INR_OPEN_MAX are used to limit the value of RLIMIT_NOFILE in include/asm-generic/resource.h. And the soft maximum number finally decides the limitation of the maximum files which are allowed to be opened. That is to say a process can use at most 1024 file descriptors for its o pened files, or an EMFILE error will happen. This error can be fixed by increasing the soft maximum number, under the constraint that the soft maximum number can not exceed the hard maximum number, or both soft and hard maximum number should be increased simultaneously with privilege. For perf sched replay, it uses sys_perf_event_open to create the file descriptor for each of the tasks in order to handle information of perf events. That is to say each task needs a unique file descriptor. In x86_64, there may be over 1024 or 4096 tasks correspoinding to the record in perf.data, which causes that no enough file descriptors can be used. As a result, EMFILE error happens and stops the replay process. To solve this problem, we adaptively increase the soft and hard maximum number of open files with a '-f' option. Example: Test environment: x86_64 with 160 cores $ cat /proc/sys/kernel/pid_max 163840 $ cat /proc/sys/fs/file-max 6815744 $ ulimit -Sn 1024 $ ulimit -Hn 4096 Before this patch: $ perf sched replay ... task 1549 ( :163132: 163132), nr_events: 1 task 1550 ( :163540: 163540), nr_events: 1 task 1551 ( <unknown>: 0), nr_events: 10 Error: sys_perf_event_open() syscall returned with -1 (Too many open files) After this patch: $ perf sched replay ... task 1549 ( :163132: 163132), nr_events: 1 task 1550 ( :163540: 163540), nr_events: 1 task 1551 ( <unknown>: 0), nr_events: 10 Error: sys_perf_event_open() syscall returned with -1 (Too many open files) Have a try with -f option $ perf sched replay -f ... task 1549 ( :163132: 163132), nr_events: 1 task 1550 ( :163540: 163540), nr_events: 1 task 1551 ( <unknown>: 0), nr_events: 10 ------------------------------------------------------------ #1 : 54.401, ravg: 54.40, cpu: 3285.21 / 3285.21 #2 : 199.548, ravg: 68.92, cpu: 4999.65 / 3456.66 #3 : 170.483, ravg: 79.07, cpu: 1349.94 / 3245.99 #4 : 192.034, ravg: 90.37, cpu: 1322.88 / 3053.67 #5 : 182.929, ravg: 99.62, cpu: 1406.51 / 2888.96 #6 : 152.974, ravg: 104.96, cpu: 1167.54 / 2716.82 #7 : 155.579, ravg: 110.02, cpu: 2992.53 / 2744.39 #8 : 130.557, ravg: 112.08, cpu: 1126.43 / 2582.59 #9 : 138.520, ravg: 114.72, cpu: 1253.22 / 2449.65 #10 : 134.328, ravg: 116.68, cpu: 1587.95 / 2363.48 Signed-off-by: Yunlong Song <yunlong.song@huawei.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/1427809596-29559-8-git-send-email-yunlong.song@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-sched.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 3261300c08f0..5ab58c6d2467 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -170,6 +170,7 @@ struct perf_sched {
170 u64 cpu_last_switched[MAX_CPUS]; 170 u64 cpu_last_switched[MAX_CPUS];
171 struct rb_root atom_root, sorted_atom_root; 171 struct rb_root atom_root, sorted_atom_root;
172 struct list_head sort_list, cmp_pid; 172 struct list_head sort_list, cmp_pid;
173 bool force;
173}; 174};
174 175
175static u64 get_nsecs(void) 176static u64 get_nsecs(void)
@@ -437,24 +438,43 @@ static u64 get_cpu_usage_nsec_parent(void)
437 return sum; 438 return sum;
438} 439}
439 440
440static int self_open_counters(void) 441static int self_open_counters(struct perf_sched *sched, unsigned long cur_task)
441{ 442{
442 struct perf_event_attr attr; 443 struct perf_event_attr attr;
443 char sbuf[STRERR_BUFSIZE]; 444 char sbuf[STRERR_BUFSIZE], info[STRERR_BUFSIZE];
444 int fd; 445 int fd;
446 struct rlimit limit;
447 bool need_privilege = false;
445 448
446 memset(&attr, 0, sizeof(attr)); 449 memset(&attr, 0, sizeof(attr));
447 450
448 attr.type = PERF_TYPE_SOFTWARE; 451 attr.type = PERF_TYPE_SOFTWARE;
449 attr.config = PERF_COUNT_SW_TASK_CLOCK; 452 attr.config = PERF_COUNT_SW_TASK_CLOCK;
450 453
454force_again:
451 fd = sys_perf_event_open(&attr, 0, -1, -1, 455 fd = sys_perf_event_open(&attr, 0, -1, -1,
452 perf_event_open_cloexec_flag()); 456 perf_event_open_cloexec_flag());
453 457
454 if (fd < 0) { 458 if (fd < 0) {
459 if (errno == EMFILE) {
460 if (sched->force) {
461 BUG_ON(getrlimit(RLIMIT_NOFILE, &limit) == -1);
462 limit.rlim_cur += sched->nr_tasks - cur_task;
463 if (limit.rlim_cur > limit.rlim_max) {
464 limit.rlim_max = limit.rlim_cur;
465 need_privilege = true;
466 }
467 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
468 if (need_privilege && errno == EPERM)
469 strcpy(info, "Need privilege\n");
470 } else
471 goto force_again;
472 } else
473 strcpy(info, "Have a try with -f option\n");
474 }
455 pr_err("Error: sys_perf_event_open() syscall returned " 475 pr_err("Error: sys_perf_event_open() syscall returned "
456 "with %d (%s)\n", fd, 476 "with %d (%s)\n%s", fd,
457 strerror_r(errno, sbuf, sizeof(sbuf))); 477 strerror_r(errno, sbuf, sizeof(sbuf)), info);
458 exit(EXIT_FAILURE); 478 exit(EXIT_FAILURE);
459 } 479 }
460 return fd; 480 return fd;
@@ -542,7 +562,7 @@ static void create_tasks(struct perf_sched *sched)
542 BUG_ON(parms == NULL); 562 BUG_ON(parms == NULL);
543 parms->task = task = sched->tasks[i]; 563 parms->task = task = sched->tasks[i];
544 parms->sched = sched; 564 parms->sched = sched;
545 parms->fd = self_open_counters(); 565 parms->fd = self_open_counters(sched, i);
546 sem_init(&task->sleep_sem, 0, 0); 566 sem_init(&task->sleep_sem, 0, 0);
547 sem_init(&task->ready_for_work, 0, 0); 567 sem_init(&task->ready_for_work, 0, 0);
548 sem_init(&task->work_done_sem, 0, 0); 568 sem_init(&task->work_done_sem, 0, 0);
@@ -1700,6 +1720,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1700 "be more verbose (show symbol address, etc)"), 1720 "be more verbose (show symbol address, etc)"),
1701 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1721 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1702 "dump raw trace in ASCII"), 1722 "dump raw trace in ASCII"),
1723 OPT_BOOLEAN('f', "force", &sched.force, "don't complain, do it"),
1703 OPT_END() 1724 OPT_END()
1704 }; 1725 };
1705 const struct option sched_options[] = { 1726 const struct option sched_options[] = {