bash top second_line - ceragon/LinuxDoc GitHub Wiki

top second line

完整日志

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
    }
}

procs_hlp(null)

用于初始化

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;
}

默认 read task

用于遍历每个 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);
}

procs_hlp(ptask)

根据进程的状态统计数据,包括全部进程数量、运行中的数量、睡眠的数量、停止的数量、僵尸状态数量。

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++;
}
⚠️ **GitHub.com Fallback** ⚠️