Skip to content

Commit

Permalink
Collect nropen for each process to monitor if fd leaks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
ShirleyFei committed Dec 7, 2022
1 parent d8d97f9 commit ea3b338
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 3 deletions.
1 change: 1 addition & 0 deletions deviate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions json.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
}

Expand Down
5 changes: 5 additions & 0 deletions man/atop.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion parseable.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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));
}
Expand Down
57 changes: 57 additions & 0 deletions photoproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
** --------------------------------------------------------------------------
*/

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
*/
Expand Down
3 changes: 2 additions & 1 deletion photoproc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand Down
3 changes: 2 additions & 1 deletion showlinux.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ proc_printdef *allprocpdefs[]=
&procprt_STTIME,
&procprt_ENDATE,
&procprt_ENTIME,
&procprt_NROPEN,
&procprt_THR,
&procprt_TRUN,
&procprt_TSLPI,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions showlinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions showprocs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down

0 comments on commit ea3b338

Please sign in to comment.