Skip to content

Commit 939cda5

Browse files
Yunlong Songacmel
Yunlong Song
authored andcommitted
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 <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Wang Nan <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 1aff59b commit 939cda5

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

tools/perf/builtin-sched.c

+26-5
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ struct perf_sched {
170170
u64 cpu_last_switched[MAX_CPUS];
171171
struct rb_root atom_root, sorted_atom_root;
172172
struct list_head sort_list, cmp_pid;
173+
bool force;
173174
};
174175

175176
static u64 get_nsecs(void)
@@ -437,24 +438,43 @@ static u64 get_cpu_usage_nsec_parent(void)
437438
return sum;
438439
}
439440

440-
static int self_open_counters(void)
441+
static int self_open_counters(struct perf_sched *sched, unsigned long cur_task)
441442
{
442443
struct perf_event_attr attr;
443-
char sbuf[STRERR_BUFSIZE];
444+
char sbuf[STRERR_BUFSIZE], info[STRERR_BUFSIZE];
444445
int fd;
446+
struct rlimit limit;
447+
bool need_privilege = false;
445448

446449
memset(&attr, 0, sizeof(attr));
447450

448451
attr.type = PERF_TYPE_SOFTWARE;
449452
attr.config = PERF_COUNT_SW_TASK_CLOCK;
450453

454+
force_again:
451455
fd = sys_perf_event_open(&attr, 0, -1, -1,
452456
perf_event_open_cloexec_flag());
453457

454458
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+
}
455475
pr_err("Error: sys_perf_event_open() syscall returned "
456-
"with %d (%s)\n", fd,
457-
strerror_r(errno, sbuf, sizeof(sbuf)));
476+
"with %d (%s)\n%s", fd,
477+
strerror_r(errno, sbuf, sizeof(sbuf)), info);
458478
exit(EXIT_FAILURE);
459479
}
460480
return fd;
@@ -542,7 +562,7 @@ static void create_tasks(struct perf_sched *sched)
542562
BUG_ON(parms == NULL);
543563
parms->task = task = sched->tasks[i];
544564
parms->sched = sched;
545-
parms->fd = self_open_counters();
565+
parms->fd = self_open_counters(sched, i);
546566
sem_init(&task->sleep_sem, 0, 0);
547567
sem_init(&task->ready_for_work, 0, 0);
548568
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)
17001720
"be more verbose (show symbol address, etc)"),
17011721
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
17021722
"dump raw trace in ASCII"),
1723+
OPT_BOOLEAN('f', "force", &sched.force, "don't complain, do it"),
17031724
OPT_END()
17041725
};
17051726
const struct option sched_options[] = {

0 commit comments

Comments
 (0)