diff --git a/deviate.c b/deviate.c index e51325fe..be3cb774 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 382d6a48..7d327ef6 100644 --- a/json.c +++ b/json.c @@ -976,6 +976,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac "\"isproc\": %d, " "\"rundelay\": %lld, " "\"blkdelay\": %lld, " + "\"nropen\": %d, " "\"sleepavg\": %d}", ps->gen.pid, ps->cpu.utime, @@ -987,6 +988,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac !!ps->gen.isproc, ps->cpu.rundelay/1000000, ps->cpu.blkdelay*1000/hertz, + ps->cpu.nropen, ps->cpu.sleepavg); } diff --git a/man/atop.1 b/man/atop.1 index 039a673d..b22f1e07 100644 --- a/man/atop.1 +++ b/man/atop.1 @@ -1660,6 +1660,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 d5258918..c90d2766 100644 --- a/parseable.c +++ b/parseable.c @@ -770,7 +770,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\n", + "%llu %s %llu %d %d %d\n", hp, ps->gen.pid, spaceformat(ps->gen.name, namout), @@ -789,6 +789,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)); } diff --git a/photoproc.c b/photoproc.c index 68912bd0..39fe5ced 100644 --- a/photoproc.c +++ b/photoproc.c @@ -31,11 +31,14 @@ ** -------------------------------------------------------------------------- */ +#define _GNU_SOURCE #include #include +#include #include #include #include +#include #include #include #include @@ -63,6 +66,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 +222,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); @@ -955,6 +961,57 @@ 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 use getdents[64] SYSCALL directly +** instead of glibc's readdir() for performance consideration. +** Also, define MAX_OPEN to be 1024 * 1024 for display. +*/ +struct linux_dirent64 { + unsigned long d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; +}; + +#define MAX_OPEN 1024 * 1024 + +static void +procfd(struct tstat *curtask) +{ + int fd, nread, fd_num = 0; + struct linux_dirent64 *buf, *d; + unsigned int count = 0; + + if ( (fd = open("fd", O_RDONLY | O_DIRECTORY)) != -1) { + count = MAX_OPEN * sizeof(struct linux_dirent64); + buf = malloc(count); + ptrverify(buf, "Malloc failed for process's opened files\n"); + + nread = syscall(SYS_getdents64, fd, buf, count); + if (nread == -1) { + curtask->cpu.nropen = -1; + } else if (nread == 0) { + curtask->cpu.nropen = 0; + } else if (nread > 0) { + for (int bops = 0; bops < nread;) { + d = (struct linux_dirent64 *)((char *)buf + bops); + bops += d->d_reclen; + fd_num++; + } + curtask->cpu.nropen = fd_num - 2; + } + + close(fd); + free(buf); + } else { + curtask->cpu.nropen = 0; + } +} + /* ** CGROUP V2 specific items */ diff --git a/photoproc.h b/photoproc.h index 56d6e48d..80859ac6 100644 --- a/photoproc.h +++ b/photoproc.h @@ -79,7 +79,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 1172f03e..6f714b00 100644 --- a/showlinux.c +++ b/showlinux.c @@ -644,6 +644,7 @@ proc_printdef *allprocpdefs[]= &procprt_STTIME, &procprt_ENDATE, &procprt_ENTIME, + &procprt_NROPEN, &procprt_THR, &procprt_TRUN, &procprt_TSLPI, @@ -1519,7 +1520,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 ea92deb0..3f8e8995 100644 --- a/showlinux.h +++ b/showlinux.h @@ -392,6 +392,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 4eb5fe99..384f8f22 100644 --- a/showprocs.c +++ b/showprocs.c @@ -1103,6 +1103,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];