Unix/Linux 系统自动化管理: CPU 管理篇

在 Unix/Linux 系统日常管理和系统维护的过程中,随时可能需要查看 CPU 的使用状态,并根据相应信息分析系统状况,判断系统的资源使用情况和系统负载情况。本文在介绍 Unix/Linux 系统中 CPU 相关机制和工具的基础上,对各工具进行了分析比较,并给出了自动化监控系统环境和 CPU 利用率的例子代码供读者参考。在 AIX 系统的 CPU 使用状态监控部分,我们将介绍 lparstat,mpstat 等工具。而在 Linux 系统 CPU 使用状态监控部分,我们将重点介绍 /proc 文件系统和 ps 等命令。

了解 AIX 系统中的可用 CPU 资源

AIX 系统中每个处理器在低位内存中有着对应的全局数据结构 PPDA (Per-processor Data Area),其中存储了处理器的各种配置信息和运行状态,比如时钟频率和 CPU 运行时间。AIX 系统接口查询 PPDA 中的数据并提供给终端用户或者应用程序使用。但在进行 CPU 监控之前,系统用户首先需要了解当前的系统环境和可用的计算资源。对于不同的系统环境,用户需要不同的监控策略。首先,对于没有划分微分区 (Micro Partition) 的服务器,系统用户可以通过很多操作系统接口得到机器实际可用的资源种类和数量。

硬件和操作系统没有使用虚拟化技术的系统


清单 1. 运行 prtconf 获得处理器的相关信息
				  
 $ prtconf | grep Processor 
 Processor Type: PowerPC_POWER6 
 Processor Implementation Mode: POWER 6 
 Processor Version: PV_6 
 Number Of Processors: 4 
 Processor Clock Speed: 4005 MHz 
  Model Implementation: Multiple Processor, PCI bus 
 + proc0                                        Processor 
 + proc2                                        Processor 
 + proc4                                        Processor 
 + proc6                                        Processor 


Processor Type 表示了处理器的类型属于 Power 6 系列。这里同样可以知道本机的处理器个数为 4,并且时钟运行频率为 4G。运用类似的命令接口,比如 lsdev -Cc processor,也可以得到其他与 CPU 相关的配置信息。

使用微分区的系统

虚拟化作为一项成熟的技术,在 IBM eServer pSeries 服务器和 BladeCenter JS 刀片服务器中已经得到广泛的应用。所以我们有必要简单说明用户在常见的虚拟化环境,微分区 (Micro Partition) 中如何得到可用的资源状态。AIX 的命令接口在虚拟化环境下仍然可以使用,但是通常得到的结果是分配给当前虚拟机的虚拟处理器 (Virtual CPU) 的信息,而不是物理处理器 (Physical CPU) 的。


清单 2. 在微分区上运行 prtconf 获得虚拟处理器的信息
				  
 # prtconf | grep Processor 
 Processor Type: PowerPC_POWER5 
 Processor Implementation Mode: POWER 5 
 Processor Version: PV_5 
 Number Of Processors: 1 
 Processor Clock Speed: 1654 MHz 
  Model Implementation: Multiple Processor, PCI bus 
 + proc0  

以上输出表示本机当前被分配了一个虚拟处理器,及其硬件类型和运行频率。为了获得该虚拟机获得的物理处理器的数量,通常需要访问对应的 HMC (Hardware Management Console) 或者 AMM (Advanced Management Module) 来获得详细的信息和配置。下面的实例运行于 HMC。


清单 3. 在 HMC 上运行 lssyscfg 获得微分区的配置
				  
 hscroot@hmc:~> lssyscfg -r prof -m Server-9117-MMA-SN060DD72 
 --filter "lpar_ids=p6ml4n05"
 name=p6ml4n05,lpar_name=p6ml4n05,lpar_id=6,lpar_env=aixlinux, 
 all_resources=0,min_mem=2048,desired_mem=3072,max_mem=4096, 
 min_num_huge_pages=0,desired_num_huge_pages=0, 
 max_num_huge_pages=0,mem_mode=ded,proc_mode=shared,min_proc_units=0.1, 
 desired_proc_units=0.2,max_proc_units=0.3,min_procs=1,desired_procs=1, 
 max_procs=1,sharing_mode=cap,uncap_weight=0,shared_proc_pool_id=0, 
 shared_proc_pool_name=DefaultPool,io_slots=none,lpar_io_pool_ids=none, 
 max_virtual_slots=10, 
"virtual_serial_adapters=0/server/1/any//any/1,1/server/1/any//any/1", 
 virtual_scsi_adapters=2/client/1/vioserver/16/0,virtual_eth_adapters=none, 
 hca_adapters=none,boot_mode=norm,conn_monitoring=0,auto_start=0, 
 power_ctrl_lpar_ids=none,work_group_id=none,redundant_err_path_reporting=0, 
 bsr_arrays=0,lhea_logical_ports=23000000/2/1/5/none, 
 lhea_capabilities=23000000/0, 
 lpar_proc_compat_mode=default,electronic_err_reporting=null, 
 virtual_fc_adapters=none 

此处跟 CPU 相关的重要字段有:

  • min_proc_units:为了启动该分区所需的最少的物理处理器个数
  • desired_proc_units: 该分区运行时通常需要的物理处理器个数
  • max_proc_units: 该分区在运行时允许获得的最多的物理处理器个数

使用负载分区的系统

从 AIX 6.1 开始,用户可以创建并使用负载分区 (Workload Partition,简称 WPAR)。负载分区可以模拟一个 AIX 6.1 用户环境,但在缺省情况下,CPU 资源不会被以 dedicated 方式划分给负载分区。所以 AIX 的系统命令,比如 lsdev 在负载分区下的输出结果会是当前系统没有处理器。负载分区中的用户,在系统响应不够及时的情况下,通常有如下几种可能:

  • 负载分区本身被分配的资源不足
  • 负载分区的其对应的宿主机的负载过大,或者出现了 IO 瓶颈

后面的段落会具体介绍如何确定和解决负载分区中跟 CPU 相关的系统瓶颈。

获得 AIX 系统中处理器资源的代码示例

本段的最后给出一段基于 Perl 的例子代码,在 AIX5.3 和 6.1 上测试通过,可以侦测当前的系统环境和 CPU 的类型和数量。这段代码首先运行系统命令 oslevel 得到当前系统的版本,如果是 AIX6.1 则运行命令 lparstat 判断当前系统是否为 WPAR。无论 AIX 系统的版本如何,都加参数 -i 运行命令 lparstat 来获得分区的个数,并以此判断是否使用了微分区技术。最后调用命令 prtconf 输出 CPU 的一些参数。

该段代码可以帮助用户快速了解当前环境,尤其适用于工作环境复杂或频繁变更的场景。需要指出的是对于使用了微分区技术的系统,代码的最后输出的是虚拟处理器的数量。需要了解系统中物理处理器和逻辑处理器状态的用户,可以参阅本文其他段落加以补充。


清单 4. 获得当前的系统环境和 CPU 的类型和数量的代码示例
				  
 # WPAR 仅存在于 AIX 6.1 系统
 my $oslevel =  `oslevel`; 
 if ($oslevel =~ m/6\.1/) 
 { 
 # 在 WPAR 中不带参数运行 lparstat 命令只返回警告信息
    my $output = `lparstat`; 
    if ($output =~ m/The output is applicable only to the Global Environment/) 
    { 
        print "This machine is one WPAR with following CPU assigned.\n"; 
        system ("prtconf | grep Processor"); 
        exit 0; 
    } 
 } 

 # 使用– i 参数列出详细的配置信息
 my @outputs = `lparstat -i`; 
 foreach my $line (@outputs) 
 { 
    # 解析命令输出并得到分区个数
    if ($line !~ m/Partition Number/) {next;} 
    my ($blank, $partition_num) = split /Partition Number\s+:\s/, $line; 
    chomp $partition_num; 

    if ($partition_num eq '-') # full system 环境没有划分微分区
    { 
        print "This machine is one full system without LPARs. The system has following 
        physical CPUs installed.\n"; 
    }elsif ($partition_num > 1) # 如果存在多于一个的分区,该系统使用了微分区技术
    { 
        print "This machine is one LPAR with virtual following CPUs installed. 
        To check the assignment of physical CPU, please log on HMC or AMM.\n"; 
    }else 
    { 
        print "Can not decide whether current environment is one LPAR or not. 
         Please check HMC or AMM to decide this.\n"; 
    } 
 } 

 # 打印处理器本身的参数
 system ("prtconf | grep Processor"); 
 exit 0; 






回页首


使用 AIX 系统工具分析处理器的工作状态

在了解当前环境的可用 CPU 资源以后,可以对系统监控的对象和方法进行规划。多数情况下,操作系统提供的命令输出提供逻辑处理器 (Logical CPU) 的信息。在 IBM eServer pSeries 服务器和 BladeCenter JS 刀片服务器中,逻辑处理器通常通过并行多线程技术实现。下文是对该技术在 AIX 系统中应用的介绍。

并行多线程的查询和设置

并行多线程 (Simultaneous Multi-threading,简称 SMT) 是一种基于超标量 (superscalar) 体系结构处理器的技术,允许多个独立的线程在一个时钟周期内对多个功能处理单元 (Functional Unit) 发出指令。通常情况下,线程和功能处理单元的绑定是完全动态的。使用这项技术可以较明显的提高处理器的的实际利用率,进而表现出更强的运算性能。在 AIX 操作系统上,我们可以通过 smtctl 命令来查询和设置并行多线程的运行状态。


清单 5. 运行 smtctl 查询处理器对 SMT 技术的支持和当前的设置
				  
 $ smtctl 

 This system is SMT capable. 
 SMT is currently enabled. 
 SMT boot mode is not set. 
 SMT threads are bound to the same physical processor. 

 proc0 has 2 SMT threads. 
 Bind processor 0 is bound with proc0 
 Bind processor 1 is bound with proc0 


 proc2 has 2 SMT threads. 
 Bind processor 2 is bound with proc2 
 Bind processor 3 is bound with proc2 


 proc4 has 2 SMT threads. 
 Bind processor 4 is bound with proc4 
 Bind processor 5 is bound with proc4 


 proc6 has 2 SMT threads. 
 Bind processor 6 is bound with proc6 
 Bind processor 7 is bound with proc6 

命令的结果说明了当前系统支持 SMT 技术,而且当前正在使用。后面的多行输出中详细说明了逻辑处理器和虚拟处理器之间的对应关系。系统中有四个可用的虚拟处理器 (Virtual CPU),因为开启了 SMT (Simultaneous MultiThreading) 功能,可以识别出八个逻辑上的虚拟处理器 (Logical CPU)。

在缺省情况下,系统中的 SMT 应被使用以增强性能。当用户需要调整系统的 SMT 设置时,同样可以使用 smtctl 命令。具体参数请查阅命令说明。在负载分区情况下,SMT 设置不允许被直接修改。用户需要对负载分区的宿主机修改 SMT 配置,这会对该系统中的所有负载分区生效。而在微分区环境下,用户可以自主调整并行多线程的配置。

系统处理器负载的查询和分析

在了解系统中并行多线程的设置以后,用户需要得到不同时间段内处理器的使用状态。为此 AIX 系统提供了丰富的系统接口。用户可以根据不同的情况选用他们,检查和判断系统中 CPU 的运行状态。本文仅以 lparstat 和 mpstat 为例进行说明。

lparstat 命令

上文的例子代码使用了 lparstat。这个命令可以在各种系统环境,如负载分区中使用,得到当前系统的配置和部分运行状态,其中的部分内容与 CPU 直接相关。在 AIX 6.1 操作系统中,lparstat 也可以用来显示负载分区 (Workload Partition) 的信息,比如负载分区使用的 CPU 资源。用户可以查阅手册得到该命令的详细说明。

lparstat 命令非常适合获得当前系统或分区的配置信息,但是用来监控 CPU 负载有两个主要的不足。首先这条命令不能得到单个处理器的负载情况,所以不能用来直接确定多处理器负载不均的问题;其次这条命令在 AIX 6.1 系统上的支持的参数与 5.3 相比变化较大。所以本文主要介绍 mpstat 命令,用于检测 AIX 系统中的 CPU 状态。

mpstat 命令

与 lparstat 命令相似,mpstat 可以自动识别当前的系统设置,比如是否开启了 SMT 功能。与 lparstat 不同的是,mpstat 可以得到详细的单个处理器的运行状况。


图 1. 在没有微分区 (Micro Partition) 的系统上运行 mpstat 获得处理器负载
图 1. 在没有微分区 (Micro Partition) 的系统上运行 mpstat 获得处理器负载 

该命令检测系统中全部处理器的利用情况,并且给出各项的总和。下面是几个常用的输出项

  • lcpu: 工作的逻辑处理器的个数
  • us: 运行的用户程序所占用的 CPU 百分比
  • sy: 运行的内核程序所占用的 CPU 百分比
  • wa: CPU 用来等待 IO 所占用的百分比
  • id: CPU 空闲且不等待 IO 所占用的百分比

通常情况下,CPU0 的负载会略高于其他处理器。在其他处理器负载相差不多而且 CPU0 的负载不太高的情况下,可以认为是正常的情况。反之则可能存在系统或应用程序上的分配问题。

在显示的内容中,如果 wa 的值过高,则表示应用程序有过多的时间等待 IO 操作,外存的访问存在性能瓶颈。如果 id 的值如果持续低于 30,而且 wa 不高,则表明 CPU 比较繁忙 , 可以考虑对应用程序进行优化。如果是微分区或负载分区系统中,应当考虑是否需要分配更多的处理器资源。

mpstat 命令提供了参数,可以周期性的检测并汇报系统状态。在 mpstat 命令的输出满足用户需要的情况下,用户可以指定合适的间隔并以后台运行 mpstat,以实现对系统 CPU 的持续监控。下面的命令会在一天的时间内每隔半小时自动搜集一次系统信息。

mpstat 1800 48 > /tmp/mpstat_output &

用户可以有策略的检查输出文件中的内容,以确定系统的运行状态。

捕捉处理器异常状态的代码示例

下面一段 Perl 代码测试于 AIX5.3 和 6.1 系统,首先运行系统命令 smtctl 检查并行多线程技术的开启状态,然后依次检查 mpstat 命令输出文件中的每行内容,并把可能表示异常情况的行存入一个数组。


清单 6. 捕捉处理器异常状态的代码示例
				  
 my $output = `smtctl`; 
 # 如果 SMT 技术没有被激活,通常我们需要激活它
 if ($output =~ m/This system is SMT capable.*SMT is currently disabled/) 
 { 
    warn "This system can have SMT enabled, but has not. This means potential performance 
     issue in some applications. Command smtctl can be used to enable SMT. Notice that 
      change can NOT be directly done on workload partition.\n"; 
 } 

 # 解析文本文件 /tmp/mpstat_output。用户应该先运行 mpstat 并把输出重定向来得到这个文件。
 my $file = '/tmp/mpstat_output'; 
 open (FILE, "<$file") or die "No mpstat output file available. 
 Please run mpstat first.\n"; 
 my @output = <FILE>; 
 close FILE; 
 my @notice; 
 foreach my $line (@output) 
 { 
    chomp $line; 
 # 跳过空行和提示行
 if ($line !~ /\S+/) {next;} 
    if ($line =~ m/System configuration/ || $line =~/cpu\s+min/) {next;} 

    # 删除每行起始的空格
    $line =~ s/^\s+//g; 
    my ($cpu, $min, $maj, $mpc, $int, $cs, $ics, $rq, $mig, $lpa, $sysc, $us, $sy, 
     $wt, $id, $pc); 
        = split /\s+/, $line; 
    # 通常系统中不应有过长的运行队列,过多的线程迁移,过长的等待时间或过少的空闲时间
 if ($rq > 5 || $mig > 5 || $wt > 5 || $id < 10) 
    { 
        push @notice, $line; 
 } 
 } 


用户可以根据自己系统的版本对例子代码进行修改,并且选择如何处理这些异常。比较常见的处理有把异常内容在标准输出设备上输出,或者发邮件给系统的管理员。为了能够自动的实现这一功能,用户也可以把修改过的脚本定义成系统的 crontab 任务,实现在一定时间段内的定时监控。在发现了异常状态以后,通常需要确定异常状态是否与特定的进程或程序相关,再进一步对操作系统或特定进程进行判断。在对 AIX 系统中的 CPU 管理进行介绍以后,下文的讨论会以 Linux 为主。





回页首


了解 Linux 系统中的可用 CPU 资源

Linux 系统由于其开放性的优势,近年来在易用性,稳定性和市场占有率上获得了一定的进步。Linux 提供了一个特殊而强大的伪文件系统 proc。在设计之初,proc 的目的是用户能够方便快捷的访问进程。经过长时间的发展,proc 文件系统已经可以提供查询系统状态,例如 CPU 状态,更改系统参数等多方面的功能。

在绝大多数的 Linux 发行版中,/proc 文件系统在系统启动时缺省挂载到目录 /proc,作为操作系统和应用进程的接口。用户和应用程序可以通过 proc 得到系统的信息,并可以改变内核的某些参数。/proc 目录中包含了许多特殊文件以允许对驱动和内核信息进行高层访问。只要用户或应用程序有正确的访问权限,它们就可以通过读写这些文件来获得信息或设置参数。由于 Linux 系统的状态,如进程占用的资源,是动态改变的,所以用户或应用程序读取 proc 文件时,proc 文件系统是动态从系统内核读出所需信息并提交的。当系统重启或者电源关闭的时候,/proc 系统中原有的数据和信息将全部丢失。但在下次系统启动时会重新建立。下面会介绍与 CPU 直接相关的两个 /proc 文件,cpuinfo 和 loadavg。

文件 /proc/cpuinfo 存放了 Linux 系统的 CPU 信息。随着 Linux 发行版,CPU 的类型、设置的不同,该文件的内容会有比较大的差异。有些发行版本的 cpuinfo 文件包含了诸如 CPU 步进 (stepping),制造厂商等详细的 CPU 硬件信息。而在一部分发行版中,该文件仅包含了每个处理器的基本信息,比如时钟频率。需要用户注意的是,在使用了 SMT 技术的系统上,/proc/cpuinfo 显示的是逻辑处理器的个数和属性。


清单 7. 在 IBM JS BladeCenter 上读取 /proc/cpuinfo
				  
 # cat /proc/cpuinfo 
 processor       : 0 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 1 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 2 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 3 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 4 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 5 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 6 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 processor       : 7 
 CPU             : POWER6 (raw), altivec supported 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 
 clock           : 4005.000000MHz 
 revision        : 3.1 (pvr 003e 0301) 

 timebase        : 512000000 
 platform        : pSeries 
 model           : IBM,7998-61X 
 machine         : CHRP IBM,7998-61X 

Linux 支持众多的硬件类型,并且有很多有差异的发行版。没有统一的命令可以得到或查询 SMT 的状态。但在基于 Power 核心的 IBM 服务器上,可以使用 ppc_64 命令。


清单 8. 使用 ppc_64 命令获得 SMT 的设置
				  
 # ppc64_cpu --smt 
 smt is on 

这条命令同样可以用来改变 SMT 的设置,详细用法请参阅命令说明。

在了解到 SMT 被开启以后分析 /proc/cpuinfo 文件的内容。可以看到系统中共有八个逻辑处理器 (Logical CPU),所以物理处理器的个数是 8 / 2 = 4。它们都是 IBM pSeries 系列的 Power 6 处理器,支持 Altivec 指令集,运行于 4GHz,修订版本为 3.1,基准时钟频率 (time base) 为 512MHz。在文件最后的内容表示了机器的硬件类型 7998-61X。查询 IBM 网站可知这是 IBM BladeCenter JS22 的刀片服务器。

因为 IBM 的微分区技术构建于 Linux 系统之下,所以为了获得微分区的被分配的物理处理器个数,需要访问 HMC(Hardware Management Console) 或 AMM(Advanced Management Module)。具体使用可参阅本文的 AIX 部分或者 IBM 的使用说明。

从 2.6.20 开始,Linux 内核引入了 KVM (Kernel-based Virtual Machine) 作为标准的虚拟化解决方案。在 KVM 中 /proc/cpuinfo 的内容会与宿主机不同,一些情况下可以帮助用户知道当前的系统是否是 KVM 下的虚拟环境


清单 9. 在 KVM 的虚拟机中读取 /proc/cpuinfo
				  
 # cat /proc/cpuinfo 
 processor       : 0 
 vendor_id       : GenuineIntel 
 CPU family      : 6 
 model           : 2 
 model name      : QEMU Virtual CPU version 0.9.1 
 stepping        : 3 
 CPU MHz         : 2660.129 
 cache size      : 2048 KB 
 fdiv_bug        : no 
 hlt_bug         : no 
 f00f_bug        : no 
 coma_bug        : no 
 fpu             : yes 
 fpu_exception   : yes 
 CPUid level     : 2 
 wp              : yes 
 flags           : fpu de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 
                   clflush mmx fxsr sse sse2 nx lm up pni 
 bogomips        : 5326.47 

在模式名 (model name) 中可以知道,本机使用了基于 QEMU 模拟器的虚拟处理器。

IBM 的 System x 系列服务器使用了不同的硬件类型,用户可以仅通过读取 /proc/cpuinfo 的内容获得包括 SMT 等的系统设置。

获得系统处理器配置的代码示例

下面的例子代码适用于使用 Power CPU 或者 Intel CPU 的 Linux 系统,并在 Redhat 企业服务器版和 Suse 企业服务器版上测试通过。它首先运行命令 arch 判断当前系统的运行平台,并读取 /proc/cpuinfo 文件。在 Power 平台上调用特有的 ppc64_cpu 命令获得 SMT 配置,并读取 /proc/ppc64/lparcfg 文件以获得 CPU 的运行模式;在 System x 系列服务器上则是通过解析文件 /proc/cpuinfo 的内容来获得 SMT 配置。代码的最后依次输出了系统中 CPU 资源的数量、配置、运行模式和类型。


清单 10. 获取系统 CPU 资源配置的代码示例
				  
 # 得到 /proc/cpuinfo 文件的内容
 my $cpu_file = '/proc/cpuinfo'; 
 open FILE, "<$cpu_file" or die "Failed to open $cpu_file.\n"; 
 my @contents = <FILE>; 
 close FILE; 

 my ($smt, $dedicate); 
 # Power 服务器上运行的 Linux 发行版有自己的命令和配置文件
 my $arch = `arch`; 
 if ($arch =~ /ppc64/){ 
    # 得到 Power 服务器上的 SMT 配置
    my $output = `ppc64_cpu --smt`; 
    if ($output =~ m/off/){ 
        $smt = "off"; 
    }elsif ($output =~ m/on/){ 
        $smt = "on"; 
    }else{ 
        die "Command ppc64_cpu does not work well. Please reinstall powerpc-utils 
        to fix this issue.\n"; 
    } 

    # 从 lparcfg 文件读出处理器运行模式
    my $cfg_file = '/proc/ppc64/lparcfg'; 
    open FILE, "<$cfg_file" or die "Failed to open $cfg_file.\n"; 
    my @cfgs = <FILE>; 
    close FILE; 

    foreach my $line (@cfgs){ 
        if ($line =~ /shared_processor_mode=0/){ 
            $dedicate = 1; # dedicated CPU 
            last; 
        } 
    } 
 } 

 # 解析 /proc/cpuinfo 文件的内容
 my $proc_num = 0; 
 my $line_num = 0; 
 my (@physical_ids, $latest_proc_line_num); 
 foreach my $line (@contents){ 
    $line_num ++; 
 chomp $line; 
 # 得到虚拟处理器的个数
    if ($line =~ /processor\s+: \d/){ 
        $proc_num ++; 
        $latest_proc_line_num = $line_num; 
    } 
    if ($arch =~ /86/ && $line =~ /physical id/ && !grep (/^\Q$line\E$/, @physical_ids)){ 
        push @physical_ids, $line; 
    } 
 } 

 # 得到 x86 构架系统的 SMT 配置
 my $phy_proc_num = scalar(@physical_ids); 
 if ($arch =~ /86/ && ($proc_num > $phy_proc_num)){ 
    $smt = "on"; 
 }elsif ($arch =~ /86/ && ($proc_num == $phy_proc_num)){ 
    $smt = "off"; 
 } 

 # 得到 Power 服务器的虚拟处理器个数
 my $vir_proc_num; 
 if ($arch =~ /ppc64/ && $smt eq "on"){ 
    $vir_proc_num = $proc_num/2; 
 }elsif ($arch =~ /ppc64/ && $smt eq "off"){ 
    $vir_proc_num = $proc_num; 
 } 

 # 输出处理器个数
 if ($arch =~ /86/){ 
    print "There exist $phy_proc_num physical processors and $proc_num logical 
    processors in the system.\n"; 
 }elsif ($arch =~ /ppc64/){ 
    print "There exist $vir_proc_num virtual processors and $proc_num logical 
    processors in the system.\n"; 
 } 

 # 输出 SMT 配置
 if ($smt eq "on"){ 
    print "SMT is $smt on this machine.\n"; 
 }else{ 
    print "SMT is $smt on this machine. This means potential performance issue in some 
    applications. Please make sure that's the configuration you want.\n"; 
 } 

 # 输出处理器运行模式
 if ($arch =~ /ppc64/ && $dedicate){ 
    print "System processors are dedicated.\n"; 
 }elsif ($arch =~ /ppc64/ && !$dedicate){ 
    print "System processors are shared.\n"; 
 } 

 # 输出 /proc/cpuinfo 中的处理器关键信息
 for (my $i = $latest_proc_line_num; $i < scalar(@contents); $i ++){ 
    print "$contents[$i]\n"; 
 } 






回页首


使用 Linux 系统接口分析处理器的工作状态

因为 Linux 系统特有的开放性,用户可以自主的添加,定义或者改变系统原有的功能。有很多开源项目提供了基于图形的或者命令行的工具,帮助用户更加方便的识别、监控甚至改变系统中的处理器的运行状态。考虑到通用的原则,本文仅介绍常见 Linux 发行版本中已经集成的接口或者工具。

系统处理器负载的查询和分析

查看 /proc/stat 文件获得 CPU 状态

/proc/stat 的内容包含了系统中的各项基本信息,例如 CPU 状态。用户可以详细了解系统中每个处理器自系统启动以来的运行状态,并以此分析和评估应用环境的工作是否正常。


清单 11. 读取 /proc/stat 获得 CPU 的使用情况
				  
 # cat /proc/stat 
 cpu  507853 325 148706 190270813 190032 152 884 0 0 
 cpu0 178463 111 68890 95035802 93558 34 96 0 0 
 cpu1 329389 213 79816 95235010 96474 117 787 0 0 
 intr 93566218 3310 2 0 0 2 0 3 0 30 0 0 0 4 0 1623929 10015567 2440 20098 0 0 0 0 0 0 0 
 3712917 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 
 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 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 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 
 ctxt 202868862 
 btime 1242974927 
 processes 356350 
 procs_running 1 
 procs_blocked 0 


命令输出的最初几行包含了系统中所有 CPU 的活动信息,在 kernel2.6.29 下的 /proc/stat 中,每行内容的处理器名后有九个数字,而早期的 kernel 会缺失一些内容,比如与虚拟化相关的信息。所有这些数值都是从系统启动开始累计到当前时刻的,并以 0.01 秒为单位。以下是这些数值的解释

  • user: 用户模式占用的 CPU 时间
  • nice: 低优先级用户模式所占用的 CPU 时间
  • system: 系统核心态占用的 CPU 时间
  • idle:cpu 空闲时间
  • iowait:硬盘 IO 等待时间 ( 从 kernel 2.5.41 开始添加此项信息 )
  • irq:硬中断时间 ( 丛 kernel 2.6.0-test4 开始添加此项信息 )
  • softirq:软中断时间(同上)
  • steal:在虚拟环境下,处理其他作业系统占用的 cpu 时间(丛 kernel 2.6.11 开始添加此项信息)
  • guest: 作业系统运行虚拟 cpu 占用 cpu 的时间(丛 kernel2.6.24 开始添加此项信息)

根据 /proc/stat 文件的内容,用户可以自行计算任意时间段内 CPU 的占用率;

CPU 时间 =user+system+nice+idle+iowait+irq+softirq+steal+guest

选取两个时间点 T1 和 T2, CPU 在 T1 和 T2 时间段中的使用时间可以如下计算:

Total=(user2+system2+nice2+idle2+iowait2+irq2+softirq2+steal2+guest2)-( user1+system1+nice1+idle1+iowait1+irq1+softirq1+steal1+guest1)

CPU 空闲百分比:

idle = (idle2 - idle1) / Total * 100%

CPU 占用百分比:

occupy = (1 - idle) * 100%

除了最初的 CPU 行以外,/proc/stat 文件还有其他与系统性能相关的一些参数。其中 ctxt 是系统启动以来 CPU 发生的上下文交换的次数。

读取 /proc/loadavg 文件获得 CPU 状态

文件 /proc/loadavg 给出了特定时间间隔内运行队列的平均进程数。同时也给出了其他的一些状态参数值供内部和外部的系统调用使用。命令 uptime 就读取了该文件以获得 CPU 上的进程负载。


清单 12. 读取 /proc/loadavg 获得处理器上的进程负载
				  
 # cat /proc/loadavg 
 5.86 5.78 5.89 12/840 22261 

命令输出前三项分别表示最近 1 分钟,最近 5 分钟及最近 15 分钟运行队列中的平均进程数,第四项包括由斜线隔开的两个数值,前者表示当前正由内核调度的进程和线程的数目,后者表示系统当前存活的进程数目;第五个值表示此文件被查看前,最近一个由内核创建的进程的 PID。

利用 ps 命令

系统处理器的工作是处理任务。而在现代操作系统中,任务是以进程的形式表现的。所以定位分析系统处理器的问题,也需要用到进程相关的接口或指令。ps 命令是分析 CPU 状态的重要工具,它读取 /proc 文件系统中各进程的信息,并且加以显示。用户首先需要定位感兴趣的进程,这可以通过 ps 命令来确定,也可以结合其他系统工具。很多情况下,用户仅需关注某个或某几个进程。


清单 13. 使用 ps 选出占用 CPU 时间最多的五个进程
				  
 [root@bldlnx02 ~]# ps -e -o pcpu,pid,user,sgi_p,cmd |grep -v PID| sort -k 1| tail -5 
 0.0     8 root     * [khelper] 
 0.0     9 root     * [kacpid] 
 0.1 21949 root     * sshd: csm@pts/0 
 0.2 21951 root     * -bash 
 99.9 12392 root     * /usr/bin/Xvnc -inetd -query 127.0.0.1 -once -depth 24 
 -desktop VNC Session Manager -rfbauth /root/.vnc/passwd -geometry 640x480 

系统中通常会有多进程的程序运行。当这些进程占用了较多的 CPU 时间时,可以单独列出该程序的所有进程。多数情况下,用户也需要进程的启动时间,状态,父进程号 (PPID),占用的内存来分析系统和进程的状态。


清单 14. 通过进程名使用 ps 命令返回进程的主要属性
				  
 # ps -C nfsd -o cmd,pCPU,start_time,user,ppid,size,stat 
 CMD                         %CPU START USER      PPID    SZ STAT 
 [nfsd]                       0.0 May12 root         1     0 D 
 [nfsd]                       0.0 May12 root         1     0 D 
 [nfsd]                       0.0 May12 root         1     0 D 
 [nfsd]                       0.0 May12 root         1     0 D 
 [nfsd]                       0.0 May12 root         1     0 S 
 [nfsd]                       0.0 May12 root         1     0 S 
 [nfsd]                       0.0 May12 root         1     0 D 
 [nfsd]                       0.0 May12 root         1     0 D 

在以上输出中各个字段分别表示如下含义:

  • CMD 进程命令名
  • %CPU 进程占用的 CPU 百分比
  • START 进程启动的时间
  • USER 进程的属主
  • PPID 父进程号
  • SZ 进程占用的内存空间
  • STAT 进程状态

ps 命令的输出结果表示系统中共有八个 nfs 服务进程,是根用户在一天以前启动的。当前这些进程没有使用 CPU 时间或内存。并且分别处于不同的状态。ps 命令可以接受的状态种类共有七种,仅介绍清单 15 中的两个作为示例

  • D 无法中断的休眠状态(通常 IO 的进程)
  • S 处于休眠状态

可以看到有六个 nfs 服务进程处于无法中断的休眠状态,这表示 NFS 服务出现了问题。用户可以通过检查物理存储可用性,查看 /var/log/messages 文件或 sysrq-T 系统 trace 等手段来进一步定位和排查错误。

获得各处理器利用率和耗用处理器时间最多的进程的代码示例

本段的最后给出一段例子代码,可以获得一段时间内的 CPU 利用率,并且找出系统中占用 CPU 较多的进程,已在 Redhat 企业服务器和 Suse 企业服务器上测试通过。代码首先选取两个相隔一分钟的两个时间段,分别读取文件 /proc/stat 的内容,获得 CPU 在两个时刻的进程占用时间等数值来计算 CPU 利用率。并且读取文件 /proc/loadavg 获得处理器上的集成负载。在负载较高的情况下,调用命令 ps 找出消耗 CPU 最多的几个进程,及其所在的处理器(processor)。


清单 15.  获得各处理器的利用率和耗用处理器时间最多的进程代码示例
				  
 # 两次读取 /proc/stat 文件的内容
 my $file = '/proc/stat'; 
 open FILE, "<$file" or die "Failed to open file $file.\n"; 
 my @fir_contents = <FILE>; 
 close FILE; 

 sleep 60; 
 open FILE, "<$file" or die "Failed to open file $file.\n"; 
 my @sec_contents = <FILE>; 
 close FILE; 

 # 把 /proc/stat 文件的内容存入一个散列
 my (%cpuinfo); 
 my $cpu_num = 0; 
 my $line_num = 0; 
 foreach my $line (@fir_contents, @sec_contents){ 
    $line_num ++; 
    if ($line =~ m/^cpu/)    { 
        # 判断当前数据来自第一次读取还是第二次读取
        my $info_time; 
        if ($line_num <= scalar(@fir_contents))        { 
            $info_time = "first"; 
        }else        { 
            $info_time = "second"; 
        } 

        # 向散列写入数据
        chomp $line; 
        my ($cpu, $user, $nice, $sys, $idle, $io, $irq, $softirq, $steal, $guest) = 
            split /\s+/, $line; 
        $cpuinfo{$info_time}{$cpu}{'user'} = $user; 
        $cpuinfo{$info_time}{$cpu}{'nice'} = $nice; 
        $cpuinfo{$info_time}{$cpu}{'sys'} = $sys; 
        $cpuinfo{$info_time}{$cpu}{'idle'} = $idle; 
        $cpuinfo{$info_time}{$cpu}{'io'} = $io;  
        $cpuinfo{$info_time}{$cpu}{'irq'} = $irq; 
        $cpuinfo{$info_time}{$cpu}{'softirq'} = $softirq; 
        $cpuinfo{$info_time}{$cpu}{'$steal'} = $steal; 
        $cpuinfo{$info_time}{$cpu}{'guest'} = $guest; 

        $cpu_num ++; 
    } 
 } 

 # 读取散列中的数据以计算 CPU 利用率
 my (%cpu_data, %cpu_usage); 
 foreach my $info_time (keys %cpuinfo) 
 { 
    foreach my $cpu (keys %{$cpuinfo{$info_time}})    { 
        $cpu_data{$cpu}{$info_time}{'total'} = 0; 
        $cpu_data{$cpu}{$info_time}{'idle'} = $cpuinfo{$info_time}{$cpu}{'idle'}; 
        foreach my $key (keys %{$cpuinfo{$info_time}{$cpu}})        { 
            $cpu_data{$cpu}{$info_time}{'total'} += $cpuinfo{$info_time}{$cpu}{$key}; 
        } 
    } 
 } 
 my $check_proc; 
 foreach my $cpu (keys %cpu_data){ 
    my $idle_interval =  $cpu_data{$cpu}{'second'}{'idle'} -  
       $cpu_data{$cpu}{'fisrt'}{'idle'}; 
    my $total_interval = $cpu_data{$cpu}{'second'}{'total'} - 
       $cpu_data{$cpu}{'fisrt'}{'total'}; 
    $cpu_usage{$cpu} = (1 - $idle_interval/$total_interval); 
    if ($cpu_usage{$cpu} > 0.5) {$check_proc = 1;} 
 } 

 # 从 /proc/loadavg 读取处理器上的进程负载
 $file = '/proc/loadavg'; 
 open FILE, "<$file" or die "Failed to open file $file.\n"; 
 my @contents = <FILE>; 
 close FILE; 
 my ($load1, $load5, $load15, $proc_num, $pid); 
 foreach my $line (@contents) {($load1, $load5, $load15, $proc_num, $pid) = \n
    split /\s+/, $line;} 
 if ($load1 > 5) {$check_proc = 1;} 

 # 如果处理器空闲,退出
 if (!$check_proc){ 
    print "CPU load on this machine is normal.\n"; 
    exit 0; 
 } 

 # 如果处理器繁忙,找出占用 CPU 时间的进程
 my @output = `ps -e -o pcpu,pid,user,sgi_p,cmd |grep -v PID| sort -k 1| tail -10`; 
 foreach my $line (@output){ 
    $line =~ s/^\s+//g; 
    my ($cpu, $pid, $user, $proc, $cmd) = split /\s+/, $line; 
 if ($cpu < 5) {next;} 
 # 输出进程号和进程占用的 CPU 百分比
    print "Process $pid of user $user takes $cpu% CPU time on processor $proc.\n"; 
 } 
 exit 0; 


在得到需要关注的进程以后,用户可以进一步查看进程的应用类型和状态。详情可以参考本系列文章之进程管理篇。





回页首


小结

在本世纪的第一个十年,计算机中的 CPU 暂时结束了高主频的竞赛,转而向多核心发展。为了真正发挥多核心 CPU 的运算效能,需要将计算任务进行科学的拆分,并且根据不同运算核心的状态有选择的进行分配。这同时需要操作系统和应用程序的良好支持。虽然并行运算的研究已经进行了几十年,但由于其复杂性,实际应用中还会存在系统负载过高,处理器负载不均,程序同步等待时间长等各种问题。应用本文上述的各种工具和手段,可以帮助我们准确的判断异常情况的根源,并采取相应的对策。随着多核系统软硬件技术的发展,程序员将可以花更少的时间写出在更多应用场景中具有更高运算效能的程序,并在将来逐渐解决这些常见的问题。



参考资料

学习
  • Running Linux, Fifth EditionMatthias Kalle, Dalheimer 和 Matt Welsh 著;O'Reilly & Associates,2005)本书包含完整 Linux 的安装指导教程,系统维护的完整信息、文档开发和编程工具、网络管理的指导原则。 

  • Programming Perl Third Edition(Larry Wall、Tom Christiansen 和 Jon Orwant 著;O'Reilly & Associates,2000)本书是最好的 Perl 指南之一。

  • Perl Cookbook(Tom Christiansen 和 Nathan Torkington 著;O'Reilly & Associates,1998)本书是 Perl 问题的权威性入门书籍。 

  • IBM Publication: 《命令参考大全,卷 5:s - u 》:AIX 6.1 信息中心文档,系统管理类。 

  • 有关 Perl 信息及其相关资源,请查看 Perl.com。 

  • Programming Perl Third Edition(Larry Wall、Tom Christiansen 和 Jon Orwant 著;O'Reilly & Associates,2000)是当今最好的 Perl 指南,现在已经更新到 5.005 和 5.6.0。 

  • Perl Cookbook(Tom Christiansen 和 Nathan Torkington 著;O'Reilly & Associates,1998)是关于所有 Perl 问题的权威性入门书籍。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值