procps-ng 3.3.10 源代码分析 - top (二)

2021-09-29  本文已影响0人  RonZheng2010

6 procs_refresh()

procs_refresh()得到本轮采样中的进程数据。

typedef struct PROCTAB 
{
    DIR*  procfs;
    int(*finder)(struct PROCTAB *, proc_t *);
    proc_t*(*reader)(struct PROCTAB *, proc_t *);
    pid_t*  pids;
char   path[PROCPATHLEN];
unsigned pathlen;
...
} PROCTAB;
static proc_t** private_ppt;
#define GROUPSMAX 4
static WIN_t Winstk [GROUPSMAX];

7 procs_hlp()

7.1 “单cpu核” vs “多cpu核”

如procs_refresh()中所说,procs_hlp()的工作有两部分。这里先说计算全局clock tik数据的情况。

全局数据计算有两种计算方法:相对于单个cpu核,或者相对于所有cpu核。全局变量Rc的成员mode_irixps保存了这个设置。默认值是相对于单个cpu核。

typedef struct RCF_t {
   char   id;                   // rcfile version id
   int    mode_altscr;          // 'A' - Alt display mode (multi task windows)
   int    mode_irixps;          // 'I' - Irix vs. Solaris mode (SMP-only)
   float  delay_time;           // 'd'/'s' - How long to sleep twixt updates
   int    win_index;            // Curwin, as index
   RCW_t  win [GROUPSMAX];      // a 'WIN_t.rc' for each window
   int    fixed_widest;         // 'X' - wider non-scalable col addition
   int    summ_mscale;          // 'E' - scaling of summary memory values
   int    task_mscale;          // 'e' - scaling of process memory values
   int    zero_suppress;        // '0' - suppress scaled zeros toggle
} RCF_t;

static RCF_t Rc;

全局clock tick值是自从系统启动以来的clock tick,这实际上也是单个cpu核的值。有几个cpu核,所有cpu核的clock tick就是这个值的几倍。

由于多线程程序使用多个核,它可能不止一个使用cpu核,那么按照单cpu核的计算方式,它的cpu占用率可能超过100%。

7.2 计算全局数据

procs_hlp()计算全局数据的步骤如下。

$ cat /proc/uptime
19217.09 149948.29
static float Frame_etscale;
Frame_etscale = 100.0f / ((float)Hertz * (float)et * (Rc.mode_irixps ? 1 : smp_num_cpus));

这里的分析,计算方式是单cpu核, Rc.mode_irixps = 1。所以公式可以简化为:

Frame_etscale = 100.0f / ((float)Hertz * (float)et);

其中Hertz变量的值是在init_libproc()中计算的。

8 init_libproc()

由于init_libproc()用attribute((constructor))修饰,它将在main()之前被调用。

static void init_libproc(void) __attribute__((constructor));
$ cat /boot/config-`uname -r` | grep '^CONFIG_HZ='
CONFIG_HZ=250

9 readproc()

readproc()的步骤如下:

$ cat /proc/2211/stat
2211 (compiz) S 1734 2211 2211 0 -1 4194304 1173835 5807 254 1 201018 11165 733 345 20 0 20 0 4109 1569832960 69715 18446744073709551615 4194304 4204954 140730964998528 0 0 0 0 4096 81923 0 0 0 17 6 0 0 83 0 0 6303088 6304056 7000064 140730965002255 140730965002262 140730965002262 140730965004264 0
typedef struct proc_t 
{
   int tid, 
   int ppid;
   unsigned pcpu; // %CPU usage
   utime,         // user-mode CPU time accumulated by process
   stime,         // kernel-mode CPU time accumulated by process
   ...
} proc_t;

10 再说procs_hlp()

procs_hlp()工作的第二部分,是计算本轮采样中进程的clock tick差值。

typedef unsigned long long TIC_t;
TIC_t tics = (this->utime + this->stime)

上轮采样的clock tick保存在全局Hash表PHist_new结构的成员tics中。这个Hash表的key值是进程pid。

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 HST_t *PHist_new;

在proc_t的成员pcpu中,保存本轮采样的clock tick的差值。

11 window_show()

window_show()的步骤如下。

12 task_show()

task_show显示本轮采样中该进程的所有数据。

它遍历进程数据的所有列,计算每列的值。

在遍历%CPU列时,

float u = (float)p->pcpu * Frame_etscale;

用前面Frame_etscale的计算式替代一下,可以得到如下计算式。为了看得更清楚,这里删掉了一些转型操作。

float u = p->pcpu / (Hertz * (uptime_cur - uptime_sav)) * 100.0f;

在这个计算式中,

上一篇 下一篇

猜你喜欢

热点阅读