From 8aca4f3a0f820ac2ce82e0869c5f00110c885055 Mon Sep 17 00:00:00 2001 From: Fei Li Date: Tue, 22 Nov 2022 17:57:05 +0800 Subject: [PATCH] Collect nropen for each process to monitor if fd leaks This patch collects and displays the current number of opened file descriptors for each process to monitor if fd leaks. As each thread has the same fds with its process, there is no need to collect each thread's fd numbers then. Considering users may set the nr_open limit to a very large number, we regard MAX_OPEN to be 10000 to avoid further performance degradation. Signed-off-by: Fei Li --- deviate.c | 1 + json.c | 2 ++ man/atop.1 | 5 +++++ parseable.c | 3 ++- photoproc.c | 35 +++++++++++++++++++++++++++++++++++ photoproc.h | 3 ++- showlinux.c | 3 ++- showlinux.h | 1 + showprocs.c | 28 ++++++++++++++++++++++++++++ 9 files changed, 78 insertions(+), 3 deletions(-) diff --git a/deviate.c b/deviate.c index c9ae3c0c..5f695729 100644 --- a/deviate.c +++ b/deviate.c @@ -455,6 +455,7 @@ calcdiff(struct tstat *devstat, const struct tstat *curstat, devstat->cpu.cgcpuweight = curstat->cpu.cgcpuweight; devstat->cpu.cgcpumax = curstat->cpu.cgcpumax; devstat->cpu.cgcpumaxr = curstat->cpu.cgcpumaxr; + devstat->cpu.nropen = curstat->cpu.nropen; if (curstat->cpu.wchan[0]) strcpy(devstat->cpu.wchan, curstat->cpu.wchan); diff --git a/json.c b/json.c index 2d4757b4..bdc942cd 100644 --- a/json.c +++ b/json.c @@ -1030,6 +1030,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac "\"blkdelay\": %lld, " "\"nvcsw\": %llu, " "\"nivcsw\": %llu, " + "\"nropen\": %d, " "\"sleepavg\": %d}", ps->gen.pid, ps->cpu.utime, @@ -1043,6 +1044,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac ps->cpu.blkdelay*1000/hertz, ps->cpu.nvcsw, ps->cpu.nivcsw, + ps->cpu.nropen, ps->cpu.sleepavg); } diff --git a/man/atop.1 b/man/atop.1 index c5a8ca2d..5368f852 100644 --- a/man/atop.1 +++ b/man/atop.1 @@ -1661,6 +1661,11 @@ Time that the process has been finished. If the process is still running, this field shows `active'. .PP .TP 9 +.B NROPEN +Current number of opened file descriptors (fds) for each process, at least 0. +As each thread has the same fds with its process, this filed shows `-`. +.PP +.TP 9 .B ENVID Virtual environment identified (OpenVZ only). .PP diff --git a/parseable.c b/parseable.c index 0cbca48b..fe9adcd7 100644 --- a/parseable.c +++ b/parseable.c @@ -785,7 +785,7 @@ print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact) for (i=0; i < nact; i++, ps++) { printf("%s %d %s %c %u %lld %lld %d %d %d %d %d %d %d %c " - "%llu %s %llu %d %d %llu %llu\n", + "%llu %s %llu %d %d %d %llu %llu\n", hp, ps->gen.pid, spaceformat(ps->gen.name, namout), @@ -804,6 +804,7 @@ print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact) ps->cpu.rundelay, spaceformat(ps->cpu.wchan, wchanout), ps->cpu.blkdelay, + ps->cpu.nropen, cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumax), cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumaxr), ps->cpu.nvcsw, diff --git a/photoproc.c b/photoproc.c index 5219f80d..c4b01a74 100644 --- a/photoproc.c +++ b/photoproc.c @@ -63,6 +63,7 @@ static int proccont(struct tstat *); static void proccmd(struct tstat *); static void procsmaps(struct tstat *); static void procwchan(struct tstat *); +static void procfd(struct tstat *); static count_t procschedstat(struct tstat *); static int proccgroupv2(struct tstat *); static struct cgroupv2vals * @@ -218,6 +219,8 @@ photoproc(struct tstat *tasklist, int maxtask) if (getwchan) procwchan(curtask); + procfd(curtask); + // read network stats from netatop netatop_gettask(curtask->gen.tgid, 'g', curtask); @@ -981,6 +984,38 @@ procschedstat(struct tstat *curtask) return curtask->cpu.rundelay; } +/* +** get current number of opened file descriptors for process +** to monitor if fd leaks. +** Considering users may set the max number of open files to +** a very large number, we regard MAX_OPEN to be 10000. +*/ +#define MAX_OPEN 10000 + +static void +procfd(struct tstat *curtask) +{ + DIR *dirp; + struct dirent *dentry; + int fd_num = 0; + + if ( (dirp = opendir("fd")) ) + { + while ( (dentry = readdir(dirp)) ) + { + if ( isdigit(dentry->d_name[0]) ) + fd_num++; + + if ( fd_num >= MAX_OPEN ) + break; + } + + curtask->cpu.nropen = fd_num; + + closedir(dirp); + } +} + /* ** CGROUP V2 specific items */ diff --git a/photoproc.h b/photoproc.h index b20e2654..2815dedd 100644 --- a/photoproc.h +++ b/photoproc.h @@ -82,7 +82,8 @@ struct tstat { int cgcpuweight; /* cgroup cpu.weight */ int cgcpumax; /* cgroup cpu.max percentage */ int cgcpumaxr; /* restrictive percentage */ - int ifuture[3]; /* reserved for future use */ + int nropen; /* number of opened files */ + int ifuture[2]; /* reserved for future use */ char wchan[16]; /* wait channel string */ count_t rundelay; /* schedstat rundelay (nanosec) */ count_t blkdelay; /* blkio delay (ticks) */ diff --git a/showlinux.c b/showlinux.c index 3d0b0947..185b19c6 100644 --- a/showlinux.c +++ b/showlinux.c @@ -423,6 +423,7 @@ proc_printdef *allprocpdefs[]= &procprt_STTIME, &procprt_ENDATE, &procprt_ENTIME, + &procprt_NROPEN, &procprt_THR, &procprt_TRUN, &procprt_TSLPI, @@ -1300,7 +1301,7 @@ priphead(int curlist, int totlist, char *showtype, char *showorder, "RUID:8 RGID:8 EUID:5 EGID:4 " "SUID:3 SGID:2 FSUID:3 FSGID:2 " "STDATE:7 STTIME:7 ENDATE:5 ENTIME:5 " - "ST:6 EXC:6 S:6 SORTITEM:10 CMD:10", + "NROPEN:5 ST:6 EXC:6 S:6 SORTITEM:10 CMD:10", "built-in varprocs"); make_proc_prints(cmdprocs, MAXITEMS, diff --git a/showlinux.h b/showlinux.h index f275a82a..87294548 100644 --- a/showlinux.h +++ b/showlinux.h @@ -418,6 +418,7 @@ extern proc_printdef procprt_STDATE; extern proc_printdef procprt_STTIME; extern proc_printdef procprt_ENDATE; extern proc_printdef procprt_ENTIME; +extern proc_printdef procprt_NROPEN; extern proc_printdef procprt_THR; extern proc_printdef procprt_TRUN; extern proc_printdef procprt_TSLPI; diff --git a/showprocs.c b/showprocs.c index da88d171..72bbe804 100644 --- a/showprocs.c +++ b/showprocs.c @@ -115,6 +115,8 @@ char *procprt_ENDATE_a(struct tstat *, int, int); char *procprt_ENDATE_e(struct tstat *, int, int); char *procprt_ENTIME_a(struct tstat *, int, int); char *procprt_ENTIME_e(struct tstat *, int, int); +char *procprt_NROPEN_a(struct tstat *, int, int); +char *procprt_NROPEN_e(struct tstat *, int, int); char *procprt_THR_a(struct tstat *, int, int); char *procprt_THR_e(struct tstat *, int, int); char *procprt_TRUN_a(struct tstat *, int, int); @@ -1235,6 +1237,32 @@ proc_printdef procprt_ENTIME = { " ENTIME ", "ENTIME", procprt_ENTIME_a, procprt_ENTIME_e, 8 }; /***************************************************************/ char * +procprt_NROPEN_a(struct tstat *curstat, int avgval, int nsecs) +{ + static char buf[64]; + + if (curstat->gen.isproc) + sprintf(buf, "%*d", procprt_NROPEN.width, curstat->cpu.nropen); + else + sprintf(buf, "%*s", procprt_NROPEN.width, "-"); + + return buf; +} + +char * +procprt_NROPEN_e(struct tstat *curstat, int avgval, int nsecs) +{ + static char buf[64]; + + sprintf(buf, "%*s", procprt_NROPEN.width, "-"); + + return buf; +} + +proc_printdef procprt_NROPEN = + { " NROPEN", "NROPEN", procprt_NROPEN_a, procprt_NROPEN_e, 7 }; +/***************************************************************/ +char * procprt_THR_a(struct tstat *curstat, int avgval, int nsecs) { static char buf[15];