# ./pidstat --help
Usage: ./pidstat [ options ] [ <interval> [ <count> ] ] [ -e <program> <args> ]
Options are:
[ -d ] [ -H ] [ -h ] [ -I ] [ -l ] [ -R ] [ -r ] [ -s ] [ -t ] [ -U [ <username> ] ]
[ -u ] [ -V ] [ -v ] [ -w ] [ -C <command> ] [ -G <process_name> ]
[ -p { <pid> [,...] | SELF | ALL } ] [ -T { TASK | CHILD | ALL } ]
[ --dec={ 0 | 1 | 2 } ] [ --human ]
报告 Linux 任务(进程)的统计信息:I/O、CPU、内存等。
CPU utilization
选项
-u
指标
%usr
在用户级别(应用程序)执行时任务使用的 CPU 百分比,无论是否有 nice priority。
请注意,此字段不包括运行虚拟处理器所花费的时间。
%system
在系统级别(内核)执行时任务使用的 CPU 百分比。
%guest
任务在虚拟机(运行虚拟处理器)中花费的 CPU 百分比。
%wait
任务在等待运行时花费的CPU的百分比。
%CPU
任务使用的 CPU 时间的总百分比。
在 SMP 环境中,如果在命令行中输入了选项 -I,则任务的 CPU 使用率将除以 CPU 的总数。
CPU
任务所属的处理器编号。
I/O Statistics
选项
-d
指标
kB_rd/s
任务导致每秒从磁盘读取的千字节数。
kB_wr/s
任务已导致或将导致每秒写入磁盘的千字节数。
kB_ccwr/s
任务取消了写入磁盘的千字节数。
这可能发生在任务截断一些脏的分页缓存时。在这种情况下,一些被其他任务占去的IO将不会发生。
iodelay
被监测的任务的块I/O延迟,以时钟滴答为单位测量。
这个指标包括等待同步块I/O完成和交换块I/O完成的延迟。
Priority And Scheduling Policy
实时优先级和调度策略信息
选项
-R
指标
prio
被监视任务的实时优先级。
policy
被监控任务的调度策略。
Page Faults And Memory Utilization
选项
-r
指标
minflt/s
该任务每秒钟发生的小故障(minor faults)总数,那些不需要从磁盘加载内存页的故障。
majflt/s
任务每秒发生的主要故障(major faults)总数,需要从磁盘加载内存页面的故障总数。
VSZ
虚拟大小:整个任务的虚拟内存使用量,以千字节为单位。
RSS
Resident Set Size: 任务使用的非交换物理内存,单位是千字节。
%MEM
任务当前使用的可用物理内存的份额。
报告任务及其所有子任务的全局统计信息时,可能会显示以下值:
minflt-nr
该任务及其所有子任务的小故障(minor faults)总数,并在时间间隔内收集。majflt-nr
任务及其所有子任务发生的重大故障(major faults)总数,并在时间间隔内收集。
Stack Utilization
选项
-R
指标
StkSize
为任务保留的作为堆栈的内存量,以千字节为单位,但不一定使用。
StkRef
作为堆栈使用的内存量,以千字节为单位,由任务引用。
Some Kernel Tables
选项
-v
指标
threads
与当前任务关联的线程数。
fd-nr
与当前任务关联的文件描述符数。
Task Switching Activity
选项
-w
指标
cswch/s
每秒任务执行的自愿上下文切换总数。
当任务因需要不可用的资源而阻塞时,会发生自愿上下文切换。
nvcswch/s
每秒执行的任务的非自愿上下文切换总数。
当任务在其时间片的持续时间内执行,然后被迫放弃处理器时,就会发生非自愿的上下文切换。
其他选项
-H
显示自纪元以来的时间戳,单位为秒。
-h
在单行上水平显示所有活动。这样做的目的是为了使它更容易被其他程序解析。
-I
在SMP环境中,表示任务的CPU使用率(如选项-u所显示的)应除以总的处理器数量。
-l
显示进程命令名称及其所有参数。
-p { pid [,...] | SELF | ALL }
选择要报告统计数据的任务(进程)。 pid是进程识别号。SELF关键字表示要报告pidstat进程本身的统计数据,而ALL关键字表示要报告系统管理的所有任务的统计数据。
-T { TASK | CHILD | ALL }
这个选项指定了pidstat命令所要监控的内容。TASK关键字表示要报告单个任务的统计数据(这是默认选项),而CHILD关键字表示要全局报告所选任务及其所有子任务的统计数据。ALL关键字表示要报告单个任务的统计数据,以及所选任务及其子任务的全局统计数据。
关键代码实现分析
获取CPU的数量
# cat /proc/stat
cpu 72163 45166 125104 12493464 3299 58616 7822 0 0 0
cpu0 15696 9304 26535 1524054 336 15268 3100 0 0 0
cpu1 16266 10600 27959 1523672 301 14475 1519 0 0 0
cpu2 14690 15250 25626 1523984 408 13848 1363 0 0 0
cpu3 15364 8359 28622 1525795 332 14201 1328 0 0 0
cpu4 5987 1093 8115 1590193 503 496 262 0 0 0
cpu5 1587 321 2903 1601235 589 140 112 0 0 0
cpu6 1424 139 2382 1601921 720 117 116 0 0 0
cpu7 1146 97 2957 1602606 106 68 19 0 0 0
intr 9130775 0 2951047 528520 0 0 0 967681 0 0 0 0 3349312 0 0 0 0 28 4 2 1 11 0 0 0 0 0 125872 0 375115 0 0 233763
16 17458 7529 31 1469 0 723 0 0 0 0 0 0 0 0 0 0 0 0 3070 0 2191 0 0 0 0 0 0 0 0 0 0 0 0 417 190557 66581 0 0 0
0 0 0 0 0 0 0 0 0 16 1924 3 19882 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 5944 0 0 2 0 0 0 0 0 17218 0 0 0 0 0 0 112 123 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 0 0 32 0 0 2 0 6 0 39725 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 103 6 0 2 3 47 3 4 0 0 0 0 0 0 4 0 0 1
1 0 0 1 1 0 0 97 0 1 1 0 0 0 5 1 1 0 0 33 0 15 0 1 2 0 2 0 0 0 12146 0 0 10 2851 1670 3 5 22769 8834 135 0 0 0 0
0 286 10623 3112 3082 1988 0 0 207 0 0 0 0 0 0 0 0 0 0 0 0 0 935 1 37 0 2944 4756 142048 156 4 2 0 0 0 0 0 0 0 0
0 0 0 0 20 0 0 3863
ctxt 12167990
btime 1663731264
processes 25119
procs_running 1
procs_blocked 0
softirq 2045855 1587 489182 4796 19123 373425 0 40118 558988 13 558623
或
# cat /sys/devices/system/cpu/
aarch32_el0 cpu2/ cpu7/ hyp_core_ctl/ online qcom_lpm/
bus_dcvs/ cpu3/ cpufreq/ isolated pmu_lib/ smt/
c1dcvs/ cpu4/ cpuidle/ kernel_max possible uevent
cpu0/ cpu5/ hang_detect_core/ modalias power/ vulnerabilities/
cpu1/ cpu6/ hotplug/ offline present
CPU 在不同状态下的统计
/*
* Structure for CPU statistics.
* In activity buffer: First structure is for global CPU utilization ("all").
* Following structures are for each individual CPU (0, 1, etc.)
*
* Used by: sadc, sar, sadf, iostat, mpstat, pidstat
*/
struct stats_cpu {
unsigned long long cpu_user;
unsigned long long cpu_nice;
unsigned long long cpu_sys;
unsigned long long cpu_idle;
unsigned long long cpu_iowait;
unsigned long long cpu_steal;
unsigned long long cpu_hardirq;
unsigned long long cpu_softirq;
unsigned long long cpu_guest;
unsigned long long cpu_guest_nice;
};
读文件 /proc/stat 并解析每个 CPU 以及整体的统计数据。
/*
***************************************************************************
* Read CPU statistics.
* Remember that this function is used by several sysstat commands!
*
* IN:
* @st_cpu Buffer where structures containing stats will be saved.
* @nr_alloc Total number of structures allocated. Value is >= 1.
*
* OUT:
* @st_cpu Buffer with statistics.
*
* RETURNS:
* Highest CPU number(*) for which statistics have been read.
* 1 means CPU "all", 2 means CPU 0, 3 means CPU 1, etc.
* Or -1 if the buffer was too small and needs to be reallocated.
*
* (*)This doesn't account for all processors in the machine in the case
* where some CPU are offline and located at the end of the list.
*
* USED BY:
* sadc, iostat, mpstat, pidstat
***************************************************************************
*/
__nr_t read_stat_cpu(struct stats_cpu *st_cpu, __nr_t nr_alloc)
{
FILE *fp;
struct stats_cpu *st_cpu_i;
struct stats_cpu sc;
char line[8192];
int proc_nr;
__nr_t cpu_read = 0;
if ((fp = fopen(STAT, "r")) == NULL) {
fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
exit(2);
}
while (fgets(line, sizeof(line), fp) != NULL) {
if (!strncmp(line, "cpu ", 4)) {
/*
* All the fields don't necessarily exist,
* depending on the kernel version used.
*/
memset(st_cpu, 0, STATS_CPU_SIZE);
/*
* Read the number of jiffies spent in the different modes
* (user, nice, etc.) among all proc. CPU usage is not reduced
* to one processor to avoid rounding problems.
*/
sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
&st_cpu->cpu_user,
&st_cpu->cpu_nice,
&st_cpu->cpu_sys,
&st_cpu->cpu_idle,
&st_cpu->cpu_iowait,
&st_cpu->cpu_hardirq,
&st_cpu->cpu_softirq,
&st_cpu->cpu_steal,
&st_cpu->cpu_guest,
&st_cpu->cpu_guest_nice);
if (!cpu_read) {
cpu_read = 1;
}
if (nr_alloc == 1)
/* We just want to read stats for CPU "all" */
break;
}
else if (!strncmp(line, "cpu", 3)) {
/* All the fields don't necessarily exist */
memset(&sc, 0, STATS_CPU_SIZE);
/*
* Read the number of jiffies spent in the different modes
* (user, nice, etc) for current proc.
* This is done only on SMP machines.
*/
sscanf(line + 3, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
&proc_nr,
&sc.cpu_user,
&sc.cpu_nice,
&sc.cpu_sys,
&sc.cpu_idle,
&sc.cpu_iowait,
&sc.cpu_hardirq,
&sc.cpu_softirq,
&sc.cpu_steal,
&sc.cpu_guest,
&sc.cpu_guest_nice);
if (proc_nr + 2 > nr_alloc) {
cpu_read = -1;
break;
}
st_cpu_i = st_cpu + proc_nr + 1;
*st_cpu_i = sc;
if (proc_nr + 2 > cpu_read) {
cpu_read = proc_nr + 2;
}
}
}
fclose(fp);
return cpu_read;
}
# cat /proc/stat
cpu 77817 45815 134672 14012018 3438 65070 8496 0 0 0
cpu0 17105 9399 28830 1710320 370 16932 3366 0 0 0
cpu1 17636 10717 30203 1710156 328 16133 1666 0 0 0
cpu2 15941 15355 27621 1711141 441 15330 1489 0 0 0
cpu3 16674 8572 30980 1712183 366 15796 1442 0 0 0
cpu4 6140 1175 8541 1782828 509 535 279 0 0 0
cpu5 1702 346 3070 1794270 594 149 114 0 0 0
cpu6 1468 151 2454 1795156 721 121 117 0 0 0
cpu7 1147 97 2968 1795960 106 71 20 0 0 0
user | nice | sys | idle | iowait | hardirq | softirq | steal | guest | guest_nice | |
---|---|---|---|---|---|---|---|---|---|---|
cpu | 77817 | 45815 | 134672 | 14012018 | 3438 | 65070 | 8496 | 0 | 0 | 0 |
cpu0 | 17105 | 9399 | 28830 | 1710320 | 370 | 16932 | 3366 | 0 | 0 | 0 |
cpu1 | 17636 | 10717 | 30203 | 1710156 | 328 | 16133 | 1666 | 0 | 0 | 0 |
cpu2 | 15941 | 15355 | 27621 | 1711141 | 441 | 15330 | 1489 | 0 | 0 | 0 |
cpu3 | 16674 | 8572 | 30980 | 1712183 | 366 | 15796 | 1442 | 0 | 0 | 0 |
cpu4 | 6140 | 1175 | 8541 | 1782828 | 509 | 535 | 279 | 0 | 0 | 0 |
cpu5 | 1702 | 346 | 3070 | 1794270 | 594 | 149 | 114 | 0 | 0 | 0 |
cpu6 | 1468 | 151 | 2454 | 1795156 | 721 | 121 | 117 | 0 | 0 | 0 |
cpu7 | 1147 | 97 | 2968 | 1795960 | 106 | 71 | 20 | 0 | 0 | 0 |
计算某个 CPU 花费的 jiffies 总数
基于 CPU Statistics 的统计数据,某个 CPU 花费的 jiffies 总数的计算公式:
tot_jiffies[curr] = st_cpu->cpu_user + st_cpu->cpu_nice +
st_cpu->cpu_sys + st_cpu->cpu_idle +
st_cpu->cpu_iowait + st_cpu->cpu_hardirq +
st_cpu->cpu_steal + st_cpu->cpu_softirq;
注意:不要添加 cpu_guest 和 cpu_guest_nice, 因为 cpu_user 和 cpu_nice 已经包含它们。
进程的统计信息
#define PID_STAT PRE "/proc/%u/stat"
#define TASK_STAT PRE "/proc/%u/task/%u/stat"
/*
***************************************************************************
* Read various stats for given PID.
*
* IN:
* @pid Process whose stats are to be read.
* @plist Pointer on the linked list where PID is saved.
* @tgid If !=0, thread whose stats are to be read.
* @curr Index in array for current sample statistics.
*
* OUT:
* @thread_nr Number of threads of the process.
*
* RETURNS:
* 0 if stats have been successfully read, and 1 otherwise.
***************************************************************************
*/
int read_pid_stats(pid_t pid, struct st_pid *plist, unsigned int *thread_nr,
pid_t tgid, int curr)
{
if (read_proc_pid_stat(pid, plist, thread_nr, tgid, curr))
return 1;
/*
* No need to test the return code here: Not finding
* the schedstat files shouldn't make pidstat stop.
*/
read_proc_pid_sched(pid, plist, tgid, curr);
if (DISPLAY_CMDLINE(pidflag) && !plist->cmdline[0]) {
if (read_proc_pid_cmdline(pid, plist, tgid))
return 1;
}
if (read_proc_pid_status(pid, plist, tgid, curr))
return 1;
if (DISPLAY_STACK(actflag)) {
if (read_proc_pid_smap(pid, plist, tgid, curr))
return 1;
}
if (DISPLAY_KTAB(actflag)) {
if (read_proc_pid_fd(pid, plist, tgid, curr))
return 1;
}
if (DISPLAY_IO(actflag))
/* Assume that /proc/#/task/#/io exists! */
return (read_proc_pid_io(pid, plist, tgid, curr));
return 0;
}
# cat /proc/1/stat
1 (init) S 0 0 0 0 -1 1077936384 30321 850720 959 456 254 483 880 1269
20 0 2 0 0 11145768960 2036 18446744073709551615 367395913728 367397338632
549050140256 0 0 0 65536 0 1073779960 0 0 0 17 2 0 0 29 0 0 367397362976
367397363736 368425443328 549050142404 549050142434 549050142434 549050142695 0
# cat /proc/1/task/1/stat
1 (init) S 0 0 0 0 -1 1077936384 24255 850720 798 456 182 296 880 1269
20 0 2 0 0 11145768960 2036 18446744073709551615 367395913728 367397338632
549050140256 0 0 0 65536 0 1073779960 1 0 0 17 2 0 0 29 0 0 367397362976
367397363736 368425443328 549050142404 549050142434 549050142434 549050142695 0
# cat /proc/1/task/233/stat
233 (init) S 0 0 0 0 -1 1077936448 5752 850720 161 456 69 188 880 1269
0 -20 2 0 215 11145768960 2036 18446744073709551615 367395913728 367397338632
549050140256 0 0 0 65536 0 1073779960 1 0 0 -1 1 0 0 11 0 0 367397362976
367397363736 368425443328 549050142404 549050142434 549050142434 549050142695 0
内核相关代码:
///kernel_platform/msm-kernel/fs/proc/array.c
static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task, int whole);
统计进程相关状态
struct pid_stats {
unsigned long long read_bytes __attribute__ ((aligned (8)));
unsigned long long write_bytes __attribute__ ((packed));
unsigned long long cancelled_write_bytes __attribute__ ((packed));
unsigned long long blkio_swapin_delays __attribute__ ((packed));
unsigned long long minflt __attribute__ ((packed));
unsigned long long cminflt __attribute__ ((packed));
unsigned long long majflt __attribute__ ((packed));
unsigned long long cmajflt __attribute__ ((packed));
unsigned long long utime __attribute__ ((packed));
long long cutime __attribute__ ((packed));
unsigned long long stime __attribute__ ((packed));
long long cstime __attribute__ ((packed));
unsigned long long gtime __attribute__ ((packed));
long long cgtime __attribute__ ((packed));
unsigned long long wtime __attribute__ ((packed));
unsigned long long vsz __attribute__ ((packed));
unsigned long long rss __attribute__ ((packed));
unsigned long nvcsw __attribute__ ((packed));
unsigned long nivcsw __attribute__ ((packed));
unsigned long stack_size __attribute__ ((packed));
unsigned long stack_ref __attribute__ ((packed));
unsigned int processor __attribute__ ((packed));
unsigned int priority __attribute__ ((packed));
unsigned int policy __attribute__ ((packed));
unsigned int threads __attribute__ ((packed));
unsigned int fd_nr __attribute__ ((packed));
};
#define PID_STAT PRE "/proc/%u/stat"
#define TASK_STAT PRE "/proc/%u/task/%u/stat"
int read_proc_pid_stat(pid_t pid, struct st_pid *plist, unsigned int *thread_nr, pid_t tgid, int curr)
{
rc = sscanf(start,
"%*s %*d %*d %*d %*d %*d %*u %llu %llu"
" %llu %llu %llu %llu %lld %lld %*d %*d %u %*u %*d %llu %llu"
" %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u"
" %*u %u %u %u %llu %llu %lld\n",
&pst->minflt, &pst->cminflt, &pst->majflt, &pst->cmajflt,
&pst->utime, &pst->stime, &pst->cutime, &pst->cstime,
thread_nr, &pst->vsz, &pst->rss, &pst->processor,
&pst->priority, &pst->policy,
&pst->blkio_swapin_delays, &pst->gtime, &pst->cgtime);
if (rc < 15)
return 1;
if (rc < 17) {
/* gtime and cgtime fields are unavailable in file */
pst->gtime = pst->cgtime = 0;
}
/* Convert to kB */
pst->vsz >>= 10;
pst->rss = PG_TO_KB(pst->rss);
}
/* Total number of jiffies spent on the interval */
/* /proc/stat > tot_jiffies */
deltot_jiffies = get_interval(tot_jiffies[prev], tot_jiffies[curr]);
/* /proc/uptime > uptime_cs */
itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
CPU Utilization
指标 | 计算方式 |
---|---|
%usr | (pstc->utime- pstp->utime) / (itv * HZ) |
%system | (pstc->stime - pstp->stime) / (itv * HZ) |
%guest | (pstc->gtime - pstp->gtime) / (itv * HZ) |
%CPU (Solaris mode) | ((pstc->utime + pstc->stime)-(pstp->utime + pstp->stime)) / deltot_jiffies |
%CPU (Irix mode) | ((pstc->utime + pstc->stime)-(pstp->utime + pstp->stime)) / (itv * HZ) |
CPU | pstc->processor |
注意:
- User time already includes guest time
- Irix mode: 本进程在本进程运行的cpu中(可能是多cpu的系统)占用的百分比
- Solaris mode: 在irix的基础上除以cpu个数
HZ:
/*
***************************************************************************
* Get number of clock ticks per second.
***************************************************************************
*/
void get_HZ(void)
{
long ticks;
if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
perror("sysconf");
}
hz = (unsigned long) ticks;
}
进程调度延时统计
int read_proc_pid_sched(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
#define PID_SCHED PRE "/proc/%u/schedstat"
#define TASK_SCHED PRE "/proc/%u/task/%u/schedstat"
// # cat /proc/1/schedstat
// 4857180564 2486120670 9302
// # cat /proc/1/task/1/schedstat
// 4857180564 2486120670 9302
// # cat /proc/1/task/233/schedstat
// 2655717387 273417638 5066
schedstat :
<task->se.sum_exec_runtime> <task->sched_info.run_delay> <task->sched_info.pcount>
struct pid_stats {
// task->sched_info.run_delay
unsigned long long wtime __attribute__ ((packed));
};
/* Convert ns to jiffies */
pst->wtime = <task->sched_info.run_delay> * HZ / 1000000000
指标 | 计算方式 |
---|---|
%wait | (pstc->wtime- pstp->wtime) / (itv * HZ) |
Page Faults And Memory Utilization
指标 | 计算方式 |
---|---|
minflt/s | (pstc->minflt - pstc->minflt) / itv |
majflt/s | (pstc->majflt - pstc->majflt) / itv |
VSZ | pstc->vsz |
RSS | pstc->rss |
%MEM | pstc->rss / tlmkb (tlmkb: /proc/meminfo MemTotal) |
Priority And Scheduling Policy
指标 | 计算方式 |
---|---|
prio | pst->priority |
policy | pst->policy |
pst->policy:
/* Normally defined in <linux/sched.h> */
#define SCHED_NORMAL 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_BATCH 3
/* SCHED_ISO not yet implemented */
#define SCHED_IDLE 5
#define SCHED_DEADLINE 6
Task Switching Activity
统计进程状态 status
# cat /proc/1/status
Name: init
Umask: 0000
State: S (sleeping)
Tgid: 1
Ngid: 0
Pid: 1
PPid: 0
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 64
Groups: 3009
VmPeak: 10901976 kB
VmSize: 10884540 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 15436 kB
VmRSS: 8144 kB
RssAnon: 2356 kB
RssFile: 5348 kB
RssShmem: 440 kB
VmData: 22528 kB
VmStk: 132 kB
VmExe: 1392 kB
VmLib: 5236 kB
VmPTE: 332 kB
VmSwap: 4348 kB
CoreDumping: 0
THP_enabled: 1
Threads: 2
SigQ: 4/27074
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000080010000
SigIgn: 0000002000000000
SigCgt: 0000004c400094f8
CapInh: 0000000000000000
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Seccomp_filters: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: ff
Cpus_allowed_list: 0-7
Mems_allowed: 1
Mems_allowed_list: 0
voluntary_ctxt_switches: 5998
nonvoluntary_ctxt_switches: 3319
struct pid_stats {
// voluntary_ctxt_switches
unsigned long nvcsw __attribute__ ((packed));
// nonvoluntary_ctxt_switches
unsigned long nivcsw __attribute__ ((packed));
// Threads
unsigned int threads __attribute__ ((packed));
};
struct st_pid {
unsigned long long total_threads;
};
#define PID_STATUS PRE "/proc/%u/status"
#define TASK_STATUS PRE "/proc/%u/task/%u/status"
int read_proc_pid_status(pid_t pid, struct st_pid *plist, pid_t tgid, int curr) {
struct pid_stats *pst = plist->pstats[curr];
// ...
if (!strncmp(line, "Uid:", 4)) {
sscanf(line + 5, "%u", &plist->uid);
}
else if (!strncmp(line, "Threads:", 8)) {
sscanf(line + 9, "%u", &pst->threads);
}
else if (!strncmp(line, "voluntary_ctxt_switches:", 24)) {
sscanf(line + 25, "%lu", &pst->nvcsw);
}
else if (!strncmp(line, "nonvoluntary_ctxt_switches:", 27)) {
sscanf(line + 28, "%lu", &pst->nivcsw);
}
}
指标 | 计算方式 |
---|---|
cswch/s | (pstc->nvcsw - pstc->nvcsw) / itv |
nvcswch/s | (pstc->nivcsw - pstc->nivcsw) / itv |
threads | pstc->threads |
Stack Utilization
统计进程堆栈内存信息
# cat /proc/1/smaps |head -20
558a757000-558a80c000 r--p 00000000 fe:03 2948 /system/bin/init
Size: 724 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 144 kB
Pss: 51 kB
Shared_Clean: 140 kB
Shared_Dirty: 0 kB
Private_Clean: 4 kB
Private_Dirty: 0 kB
Referenced: 144 kB
......
7fd5ee4000-7fd5f05000 rw-p 00000000 00:00 0 [stack]
Size: 132 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 28 kB
Pss: 28 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 28 kB
Referenced: 28 kB
Anonymous: 28 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 92 kB
SwapPss: 92 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd wr mr mw me gd ac
struct pid_stats {
unsigned long stack_size __attribute__ ((packed));
unsigned long stack_ref __attribute__ ((packed));
};
int read_proc_pid_smap(pid_t pid, struct st_pid *plist, pid_t tgid, int curr) {
struct pid_stats *pst = plist->pstats[curr];
// ......
case 1:
if (strstr(line, "Size:")) {
sscanf(line + sizeof("Size:"), "%lu", &pst->stack_size);
state = 2;
}
break;
case 2:
if (strstr(line, "Referenced:")) {
sscanf(line + sizeof("Referenced:"), "%lu", &pst->stack_ref);
state = 3;
}
}
指标 | 计算方式 |
---|---|
StkSize | pst->stack_size |
StkRef | pst->stack_ref |
Some Kernel Tables
统计进程打开文件信息
struct pid_stats {
unsigned int fd_nr __attribute__ ((packed));
};
#define PID_FD PRE "/proc/%u/fd"
#define TASK_FD PRE "/proc/%u/task/%u/fd"
int read_proc_pid_fd(pid_t pid, struct st_pid *plist, pid_t tgid, int curr)
{
struct pid_stats *pst = plist->pstats[curr];
if (tgid) {
sprintf(filename, TASK_FD, tgid, pid);
}
else {
sprintf(filename, PID_FD, pid);
}
dir = opendir(filename)
/* Count number of entries if fd directory */
while ((drp = readdir(dir)) != NULL) {
if (isdigit(drp->d_name[0])) {
(pst->fd_nr)++;
}
}
}
指标 | 计算方式 |
---|---|
fd-nr | pstc->fd_nr |
I/O Statistics
统计进程 IO 信息
# cat /proc/1/io
rchar: 619196013
wchar: 79644789
syscr: 219124
syscw: 62707
read_bytes: 277807104
write_bytes: 21979136
cancelled_write_bytes: 4096
# cat /proc/1/task/1/io
rchar: 15870554
wchar: 55886697
syscr: 8570
syscw: 7476
read_bytes: 22913024
write_bytes: 217088
cancelled_write_bytes: 0
# cat /proc/1/task/233/io
rchar: 3623029
wchar: 3640600
syscr: 4205
syscw: 3366
read_bytes: 1089536
write_bytes: 8212480
cancelled_write_bytes: 0
struct pid_stats {
unsigned long long read_bytes __attribute__ ((aligned (8)));
unsigned long long write_bytes __attribute__ ((packed));
unsigned long long cancelled_write_bytes __attribute__ ((packed));
};
#define PID_IO PRE "/proc/%u/io"
#define TASK_IO PRE "/proc/%u/task/%u/io"
int read_proc_pid_io(pid_t pid, struct st_pid *plist, pid_t tgid, int curr) {
if (!strncmp(line, "read_bytes:", 11)) {
sscanf(line + 12, "%llu", &pst->read_bytes);
}
else if (!strncmp(line, "write_bytes:", 12)) {
sscanf(line + 13, "%llu", &pst->write_bytes);
}
else if (!strncmp(line, "cancelled_write_bytes:", 22)) {
sscanf(line + 23, "%llu", &pst->cancelled_write_bytes);
}
}
指标 | 计算方式 |
---|---|
kB_rd/s | (pstc->read_bytes - pstp->read_bytes) / itv |
kB_wr/s | (pstc->write_bytes - pstp->write_bytes) / itv |
kB_ccwr/s | (pstc->cancelled_write_bytes - pstp->cancelled_write_bytes) / itv |
iodelay | pstc->blkio_swapin_delays - pstp->blkio_swapin_delays |