CLion:2019.3.6
源码管理平台:Macbook Pro 10.12.6
C语言源码程序:Makefile格式的linux系统的top命令源码。
top所在的系统:ubuntu 14.04
一、源码导入
linux的top命令采用的是procps-ng项目,可以通过Clion 导入Makefile格式的C语言源程序:procps项目 这篇博客将源码进行下载和导入。
二、RES 指标的源码分析
1、输入top命令后显示如下:
对于RES指标, 代表PID进程占用的物理内存,其中包括共享库内存,RES的数据是怎么计算得来的呢,接下来我们将通过查看源码来了解这个数据的源头。
2、top的源码分析
top的源码位于top.c文件中:
top.c通过task_show如下进行获取res的数值,
/*
* Build the information for a single task row and
* display the results or return them to the caller. */
static const char *task_show (const WIN_t *q, const int idx) {
... 省略....
#define pages2K(n) (unsigned long)( (n) << Pg2K_shft )
... 省略....
// we must begin a row with a possible window number in mind...
*(rp = rbuf) = '\0';
if (Rc.mode_altscr) rp = scat(rp, " ");
... 省略....
for (x = 0; x < q->maxpflgs; x++) {
const char *cp = NULL;
FLG_t i = q->procflgs[x];
... 省略....
switch (i) {
... 省略....
case EU_MEM:
cp = scale_pcnt((float)pages2K(p->resident) * 100 / kb_main_total, W, Jn);
... 省略....
case EU_NMA:
cp = make_num(numa_node_of_cpu(p->processor), W, Jn, AUTOX_NO, 0);
break;
case EU_RES:
cp = scale_mem(S, pages2K(p->resident), W, Jn);
break;
case EU_SHR:
cp = scale_mem(S, pages2K(p->share), W, Jn);
break;
case EU_SWP:
cp = scale_mem(S, p->vm_swap, W, Jn);
break;
... 省略....
default: // keep gcc happy
continue;
} // end: switch 'procflag'
#undef pages2K
} // end: task_show
其中RES获取的片段如下:
其中p->resident 是res的数据源,p的结构:
proc_t *p = q->ppt[idx];
其中proc_t的结构体主要内容如下所示:
// Basic data structure which holds all information we can get about a process.
// (unless otherwise specified, fields are read from /proc/#/stat)
//
// Most of it comes from task_struct in linux/sched.h
//
typedef struct proc_t {
// 1st 16 bytes
int
tid, // (special) task id, the POSIX thread ID (see also: tgid)
ppid; // stat,status pid of parent process
unsigned long // next 2 fields are NOT filled in by readproc
..........省略.........
long
priority, // stat kernel scheduling priority
nice, // stat standard unix nice level of process
rss, // stat identical to 'resident'
alarm, // stat ?
// the next 7 members come from /proc/#/statm
size, // statm total virtual memory (as # pages)
resident, // statm resident non-swapped memory (as # pages)
share, // statm shared (mmap'd) memory (as # pages)
trs, // statm text (exe) resident set (as # pages)
lrs, // statm library resident set (always 0 w/ 2.6)
drs, // statm data+stack resident set (as # pages)
dt; // statm dirty pages (always 0 w/ 2.6)
unsigned long
vm_size, // status equals 'size' (as kb)
vm_lock, // status locked pages (as kb)
vm_rss, // status equals 'rss' and/or 'resident' (as kb)
vm_rss_anon, // status the 'anonymous' portion of vm_rss (as kb)
vm_rss_file, // status the 'file-backed' portion of vm_rss (as kb)
vm_rss_shared, // status the 'shared' portion of vm_rss (as kb)
vm_data, // status data only size (as kb)
vm_stack, // status stack only size (as kb)
vm_swap, // status based on linux-2.6.34 "swap ents" (as kb)
..........省略.........
const char
*lxcname; // n/a lxc container name
} proc_t;
所以top的res是从proc_t->resident获取的,其中resident的单位是页面,是通过pages2K将页面数量转换成字节数, 页面的大小是4K:
case EU_RES:
cp = scale_mem(S, pages2K(p->resident), W, Jn);
其中pages2K函数:
/* The run-time acquired page stuff */
static unsigned Pg2K_shft = 0;
// get virtual page stuff
i = page_bytes; // from sysinfo.c, at lib init
while(i > 1024) { i >>= 1; Pg2K_shft++; }
#define pages2K(n) (unsigned long)( (n) << Pg2K_shft )
如上所示:q->ppt[idx]又是从哪儿初始化的呢?
如下代码所示:q作为task_show函数传递进来:
static const char *task_show (const WIN_t *q, const int idx) {
WIN_t的结构定义如下:
/* This structure stores configurable information for each window.
By expending a little effort in its creation and user requested
maintenance, the only real additional per frame cost of having
windows is an extra sort -- but that's just on pointers! */
typedef struct WIN_t {
FLG_t pflgsall [PFLAGSSIZ], // all 'active/on' fieldscur, as enum
procflgs [PFLAGSSIZ]; // fieldscur subset, as enum
RCW_t rc; // stuff that gets saved in the rcfile
int winnum, // a window's number (array pos + 1)
winlines, // current task window's rows (volatile)
maxpflgs, // number of displayed procflgs ("on" in fieldscur)
totpflgs, // total of displayable procflgs in pflgsall array
begpflg, // scrolled beginning pos into pflgsall array
endpflg, // scrolled ending pos into pflgsall array
begtask, // scrolled beginning pos into Frame_maxtask
begnext, // new scrolled delta for next frame's begtask
#ifndef SCROLLVAR_NO
varcolbeg, // scrolled position within variable width col
#endif
varcolsz, // max length of variable width column(s)
usrseluid, // validated uid for 'u/U' user selection
usrseltyp, // the basis for matching above uid
usrselflg, // flag denoting include/exclude matches
hdrcaplen; // column header xtra caps len, if any
char capclr_sum [CLRBUFSIZ], // terminfo strings built from
capclr_msg [CLRBUFSIZ], // RCW_t colors (& rebuilt too),
capclr_pmt [CLRBUFSIZ], // but NO recurring costs !
capclr_hdr [CLRBUFSIZ], // note: sum, msg and pmt strs
capclr_rowhigh [CLRBUFSIZ], // are only used when this
capclr_rownorm [CLRBUFSIZ], // window is the 'Curwin'!
cap_bold [CAPBUFSIZ], // support for View_NOBOLD toggle
grpname [GRPNAMSIZ], // window number:name, printable
#ifdef USE_X_COLHDR
columnhdr [ROWMINSIZ], // column headings for procflgs
#else
columnhdr [SCREENMAX], // column headings for procflgs
#endif
*captab [CAPTABMAX]; // captab needed by show_special()
struct osel_s *osel_1st; // other selection criteria anchor
int osel_tot; // total of other selection criteria
char *findstr; // window's current/active search string
int findlen; // above's strlen, without call overhead
proc_t **ppt; // this window's proc_t ptr array
struct WIN_t *next, // next window in window stack
*prev; // prior window in window stack
} WIN_t;
关键的代码在readproc.c,如下代码所示:
//
// This reads process info from /proc in the traditional way, for one process.
// The pid (tgid? tid?) is already in p, and a path to it in path, with some
// room to spare.
static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
......省略.......
if (flags & PROC_FILLMEM) { // read /proc/#/statm
if (likely(file2str(path, "statm", &ub) != -1))
statm2proc(ub.buf, p);
}
......省略.......
其中statm2proc的函数实现如下:
static void statm2proc(const char* s, proc_t *restrict P) {
sscanf(s, "%ld %ld %ld %ld %ld %ld %ld",
&P->size, &P->resident, &P->share,
&P->trs, &P->lrs, &P->drs, &P->dt);
}
可以看出,top的RES是从/proc/pid/statm文件中格式化读出来的。
版权声明:本文为whbing1471原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。