bash top fifth_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
进程号 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
其中 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);
}
}
内容示例
$ 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;
}
$ 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);
}
$ 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 */
);
}
statm 中的第一个值
statm 中的第二个值
statm 中的第三个值
(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);
}
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);
}
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);
}