bash top second_line - ceragon/LinuxDoc GitHub Wiki
top - 10:49:30 up 4 days, 13:08, 1 user, load average: 0.10, 0.28, 0.20
任务: 306 total, 1 running, 304 sleeping, 0 stopped, 1 zombie
%Cpu(s): 3.5 us, 1.4 sy, 0.0 ni, 95.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 15897.9 total, 235.3 free, 8007.0 used, 7655.7 buff/cache
MiB Swap: 2048.0 total, 1687.5 free, 360.5 used. 7403.8 avail Mem
进程号 USER PR NI VIRT RES SHR %CPU %MEM TIME+ COMMAND
446465 ceragon 20 0 11.7g 5.1g 535188 S 25.0 33.0 38:23.92 ld-linux-x86-64
517659 ceragon 20 0 15112 3984 3204 R 12.5 0.0 0:00.02 top
452 root -51 0 0 0 0 S 6.2 0.0 0:52.38 irq/168-iwlwifi
328018 ceragon 20 0 11.7g 2.4g 465028 S 6.2 15.2 69:05.34 ld-linux-x86-64
1 root 20 0 169256 11512 6604 S 0.0 0.1 0:09.36 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.09 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp
任务: 306 total, 1 running, 304 sleeping, 0 stopped, 1 zombie
const char *Uniq_nlstab[uniq_MAX];
static void build_uniq_nlstab (void) {
Uniq_nlstab[STATE_line_1_fmt] = _("%s:~3"
" %3u ~2total,~3 %3u ~2running,~3 %3u ~2sleeping,~3 %3u ~2stopped,~3 %3u ~2zombie~3\n");
}const char *Norm_nlstab[norm_MAX];
static void build_norm_nlstab (void) {
Norm_nlstab[WORD_process_txt] = _("Tasks");
}static void summary_show (void) {
// 作用就是把内容格式化输出
show_special(0, fmtmk(N_unq(STATE_line_1_fmt)
, Thread_mode ? N_txt(WORD_threads_txt) : N_txt(WORD_process_txt)
, Frame_maxtask, Frame_running, Frame_sleepin
, Frame_stopped, Frame_zombied));
}信息的显示只是读取全局变量的值,赋值的位置另有地方。找到了下面的位置,可以看到是定时刷新的。
int main (int dont_care_argc, char **argv) {
for (;;) {
frame_make();
}
}static void frame_make (void) {
if (Pseudo_row == PROC_XTRA) {
procs_refresh();
}
}用于刷新当前的任务状态
static int Frames_libflags; // PROC_FILLxxx flags
static pid_t Monpids [MONPIDMAX+1] = { 0 };
static int Thread_mode = 0, // set w/ 'H' - show threads via readeither();
static void procs_refresh (void) {
static proc_t **private_ppt;
PROCTAB* PT;
proc_t *(*read_something)(PROCTAB*, proc_t *);
procs_hlp(NULt);
PT = openproc(Frames_libflags, Monpids);
// 如果加入了 -H 参数 Thread_mode 会变为 true
read_something = Thread_mode ? readeither : readproc;
for (;;) {
if (!(ptask = read_something(PT, private_ppt[n_used]))) break;
procs_hlp((private_ppt[n_used] = ptask)); // tally this proc_t
}
}用于初始化
static int Frame_maxtask;
static unsigned Frame_running,
Frame_sleepin,
Frame_stopped,
Frame_zombied;
static void procs_hlp (proc_t *this) {
Frame_maxtask = Frame_running = Frame_sleepin = Frame_stopped = Frame_zombied = 0;
}用于遍历每个 task
proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
// 参数p:上一次选择的节点
proc_t *ret;
for(;;){
if (!PT->finder(PT,p)) break;
ret = PT->reader(PT,p);
if(ret) return ret;
}
return NULL;
}#define PROC_PID 0x1000
#define PROC_FILLSTAT 0x0040
PROCTAB* openproc(int flags, ...) {
// flags 的默认值是 PROC_FILLSTAT
PT->reader = simple_readproc;
if (flags & PROC_PID){
} else {
PT->procfs = opendir("/proc");
PT->finder = simple_nextpid;
}
}finder,用于遍历下一个 task
static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
static struct dirent *ent;
char *restrict const path = PT->path;
for (;;) {
// 会从 /proc 目录下读取内容,这个目录下有所有运行中的进程。每调用一次,都会返回下一个文件
// ======= 调用 glibc 的方法 readdir
ent = readdir(PT->procfs);
// 说明找不到下一个了
if(!ent || !ent->d_name[0]) return 0;
// 只要 d_name 是纯数字,啧说明是一个运行中的进程
if(*ent->d_name > '0' && *ent->d_name <= '9') break;
}
// 将字符串 /proc/# 保存到 PT->path 中
snprintf(path, PROCPATHLEN, "/proc/%s", ent->d_name);
return 1;
}reader,主要作用是读取进程的 stat 信息
$ cat 9/stat
9 (mm_percpu_wq) I 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 15 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
static struct utlbuf_s ub = { NULL, 0 };
char *restrict const path = PT->path;
unsigned flags = PT->flags;
if (flags & PROC_FILLSTAT) { // read /proc/#/stat
file2str(path, "stat", &ub);
stat2proc(ub.buf, p);
}
return p;
}static void stat2proc(const char* S, proc_t *restrict P) {
S = strchr(S, '(');
S++;
tmp = strrchr(S, ')');
S = tmp + 2; // skip ") "
// 以上图为例,读取到的 stat 是 I
sscanf(S,
"%c "
&P->state);
}根据进程的状态统计数据,包括全部进程数量、运行中的数量、睡眠的数量、停止的数量、僵尸状态数量。
static int Frame_maxtask;
static unsigned Frame_running,
Frame_sleepin,
Frame_stopped,
Frame_zombied;
static void procs_hlp (proc_t *this) {
switch (this->state) {
case 'R':
Frame_running++;
break;
case 't': // 't' (tracing stop)
case 'T':
Frame_stopped++;
break;
case 'Z':
Frame_zombied++;
break;
default:
/* currently: 'D' (disk sleep),
'I' (idle),
'P' (parked),
'S' (sleeping),
'X' (dead - actually 'dying' & probably never seen)
*/
Frame_sleepin++;
break;
}
Frame_maxtask++;
}