sysstat - pidstat

# ./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、内存等。

pidstat manual page


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
CPU Statistics

user

nicesysidleiowaithardirqsoftirqstealguestguest_nice
cpu7781745815134672140120183438650708496000
cpu0171059399288301710320370169323366000
cpu11763610717302031710156328161331666000
cpu21594115355276211711141441153301489000
cpu3166748572309801712183366157961442000
cpu46140117585411782828509535279000
cpu5170234630701794270594149114000
cpu6146815124541795156721121117000
cpu7114797296817959601067120000

计算某个 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)
CPUpstc->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
VSZpstc->vsz
RSSpstc->rss
%MEMpstc->rss / tlmkb    (tlmkb: /proc/meminfo MemTotal)

Priority And Scheduling Policy

指标计算方式
priopst->priority
policypst->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
threadspstc->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;
        }
}
指标计算方式
StkSizepst->stack_size
StkRefpst->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-nrpstc->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
iodelaypstc->blkio_swapin_delays - pstp->blkio_swapin_delays

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zs.w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值