bash top first_line - ceragon/LinuxDoc GitHub Wiki

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

当前时间

内容

top - 10:49:30

代码

static char buf[256];
char *sprint_uptime(int human_readable) {
    struct tm *realtime;
    time_t realseconds;
    // ======= 调用 glibc 的 time 方法
    time(&realseconds);
    // ======= 调用 glibc 的 localtime 方法
    // 当前时间
    realtime = localtime(&realseconds);
    // 打印时分秒
    pos = sprintf(buf, " %02d:%02d:%02d ",
      realtime->tm_hour, realtime->tm_min, realtime->tm_sec);
}

系统运行时长

内容

up 4 days, 13:08,

代码

char *sprint_uptime(int human_readable) {
    int updays;
    double uptime_secs, idle_secs;
    uptime(&uptime_secs, &idle_secs);
    // 将秒转换为天
    updays = (int) uptime_secs / (60*60*24);
    // 追加字符串 up
    strcat (buf, "up ");
    pos += 3;
    if (updays)
        // 打印启动后的天数
        pos += sprintf(buf + pos, "%d day%s, ", updays, (updays != 1) ? "s" : "");
    // 分钟
    upminutes = (int) uptime_secs / 60;
    // 小时
    uphours = upminutes / 60;
    uphours = uphours % 24;
    upminutes = upminutes % 60;
    // 打印启动后的小时和分钟
    pos += sprintf(buf + pos, "%2d:%02d, ", uphours, upminutes);
}

uptime 的实现

手动执行命令可以看到的信息

$ cat /proc/uptime 
1291.55 9247.65

方法实现

#define UPTIME_FILE  "/proc/uptime"
static int uptime_fd = -1;
static char buf[8192];
int uptime(double *restrict uptime_secs, double *restrict idle_secs) {
    double up=0, idle=0;
    FILE_TO_BUF(UPTIME_FILE,uptime_fd);
    // buf 是个字符串,格式是两个 double 类型的数字,如下面所示
    sscanf(buf, "%lf %lf", &up, &idle);
    SET_IF_DESIRED(uptime_secs, up);
    return up;
}

FILE_TO_BUF() 宏的展开

void FILE_TO_BUF(){
    static int local_n;
    // 由于 /proc/uptime 是个文件,所以要像文件一样操作
    if (uptime_fd == -1 && (uptime_fd = open("/proc/uptime", 00)) == -1) {
        return;
    }
    // 重置读索引
    lseek(uptime_fd, 0L, 0);
    // 读取信息到 buf 中
    if ((local_n = read(uptime_fd, buf, sizeof buf - 1)) < 0) {
        return;
    }
    buf[local_n] = '\0';
}

在线用户数

内容

1 user,

代码

struct utmp {
    short int ut_type;		/* Type of login.  */
    pid_t ut_pid;			/* Process ID of login process.  */
    char ut_user[UT_NAMESIZE]   /* Username.  */
};
#define USER_PROCESS	7	/* Normal process.  */
#define ut_name		ut_user
char *sprint_uptime(int human_readable) {
    struct utmp *utmpstruct;
    numuser = 0;
    // 重置文件的读入流
    setutent();
    // Read next entry from a utmp-like file.
    // ========== getutent() 调用 glibc 的库
    while ((utmpstruct = getutent())) {
        // 类型是 7,且用户名不为空
      if ((utmpstruct->ut_type == USER_PROCESS) &&
         (utmpstruct->ut_name[0] != '\0'))
          // 用户数 +1
        numuser++;
    }
    // 结束文件读入
    endutent();
    // 打印在线用户数
    pos += sprintf(buf + pos, "%2d user%s, ", numuser, numuser == 1 ? "" : "s");
}

load average 系统平均负载

内容

load average: 0.10, 0.28, 0.20

代码

static double av[3];
char *sprint_uptime(int human_readable) {
    loadavg(&av[0], &av[1], &av[2]);
    pos += sprintf(buf + pos, " load average: %.2f, %.2f, %.2f",
		   av[0], av[1], av[2]);
}
$ cat /proc/loadavg 
0.15 0.19 0.19 1/622 11603
void loadavg(double *restrict av1, double *restrict av5, double *restrict av15) {
    double avg_1=0, avg_5=0, avg_15=0;
    FILE_TO_BUF(LOADAVG_FILE,loadavg_fd);
    if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) {
        return;
    }
    SET_IF_DESIRED(av1,  avg_1);
    SET_IF_DESIRED(av5,  avg_5);
    SET_IF_DESIRED(av15, avg_15);
}
void FILE_TO_BUF(){
    static int local_n;
    // 由于 /proc/loadavg 是个文件,所以要像文件一样操作
    if (uptime_fd == -1 && (uptime_fd = open("/proc/loadavg", 00)) == -1) {
        return;
    }
    // 重置读索引
    lseek(uptime_fd, 0L, 0);
    // 读取信息到 buf 中
    if ((local_n = read(uptime_fd, buf, sizeof buf - 1)) < 0) {
        return;
    }
    buf[local_n] = '\0';
}
⚠️ **GitHub.com Fallback** ⚠️