Chinaunix首页 | 论坛 | 博客
  • 博客访问: 127434
  • 博文数量: 6
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 170
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-22 13:06
文章分类

全部博文(6)

文章存档

2015年(2)

2014年(4)

我的朋友

分类: 虚拟化

2014-04-04 23:55:43

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 {
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上).


在include\linux\sched.h中有如下定义:
#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);
......
}




相关函数调用流程图:




阅读(7127) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:qemu中KVM硬件虚拟化的初始化分析

给主人留下些什么吧!~~