mpstat是用于获取 CPU 相关统计信息的很有用的命令。
以下给出示例:
# mpstat -P ALL 1
09:06:48 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
09:06:49 AM all 4.00 0.00 6.00 0.00 0.00 0.50 0.00 10.50 79.00
09:06:49 AM 0 3.00 0.00 4.00 0.00 0.00 1.00 0.00 11.00 81.00
09:06:49 AM 1 3.00 0.00 9.00 0.00 0.00 0.00 0.00 11.00 77.00
它显示了系统中 CPU 的各种统计信息。其中%guest显示了运行vCPU时所消耗的cpu时间百分比。
mpstat的数据是从/proc/stat中读取的,stat中的内容如下:
cpu 10671864 0 5014212 110094401 884610 0 341684 0 7631438 0
cpu0 5453241 0 2426674 54706368 582976 0 334127 0 3906382 0
cpu1 5218623 0 2587538 55388032 301633 0 7556 0 3725055 0
..........................
第一行cpu为总的信息,cpu0 … cpun为各个具体CPU信息
上面共有10个值(单位:jiffies),前面8个值分别为:
User time,Nice time,System time,Idle time,Waiting time,Hard Irq time,
SoftIRQ time,Steal time, Guest time,Guest Nice time
/proc/stat文件的创建由函数proc_stat_init()实现,在文件fs/proc/stat.c中,
在内核初始化时调用。./proc/stat文件相关函数时间均在stat.c文件中。
/proc/stat文件的数据由show_stat()函数填充.
每个cpu通过per_cpu机制都定义了一个struct kernel_cpustat类型的变量kernel_cpustat,
在每一次时钟中断中,都会调用先关函数更新kernel_cpustat中的数据。
enum cpu_usage_stat {
struct kernel_cpustat {
时钟中断发生的时间间隔称为节拍(tick),节拍在内核编译阶段设定:
linux # zcat /proc/config.gz | grep CONFIG_HZ
CONFIG_HZ_250=y
CONFIG_HZ=250
以上设定节拍为250HZ,即每4ms发生一次时钟中断,每秒发生250次。jiffies是一个全局变量,它记录了自系统启动以来产生的节拍数。
每个cpu有各自的定时器,本地时钟中断发生时,由中断处理函数完成更新进程时间片、计算进程用户用时/系统用时等任务。
update_process_times函数在本地时钟中断发生时被调用,该函数调用account_process_tick更新进程的用户态/内核态占用率,
调用run_local_timers执行软时间中断,调用scheduler_tick更新当前进程的时间片。
Linux内核配置默认选择基于tick的cpu时间统计方法:
CONFIG_TICK_CPU_ACCOUNTING:
This is the basic tick based cputime accounting that maintains
statistics about user, system and idle time spent on per jiffies
granularity.
3.9.7内核的其它两种统计方式为:
CONFIG_VIRT_CPU_ACCOUNTING_GEN
CONFIG_IRQ_TIME_ACCOUNTING
以下给出示例:
# mpstat -P ALL 1
09:06:48 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
09:06:49 AM all 4.00 0.00 6.00 0.00 0.00 0.50 0.00 10.50 79.00
09:06:49 AM 0 3.00 0.00 4.00 0.00 0.00 1.00 0.00 11.00 81.00
09:06:49 AM 1 3.00 0.00 9.00 0.00 0.00 0.00 0.00 11.00 77.00
它显示了系统中 CPU 的各种统计信息。其中%guest显示了运行vCPU时所消耗的cpu时间百分比。
mpstat的数据是从/proc/stat中读取的,stat中的内容如下:
cpu 10671864 0 5014212 110094401 884610 0 341684 0 7631438 0
cpu0 5453241 0 2426674 54706368 582976 0 334127 0 3906382 0
cpu1 5218623 0 2587538 55388032 301633 0 7556 0 3725055 0
..........................
第一行cpu为总的信息,cpu0 … cpun为各个具体CPU信息
上面共有10个值(单位:jiffies),前面8个值分别为:
User time,Nice time,System time,Idle time,Waiting time,Hard Irq time,
SoftIRQ time,Steal time, Guest time,Guest Nice time
/proc/stat文件的创建由函数proc_stat_init()实现,在文件fs/proc/stat.c中,
在内核初始化时调用。./proc/stat文件相关函数时间均在stat.c文件中。
/proc/stat文件的数据由show_stat()函数填充.
每个cpu通过per_cpu机制都定义了一个struct kernel_cpustat类型的变量kernel_cpustat,
在每一次时钟中断中,都会调用先关函数更新kernel_cpustat中的数据。
enum cpu_usage_stat {
CPUTIME_USER,};
CPUTIME_NICE,
CPUTIME_SYSTEM,
CPUTIME_SOFTIRQ,
CPUTIME_IRQ,
CPUTIME_IDLE,
CPUTIME_IOWAIT,
CPUTIME_STEAL,
CPUTIME_GUEST,
CPUTIME_GUEST_NICE,
NR_STATS,
struct kernel_cpustat {
u64 cpustat[NR_STATS];};
时钟中断发生的时间间隔称为节拍(tick),节拍在内核编译阶段设定:
linux # zcat /proc/config.gz | grep CONFIG_HZ
CONFIG_HZ_250=y
CONFIG_HZ=250
以上设定节拍为250HZ,即每4ms发生一次时钟中断,每秒发生250次。jiffies是一个全局变量,它记录了自系统启动以来产生的节拍数。
每个cpu有各自的定时器,本地时钟中断发生时,由中断处理函数完成更新进程时间片、计算进程用户用时/系统用时等任务。
update_process_times函数在本地时钟中断发生时被调用,该函数调用account_process_tick更新进程的用户态/内核态占用率,
调用run_local_timers执行软时间中断,调用scheduler_tick更新当前进程的时间片。
Linux内核配置默认选择基于tick的cpu时间统计方法:
CONFIG_TICK_CPU_ACCOUNTING:
This is the basic tick based cputime accounting that maintains
statistics about user, system and idle time spent on per jiffies
granularity.
3.9.7内核的其它两种统计方式为:
CONFIG_VIRT_CPU_ACCOUNTING_GEN
CONFIG_IRQ_TIME_ACCOUNTING
参考资料(金步国 Linux-3.10-x86_64 内核配置选项简介
) :
Cputime accounting
CPU时间统计方式
Simple tick based cputime accounting
CONFIG_TICK_CPU_ACCOUNTING 简单的基于滴答的统计,适用于大多数场合 Deterministic task and CPU time accounting CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 通过读取CPU计数器进行统计,可以提供更精确的统计,但是对性能有一些不利影响. Full dynticks CPU time accounting CONFIG_VIRT_CPU_ACCOUNTING_GEN 利用上下文跟踪子系统,通过观察每一个内核与用户空间的边界进行统计.该选项对性能有显著的不良影响,目前仅用于完全无滴答子系统(CONFIG_NO_HZ_FULL)的调试 Fine granularity task level IRQ time accounting CONFIG_IRQ_TIME_ACCOUNTING 通过读取TSC时间戳进行统计,这是统计进程IRQ时间的更细粒度的统计方式,但对性能有些不良影响(特别是在RDTSC指令速度较慢的CPU上). |
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
表示当前当前进程所处的cpu是不是vCPU,guest值计算的是vCPU进程在当前cpu的system占用。
//该函数统计当前task的system_time,假如flags中标记了PF_VCPU,则将时间算入guest_time.
void account_system_time(struct task_struct *p, int hardirq_offset,
cputime_t cputime, cputime_t cputime_scaled)
{
int index;
if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) {
account_guest_time(p, cputime, cputime_scaled);return;
}}
............
static inline void __guest_enter(void)
{
/*}
* This is running in ioctl context so we can avoid
* the call to vtime_account() with its unnecessary idle check.
*/
vtime_account_system(current);
current->flags |= PF_VCPU;
static inline void __guest_exit(void)
{
/*}
* This is running in ioctl context so we can avoid
* the call to vtime_account() with its unnecessary idle check.
*/
vtime_account_system(current);
current->flags &= ~PF_VCPU;
static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
......
preempt_disable();
......
local_irq_disable();
......
kvm_guest_enter();
......
kvm_x86_ops->run(vcpu); //vmx.c vmx_vcpu_run(vcpu)
......
local_irq_enable();
......
kvm_guest_exit();
preempt_enable();
......}
r = kvm_x86_ops->handle_exit(vcpu);
return r;
......
static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
{
......
/* Enter guest mode */}
"jne 1f \n\t"
__ex(ASM_VMX_VMLAUNCH) "\n\t"
"jmp 2f \n\t"
"1: " __ex(ASM_VMX_VMRESUME) "\n\t"
"2: "
......
vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
......
相关函数调用流程图:


