Skip to content

Commit ea3b338

Browse files
committed
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 use getdents[64] SYSCALL directly to get fd numbers instead of glibc's readdir() for performance consideration. Also, define MAX_OPEN to be 1024 * 1024 for display even if the fd numbers may exceed 1024 * 1024. Signed-off-by: Fei Li <lifei.shirley@bytedance.com>
1 parent d8d97f9 commit ea3b338

File tree

9 files changed

+98
-3
lines changed

9 files changed

+98
-3
lines changed

deviate.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ calcdiff(struct tstat *devstat, const struct tstat *curstat,
455455
devstat->cpu.cgcpuweight = curstat->cpu.cgcpuweight;
456456
devstat->cpu.cgcpumax = curstat->cpu.cgcpumax;
457457
devstat->cpu.cgcpumaxr = curstat->cpu.cgcpumaxr;
458+
devstat->cpu.nropen = curstat->cpu.nropen;
458459

459460
if (curstat->cpu.wchan[0])
460461
strcpy(devstat->cpu.wchan, curstat->cpu.wchan);

json.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac
976976
"\"isproc\": %d, "
977977
"\"rundelay\": %lld, "
978978
"\"blkdelay\": %lld, "
979+
"\"nropen\": %d, "
979980
"\"sleepavg\": %d}",
980981
ps->gen.pid,
981982
ps->cpu.utime,
@@ -987,6 +988,7 @@ static void json_print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nac
987988
!!ps->gen.isproc,
988989
ps->cpu.rundelay/1000000,
989990
ps->cpu.blkdelay*1000/hertz,
991+
ps->cpu.nropen,
990992
ps->cpu.sleepavg);
991993
}
992994

man/atop.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,11 @@ Time that the process has been finished. If the process is still running,
16601660
this field shows `active'.
16611661
.PP
16621662
.TP 9
1663+
.B NROPEN
1664+
Current number of opened file descriptors (fds) for each process, at least 0.
1665+
As each thread has the same fds with its process, this filed shows `-`.
1666+
.PP
1667+
.TP 9
16631668
.B ENVID
16641669
Virtual environment identified (OpenVZ only).
16651670
.PP

parseable.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact)
770770
for (i=0; i < nact; i++, ps++)
771771
{
772772
printf("%s %d %s %c %u %lld %lld %d %d %d %d %d %d %d %c "
773-
"%llu %s %llu %d %d\n",
773+
"%llu %s %llu %d %d %d\n",
774774
hp,
775775
ps->gen.pid,
776776
spaceformat(ps->gen.name, namout),
@@ -789,6 +789,7 @@ print_PRC(char *hp, struct sstat *ss, struct tstat *ps, int nact)
789789
ps->cpu.rundelay,
790790
spaceformat(ps->cpu.wchan, wchanout),
791791
ps->cpu.blkdelay,
792+
ps->cpu.nropen,
792793
cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumax),
793794
cgroupv2max(ps->gen.isproc, ps->cpu.cgcpumaxr));
794795
}

photoproc.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,14 @@
3131
** --------------------------------------------------------------------------
3232
*/
3333

34+
#define _GNU_SOURCE
3435
#include <sys/types.h>
3536
#include <sys/param.h>
37+
#include <sys/syscall.h>
3638
#include <dirent.h>
3739
#include <stdio.h>
3840
#include <string.h>
41+
#include <fcntl.h>
3942
#include <unistd.h>
4043
#include <ctype.h>
4144
#include <time.h>
@@ -63,6 +66,7 @@ static int proccont(struct tstat *);
6366
static void proccmd(struct tstat *);
6467
static void procsmaps(struct tstat *);
6568
static void procwchan(struct tstat *);
69+
static void procfd(struct tstat *);
6670
static count_t procschedstat(struct tstat *);
6771
static int proccgroupv2(struct tstat *);
6872
static struct cgroupv2vals *
@@ -218,6 +222,8 @@ photoproc(struct tstat *tasklist, int maxtask)
218222
if (getwchan)
219223
procwchan(curtask);
220224

225+
procfd(curtask);
226+
221227
// read network stats from netatop
222228
netatop_gettask(curtask->gen.tgid, 'g', curtask);
223229

@@ -955,6 +961,57 @@ procschedstat(struct tstat *curtask)
955961
return curtask->cpu.rundelay;
956962
}
957963

964+
/*
965+
** get current number of opened file descriptors for process
966+
** to monitor if fd leaks.
967+
** Considering users may set the max number of open files to
968+
** a very large number, we use getdents[64] SYSCALL directly
969+
** instead of glibc's readdir() for performance consideration.
970+
** Also, define MAX_OPEN to be 1024 * 1024 for display.
971+
*/
972+
struct linux_dirent64 {
973+
unsigned long d_ino;
974+
off_t d_off;
975+
unsigned short d_reclen;
976+
unsigned char d_type;
977+
char d_name[];
978+
};
979+
980+
#define MAX_OPEN 1024 * 1024
981+
982+
static void
983+
procfd(struct tstat *curtask)
984+
{
985+
int fd, nread, fd_num = 0;
986+
struct linux_dirent64 *buf, *d;
987+
unsigned int count = 0;
988+
989+
if ( (fd = open("fd", O_RDONLY | O_DIRECTORY)) != -1) {
990+
count = MAX_OPEN * sizeof(struct linux_dirent64);
991+
buf = malloc(count);
992+
ptrverify(buf, "Malloc failed for process's opened files\n");
993+
994+
nread = syscall(SYS_getdents64, fd, buf, count);
995+
if (nread == -1) {
996+
curtask->cpu.nropen = -1;
997+
} else if (nread == 0) {
998+
curtask->cpu.nropen = 0;
999+
} else if (nread > 0) {
1000+
for (int bops = 0; bops < nread;) {
1001+
d = (struct linux_dirent64 *)((char *)buf + bops);
1002+
bops += d->d_reclen;
1003+
fd_num++;
1004+
}
1005+
curtask->cpu.nropen = fd_num - 2;
1006+
}
1007+
1008+
close(fd);
1009+
free(buf);
1010+
} else {
1011+
curtask->cpu.nropen = 0;
1012+
}
1013+
}
1014+
9581015
/*
9591016
** CGROUP V2 specific items
9601017
*/

photoproc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ struct tstat {
7979
int cgcpuweight; /* cgroup cpu.weight */
8080
int cgcpumax; /* cgroup cpu.max percentage */
8181
int cgcpumaxr; /* restrictive percentage */
82-
int ifuture[3]; /* reserved for future use */
82+
int nropen; /* number of opened files */
83+
int ifuture[2]; /* reserved for future use */
8384
char wchan[16]; /* wait channel string */
8485
count_t rundelay; /* schedstat rundelay (nanosec) */
8586
count_t blkdelay; /* blkio delay (ticks) */

showlinux.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ proc_printdef *allprocpdefs[]=
644644
&procprt_STTIME,
645645
&procprt_ENDATE,
646646
&procprt_ENTIME,
647+
&procprt_NROPEN,
647648
&procprt_THR,
648649
&procprt_TRUN,
649650
&procprt_TSLPI,
@@ -1519,7 +1520,7 @@ priphead(int curlist, int totlist, char *showtype, char *showorder,
15191520
"RUID:8 RGID:8 EUID:5 EGID:4 "
15201521
"SUID:3 SGID:2 FSUID:3 FSGID:2 "
15211522
"STDATE:7 STTIME:7 ENDATE:5 ENTIME:5 "
1522-
"ST:6 EXC:6 S:6 SORTITEM:10 CMD:10",
1523+
"NROPEN:5 ST:6 EXC:6 S:6 SORTITEM:10 CMD:10",
15231524
"built-in varprocs");
15241525

15251526
make_proc_prints(cmdprocs, MAXITEMS,

showlinux.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ extern proc_printdef procprt_STDATE;
392392
extern proc_printdef procprt_STTIME;
393393
extern proc_printdef procprt_ENDATE;
394394
extern proc_printdef procprt_ENTIME;
395+
extern proc_printdef procprt_NROPEN;
395396
extern proc_printdef procprt_THR;
396397
extern proc_printdef procprt_TRUN;
397398
extern proc_printdef procprt_TSLPI;

showprocs.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,32 @@ proc_printdef procprt_ENTIME =
11031103
{ " ENTIME ", "ENTIME", procprt_ENTIME_a, procprt_ENTIME_e, 8 };
11041104
/***************************************************************/
11051105
char *
1106+
procprt_NROPEN_a(struct tstat *curstat, int avgval, int nsecs)
1107+
{
1108+
static char buf[64];
1109+
1110+
if (curstat->gen.isproc)
1111+
sprintf(buf, "%*d", procprt_NROPEN.width, curstat->cpu.nropen);
1112+
else
1113+
sprintf(buf, "%*s", procprt_NROPEN.width, "-");
1114+
1115+
return buf;
1116+
}
1117+
1118+
char *
1119+
procprt_NROPEN_e(struct tstat *curstat, int avgval, int nsecs)
1120+
{
1121+
static char buf[64];
1122+
1123+
sprintf(buf, "%*s", procprt_NROPEN.width, "-");
1124+
1125+
return buf;
1126+
}
1127+
1128+
proc_printdef procprt_NROPEN =
1129+
{ " NROPEN", "NROPEN", procprt_NROPEN_a, procprt_NROPEN_e, 7 };
1130+
/***************************************************************/
1131+
char *
11061132
procprt_THR_a(struct tstat *curstat, int avgval, int nsecs)
11071133
{
11081134
static char buf[15];

0 commit comments

Comments
 (0)