bash top fifth_line - ceragon/LinuxDoc GitHub Wiki

top fifth 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

信息显示

内容

 进程号 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                                                                                                  

header 显示

显示内容

其中 columnhdr 就是 header 的名称,下面代码用于显示

static int window_show (WIN_t *q, int wmax) {
    PUFF("\n%s%s%s", q->capclr_hdr, q->columnhdr, Caps_endline);
}

赋值逻辑

const char *Head_nlstab[EU_MAXPFLGS];
const char *Desc_nlstab[EU_MAXPFLGS];
static void build_two_nlstabs (void) {
    Head_nlstab[EU_PID] = _("PID");
    Desc_nlstab[EU_PID] = _("Process Id");
    Head_nlstab[EU_UEN] = _("USER");
    Desc_nlstab[EU_UEN] = _("Effective User Name");
    Head_nlstab[EU_PRI] = _("PR");
    Desc_nlstab[EU_PRI] = _("Priority");
    Head_nlstab[EU_NCE] = _("NI");
    Desc_nlstab[EU_NCE] = _("Nice Value");
    Head_nlstab[EU_VRT] = _("VIRT");
    Desc_nlstab[EU_VRT] = _("Virtual Image (KiB)");
    Head_nlstab[EU_RES] = _("RES");
    Desc_nlstab[EU_RES] = _("Resident Size (KiB)");
    Head_nlstab[EU_SHR] = _("SHR");
    Desc_nlstab[EU_SHR] = _("Shared Memory (KiB)");
    Head_nlstab[EU_CPU] = _("%CPU");
    Desc_nlstab[EU_CPU] = _("CPU Usage");
    Head_nlstab[EU_MEM] = _("%MEM");
    Desc_nlstab[EU_MEM] = _("Memory Usage (RES)");
    Head_nlstab[EU_TM2] = _("TIME+");
    Desc_nlstab[EU_TM2] = _("CPU Time, hundredths");
    Head_nlstab[EU_CMD] = _("COMMAND");
    Desc_nlstab[EU_CMD] = _("Command Name/Line");
}
static WIN_t *Curwin;
static void build_headers (void) {
    FLG_t f;
    char *s;
    WIN_t *w = Curwin;
    // 重置 columnhdr,且将指针赋值给 s
    memset((s = w->columnhdr), 0, sizeof(w->columnhdr));
    for (i = 0; i < w->maxpflgs; i++) {
        f = w->procflgs[i];
        if (EU_MAXPFLGS <= f) continue;
        // 将 f 对应的列名称追加到 s 后面
        s = scat(s, utf8_justify(N_col(f) // 作用是从 Head_nlstab 中取出对应的值
               , VARcol(f) ? w->varcolsz : Fieldstab[f].width // 取出列宽
               , CHKw(w, Fieldstab[f].align))); // 对齐
    }
}

进程信息显示

static int window_show (WIN_t *q, int wmax) {
    int i, lwin;
    // 进程排序,截取前 Frame_maxtask 个
    qsort(q->ppt, Frame_maxtask, sizeof(proc_t *), Fieldstab[q->rc.sortindx].sort);
    while (i < Frame_maxtask && lwin < wmax) {
        if ((CHKw(q, Show_IDLEPS) || isBUSY(q->ppt[i]))
                && wins_usrselect(q, i) // 过滤掉当前用户不可见的进程
                && *task_show(q, i)){   // 显示进程信息
            ++lwin;
        }
        ++i;
    }
}
static float        Frame_etscale;
static const char *task_show (const WIN_t *q, const int idx) {
    static char rbuf[ROWMINSIZ];
    char *rp;
    proc_t *p = q->ppt[idx];
    *(rp = rbuf) = '\0';
    for (x = 0; x < q->maxpflgs; x++) {
        FLG_t       i = q->procflgs[x];
        switch (i) {
            case EU_PID:
                // pid 取的是 proc 的 tid
                cp = make_num(p->tid, W, Jn, AUTOX_NO, 0);
                break;
            case EU_UEN:
                // 进程对应的用户名,对应的是 euser
                cp = make_str_utf8(p->euser, W, Js, EU_UEN);
                break;  
            case EU_PRI:
                if (-99 > p->priority || 999 < p->priority) {
                    // 实时进程
                   cp = make_str("rt", W, Jn, AUTOX_NO);
                } else
                    // 优先级对应的是 priority
                   cp = make_num(p->priority, W, Jn, AUTOX_NO, 0);
                break;
            case EU_NCE:
                // nice 对应的是 nice
                cp = make_num(p->nice, W, Jn, AUTOX_NO, 1);
                break;
            case EU_VRT:
                // 虚拟地址空间占用,p->size 对应的是页数,需要转换成 kb,默认一页是 4kb
                cp = scale_mem(S, pages2K(p->size), W, Jn);
                break;
            case EU_RES:
                // 物理内存占用, 对应的是 resident,也是以页为单位
                cp = scale_mem(S, pages2K(p->resident), W, Jn);
                break;
            case EU_SHR:
                // share memory 占用,以页为单位
                cp = scale_mem(S, pages2K(p->share), W, Jn);
                break;  
            case EU_CPU: {
                // 进程一段时间内的 CPU 占用,对应 pcpu
                float u = (float)p->pcpu;    
                // u 是权重,需要转换成百分比
                u *= Frame_etscale;
                if (p->pad_2 != 'x' && u > 100.0 * p->nlwp) u = 100.0 * p->nlwp;
                if (u > Cpu_pmax) u = Cpu_pmax;
                // 打印数值
                cp = scale_pcnt(u, W, Jn);
            }   break;
            case EU_MEM:
                // 内存占用的百分比,物理内存。
                cp = scale_pcnt((float)pages2K(p->resident) * 100 / kb_main_total, W, Jn);
                break;
            case EU_TM2:
            case EU_TME:
            {  
                // 显示占用 CPU 的总时长
                TIC_t t = p->utime + p->stime;
                if (CHKw(q, Show_CTIMES)) t += (p->cutime + p->cstime);
                // 将时间显示成,小时:分钟.秒的形式
                cp = scale_tics(t, W, Jn);
            }
                break;    
            case EU_CMD:
                // 就是显示 p->cmd 的值
                makeVAR(forest_display(q, p));
                break;
        }
    }
}
static inline const char *forest_display (const WIN_t *q, const proc_t *p) {
    // 默认取的是 cmd
    const char *which = (CHKw(q, Show_CMDLIN)) ? *p->cmdline : p->cmd;
    return which;
}

进程信息赋值

赋值分成了多个部分,包括 status、stat、statm

整体

static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
    if (likely(file2str(path, "status", &ub) != -1)){
        status2proc(ub.buf, p, 1);
    }
    if (flags & PROC_FILLUSR){
        memcpy(p->euser, pwcache_get_user(p->euid), sizeof p->euser);
    }
}

status 赋值

内容示例

$ cat 9/status
Name:   migration/6
Umask:  0000
State:  S (sleeping)
Tgid:   49
Ngid:   0
Pid:    49
PPid:   2
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 64
Groups:  
NStgid: 49
NSpid:  49
NSpgid: 0
NSsid:  0
Threads:        1
SigQ:   0/63332
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: ffffffffffffffff
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
Seccomp_filters:        0
Speculation_Store_Bypass:       thread vulnerable
SpeculationIndirectBranch:      conditional enabled
Cpus_allowed:   40
Cpus_allowed_list:      6
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        40116
nonvoluntary_ctxt_switches:     0

代码处理

static void status2proc(char *S, proc_t *restrict P, int is_proc){
    long Pid = 0;
    for(;;){
         S = strchr(S, '\n');
         S++;
    case_Pid:
        Pid = strtol(S,&S,10);
        continue;
    case_Uid:
        P->ruid = strtol(S,&S,10);  // real
        P->euid = strtol(S,&S,10);  // effective
        P->suid = strtol(S,&S,10);  // save
        P->fuid = strtol(S,&S,10);  // fs
        continue;
    }
    P->tid  = Pid;
}

statm 赋值

$ cat statm 
369999 29154 8446 6582 0 313423 0
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);
}

stat 赋值

$ cat /proc/139852/stat
139852 (ld-linux-x86-64) S 139837 139710 139710 0 -1 1077936128 1127692 22574 227 0 45001 1235 26 24 20 0 89 0 47134877 12416512000 1186077 18446744073709551615 139807025864704 139807026005620 140735476211296 0 0 0 0 4097 16796878 0 0 0 17 6 0 0 0 0 0 139807026046240 139807026053112 93825015668736 140735476219468 140735476225946 140735476225946 140735476228060 0
static void stat2proc(const char* S, proc_t *restrict P) {
    size_t num;
    char* tmp;
    S = strchr(S, '(');
    S++;
    tmp = strrchr(S, ')');
    num = tmp - S;
    // 给 cmd 赋值
    memcpy(P->cmd, S, num);
    S = tmp + 2;                 // skip ") "
    sscanf(S,
       "%c "
       "%d %d %d %d %d "
       "%lu %lu %lu %lu %lu "
       "%llu %llu %llu %llu "  /* utime stime cutime cstime */
       "%ld %ld "
       "%d "
       "%ld "
       "%llu "  /* start_time */
       "%lu "
       "%ld "
       "%lu %"KLF"u %"KLF"u %"KLF"u %"KLF"u %"KLF"u "
       "%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */
       "%"KLF"u %*u %*u "
       "%d %d "
       "%lu %lu",
       &P->state,
       &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
       &P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
       // 进程自己的 utime 和 stime,最后相加得到 pcpu
       &P->utime, &P->stime, &P->cutime, &P->cstime,
       // 优先级赋值, nice 值赋值
       &P->priority, &P->nice,
       &P->nlwp,
       &P->alarm,
       &P->start_time,
       &P->vsize,
       &P->rss,
       &P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp, &P->kstk_eip,
/*     P->signal, P->blocked, P->sigignore, P->sigcatch,   */ /* can't use */
       &P->wchan, /* &P->nswap, &P->cnswap, */  /* nswap and cnswap dead for 2.4.xx and up */
/* -- Linux 2.0.35 ends here -- */
       &P->exit_signal, &P->processor,  /* 2.2.1 ends with "exit_signal" */
/* -- Linux 2.2.8 to 2.5.17 end here -- */
       &P->rtprio, &P->sched  /* both added to 2.5.18 */
    );
}

关键值总结

VIRT

statm 中的第一个值

RES

statm 中的第二个值

SHR

statm 中的第三个值

%CPU

(utime + stime)/

// 历史记录结构体
typedef struct HST_t {
   TIC_t tics;                  // last frame's tics count
   unsigned long maj, min;      // last frame's maj/min_flt counts
   int pid;                     // record 'key'
   int lnk;                     // next on hash chain
} HST_t;
static float        Frame_etscale; 
extern unsigned long long Hertz;   /* clock tick frequency */
// 通过 /proc/stat 可以获取该值
extern long smp_num_cpus;          /* number of CPUs */
static void procs_hlp (proc_t *this) {
    // 无符号的 long
    TIC_t tics;
    HST_t *h;
    if (!this) {
        static double uptime_sav;
        double uptime_cur;
        float et;
        // 获取操作系统的运行持续时间
        uptime(&uptime_cur, NULL);
        // 距离上次计算的时间差值
        et = uptime_cur - uptime_sav;
        // 
        Frame_etscale = 100.0f / ((float)Hertz * (float)et * (Rc.mode_irixps ? 1 : smp_num_cpus));
    }
    // utime: 用户时间,stime:系统时间
    PHist_new[Frame_maxtask].tics = tics = (this->utime + this->stime);
    if ((h = hstget(this->tid))) {
        // 如果有历史数据,则减去历史值。这样就能得到某一段时间的CPU占用
        tics -= h->tics;
    }
    this->pcpu = tics;
}
static const char *task_show (const WIN_t *q, const int idx) {
    float u = (float)p->pcpu;    
    u *= Frame_etscale;
    cp = scale_pcnt(u, W, Jn);
}

%MEM

static const char *task_show (const WIN_t *q, const int idx) {
    // kb_main_total 是总的物理内存
    // resident 是物理内存占用
    cp = scale_pcnt((float)pages2K(p->resident) * 100 / kb_main_total, W, Jn);
}

TIME+

static const char *task_show (const WIN_t *q, const int idx) {
    TIC_t t = p->utime + p->stime;
    cp = scale_tics(t, W, Jn);
}
⚠️ **GitHub.com Fallback** ⚠️