Linux的CPU資源調優

http://www.uplinux.com/shizi/wenxian/3629.html點擊打開鏈接


一)中斷的CPU親和性
 
我們可以調整中斷到某個CPU上,這樣可以讓CPU更有效的利用起來.
 
首先關閉掉irqbalance服務,如下:
/etc/init.d/irqbalance stop 
Stopping irqbalance: [  OK  ]
 
查看當前各種中斷所使用的CPU,如下:
for f in `find . -name "smp_affinity"`; do echo -ne "$f->" && cat $f; done
./18/smp_affinity->1
./17/smp_affinity->3
./15/smp_affinity->1
./14/smp_affinity->1
./13/smp_affinity->3
./12/smp_affinity->1
./11/smp_affinity->3
./10/smp_affinity->3
./9/smp_affinity->3
./8/smp_affinity->3
./7/smp_affinity->3
./6/smp_affinity->3
./5/smp_affinity->3
./4/smp_affinity->3
./3/smp_affinity->3
./2/smp_affinity->3
./1/smp_affinity->3
./0/smp_affinity->3
 
查看中斷使用率,如下:
cat /proc/interrupts 
           CPU0       CPU1       
  0:        137          0   IO-APIC-edge      timer
  1:          7          1   IO-APIC-edge      i8042
  3:          0          1   IO-APIC-edge    
  4:          1          0   IO-APIC-edge    
  7:          0          0   IO-APIC-edge      parport0
  8:          0          0   IO-APIC-edge      rtc0
  9:          0          0   IO-APIC-fasteoi   acpi
 12:        103          2   IO-APIC-edge      i8042
 14:       2301        628   IO-APIC-edge      ata_piix
 15:        116         49   IO-APIC-edge      ata_piix
 17:         15          0   IO-APIC-fasteoi   ioc0
 18:       4122         39   IO-APIC-fasteoi   eth0
NMI:          0          0   Non-maskable interrupts
LOC:      18423      16772   Local timer interrupts
SPU:          0          0   Spurious interrupts
PMI:          0          0   Performance monitoring interrupts
PND:          0          0   Performance pending work
RES:       2740       2914   Rescheduling interrupts
CAL:        110       1349   Function call interrupts
TLB:        339        421   TLB shootdowns
TRM:          0          0   Thermal event interrupts
THR:          0          0   Threshold APIC interrupts
MCE:          0          0   Machine check exceptions
MCP:          3          3   Machine check polls
ERR:          0
MIS:          0
 
我們看一下18號中斷下的相關文件,如下:
cd /proc/irq/18/ && ls
affinity_hint  eth0  node  smp_affinity  spurious
 
我們看下它使用的CPU.
more smp_affinity 
1
注:這裏輸出爲1表示,它使用了第一個CPU,1對映的兩進制掩碼也是1.
如果它使用前兩個CPU,那麼這裏就是3,即二進制的11.
如果我們有4個處理器,這裏的值就應該是F,也就是二進制1111.
如果我們只要第2個處理器進行處理,這裏的值就應該是2,因爲2的二進制是10.
 
我們在另一臺服務器ping本機,如下:
ping 192.168.75.135
64 bytes from 192.168.75.135: icmp_seq=3454 ttl=64 time=2.80 ms
64 bytes from 192.168.75.135: icmp_seq=3455 ttl=64 time=3.80 ms
64 bytes from 192.168.75.135: icmp_seq=3456 ttl=64 time=0.814 ms
64 bytes from 192.168.75.135: icmp_seq=3457 ttl=64 time=0.293 ms
64 bytes from 192.168.75.135: icmp_seq=3458 ttl=64 time=1.84 ms
64 bytes from 192.168.75.135: icmp_seq=3459 ttl=64 time=0.265 ms
64 bytes from 192.168.75.135: icmp_seq=3460 ttl=64 time=0.021 ms
64 bytes from 192.168.75.135: icmp_seq=3461 ttl=64 time=0.793 ms
64 bytes from 192.168.75.135: icmp_seq=3462 ttl=64 time=0.285 ms
64 bytes from 192.168.75.135: icmp_seq=3463 ttl=64 time=0.038 ms
64 bytes from 192.168.75.135: icmp_seq=3464 ttl=64 time=0.936 ms
64 bytes from 192.168.75.135: icmp_seq=3465 ttl=64 time=0.279 ms
64 bytes from 192.168.75.135: icmp_seq=3466 ttl=64 time=0.706 ms
 
 
在本機監控網卡中斷分佈,如下:
while ((1)) ; do sleep 1; cat /proc/interrupts |grep eth0; done
 18:       5568         39   IO-APIC-fasteoi   eth0
 18:       5570         39   IO-APIC-fasteoi   eth0
 18:       5576         39   IO-APIC-fasteoi   eth0
 18:       5580         39   IO-APIC-fasteoi   eth0
 18:       5584         39   IO-APIC-fasteoi   eth0
 18:       5590         39   IO-APIC-fasteoi   eth0
 18:       5592         39   IO-APIC-fasteoi   eth0
 18:       5598         39   IO-APIC-fasteoi   eth0
 18:       5604         39   IO-APIC-fasteoi   eth0
 18:       5606         39   IO-APIC-fasteoi   eth0
 18:       5612         39   IO-APIC-fasteoi   eth0
 18:       5616         39   IO-APIC-fasteoi   eth0
 18:       5620         39   IO-APIC-fasteoi   eth0
 18:       5626         39   IO-APIC-fasteoi   eth0
 18:       5628         39   IO-APIC-fasteoi   eth0
 18:       5634         39   IO-APIC-fasteoi   eth0
 18:       5638         39   IO-APIC-fasteoi   eth0
 18:       5641         39   IO-APIC-fasteoi   eth0
 18:       5647         39   IO-APIC-fasteoi   eth0
 18:       5650         39   IO-APIC-fasteoi   eth0
 18:       5656         39   IO-APIC-fasteoi   eth0
我們看到當前的中斷(第二列)即所有的網卡中斷請求都分佈到了CPU0.
 
 
我們這裏指定前兩個CPU做爲處理網卡請求,如下:
echo "3" > smp_affinity
 
while ((1)) ; do sleep 1; cat /proc/interrupts |grep eth0; done
 18:       6430         50   IO-APIC-fasteoi   eth0
 18:       6433         53   IO-APIC-fasteoi   eth0
 18:       6439         53   IO-APIC-fasteoi   eth0
 18:       6441         53   IO-APIC-fasteoi   eth0
 18:       6443         57   IO-APIC-fasteoi   eth0
 18:       6444         58   IO-APIC-fasteoi   eth0
 18:       6447         61   IO-APIC-fasteoi   eth0
 18:       6449         61   IO-APIC-fasteoi   eth0
 18:       6453         63   IO-APIC-fasteoi   eth0
 18:       6459         63   IO-APIC-fasteoi   eth0
 18:       6459         65   IO-APIC-fasteoi   eth0
 18:       6462         68   IO-APIC-fasteoi   eth0
 18:       6463         69   IO-APIC-fasteoi   eth0
 18:       6467         71   IO-APIC-fasteoi   eth0
 18:       6469         71   IO-APIC-fasteoi   eth0
 18:       6472         73   IO-APIC-fasteoi   eth0
注:我們看到網卡的中斷請求已經平均的分配到了兩個CPU.
 
 
 
二)isolcpus
 
通過在grub中設定isolcpus內核參數可以指定哪幾個CPU在系統中是孤立的,也就是說默認它們將不被使用.
 
測試如下:
編輯/boot/grub/menu.list
 
在加載內核的選項後加入isolcpus=0,如下:
kernel /boot/vmlinuz-2.6.32-71.el6.i686 ro root=UUID=96262e00-91a3-432d-b225-cb35d29eec8f rhgb quiet isolcpus=0
 
也就是說我們在啓動系統時將默認不使用CPU0,注意這裏說的默認不使用並不是絕對的,操作系統仍然可以指定使用哪個CPU.對於用戶而言可以通過taskset來做到這點.
 
重啓系統後,我們查看進程的親和性,如下:
ps -eo pid,args:50,psr 
  PID COMMAND                                            PSR
    1 /sbin/init                                           1
    2 [kthreadd]                                           0
    3 [migration/0]                                        0
    4 [ksoftirqd/0]                                        0
    5 [watchdog/0]                                         0
    6 [migration/1]                                        1
    7 [ksoftirqd/1]                                        1
    8 [watchdog/1]                                         1
    9 [events/0]                                           0
   10 [events/1]                                           1
   11 [cpuset]                                             0
   12 [khelper]                                            0
   13 [netns]                                              0
   14 [async/mgr]                                          0
   15 [pm]                                                 0
   16 [sync_supers]                                        1
   17 [bdi-default]                                        0
   18 [kintegrityd/0]                                      0
   19 [kintegrityd/1]                                      1
   20 [kblockd/0]                                          0
   21 [kblockd/1]                                          1
   22 [kacpid]                                             0
   23 [kacpi_notify]                                       0
   24 [kacpi_hotplug]                                      0
   25 [ata/0]                                              0
   26 [ata/1]                                              1
   27 [ata_aux]                                            0
   28 [ksuspend_usbd]                                      0
   29 [khubd]                                              0
   30 [kseriod]                                            0
   33 [khungtaskd]                                         0
   34 [kswapd0]                                            0
   35 [ksmd]                                               0
   36 [aio/0]                                              0
   37 [aio/1]                                              1
   38 [crypto/0]                                           0
   39 [crypto/1]                                           1
   45 [kpsmoused]                                          0
   46 [usbhid_resumer]                                     0
   75 [kstriped]                                           0
  239 [scsi_eh_0]                                          0
  240 [scsi_eh_1]                                          0
  250 [mpt_poll_0]                                         0
  251 [mpt/0]                                              0
  252 [scsi_eh_2]                                          0
  301 [jbd2/sda1-8]                                        0
  302 [ext4-dio-unwrit]                                    0
  303 [ext4-dio-unwrit]                                    1
  324 [flush-8:0]                                          0
  390 /sbin/udevd -d                                       1
  643 /sbin/udevd -d                                       1
  644 /sbin/udevd -d                                       1
  731 [kauditd]                                            0
 1004 auditd                                               1
 1029 /sbin/rsyslogd -c 4                                  1
 1062 irqbalance                                           1
 1081 rpcbind                                              1
 1093 mdadm --monitor --scan -f --pid-file=/var/run/mdad   1
 1102 dbus-daemon --system                                 1
 1113 NetworkManager --pid-file=/var/run/NetworkManager/   1
 1117 /usr/sbin/modem-manager                              1
 1124 /sbin/dhclient -d -4 -sf /usr/libexec/nm-dhcp-clie   1
 1129 /usr/sbin/wpa_supplicant -c /etc/wpa_supplicant/wp   1
 1131 avahi-daemon: registering [linux.local]              1
 1132 avahi-daemon: chroot helper                          1
 1149 rpc.statd                                            1
 1186 [rpciod/0]                                           0
 1187 [rpciod/1]                                           1
 1194 rpc.idmapd                                           1
 1204 cupsd -C /etc/cups/cupsd.conf                        1
 1229 /usr/sbin/acpid                                      1
 1238 hald                                                 1
 1239 hald-runner                                          1
 1279 hald-addon-input: Listening on /dev/input/event2 /   1
 1283 hald-addon-acpi: listening on acpid socket /var/ru   1
 1303 automount --pid-file /var/run/autofs.pid             1
 1326 /usr/sbin/sshd                                       1
 1456 /usr/libexec/postfix/master                          1
 1463 pickup -l -t fifo -u                                 1
 1464 qmgr -l -t fifo -u                                   1
 1467 /usr/sbin/abrtd                                      1
 1475 crond                                                1
 1486 /usr/sbin/atd                                        1
 1497 libvirtd --daemon                                    1
 1553 /sbin/mingetty /dev/tty1                             1
 1558 /sbin/mingetty /dev/tty2                             1
 1561 /sbin/mingetty /dev/tty3                             1
 1564 /sbin/mingetty /dev/tty4                             1
 1567 /sbin/mingetty /dev/tty5                             1
 1569 /sbin/mingetty /dev/tty6                             1
 1586 /usr/sbin/dnsmasq --strict-order --bind-interfaces   1
 1598 sshd: root@pts/0                                     1
 1603 -bash                                                1
 
我們看到有一些內核線程比如[kblockd/0]佔用了CPU0,這是因爲它指定了在CPU0上執行.其餘的進程佔用了CPU1.
 
我們這裏用一個簡單的循環程序測試一下:
#include <stdio.h>
 
int
main ()
{
while(1){
}
return 0;
}
 
gcc test.c
 
./a.out&
./a.out&
./a.out&
./a.out&
 
查看a.out進程的程序親和性,如下:
ps -eo pid,args:50,psr |grep a.out
 1669 ./a.out                                              1
 1670 ./a.out                                              1
 1671 ./a.out                                              1
 1672 ./a.out                                              1
 1675 grep a.out                                           1
 
我們看到4個a.out進程都使用了CPU1.這正是我們想看到的.
 
最後要說明的是如果使用isolcpus=1,則系統默認會使用CPU0提供服務.如果我們只有兩個cpu,卻指定isolcpus=0,1,這時將默認使用CPU0.
 
 
三)cpu的熱插拔
 
在操作系統層面可以對cpu進行熱插拔.
 
動態關閉cpu1,如下:
echo "0" > /sys/devices/system/cpu/cpu1/online  
 
此時我們在系統中,只能看到1個CPU了.
cat /proc/cpuinfo 
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 15
model           : 107
model name      : AMD Sempron(tm) Dual Core Processor 2300
stepping        : 2
cpu MHz         : 2210.053
cache size      : 256 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt rdtscp lm 3dnowext 3dnow constant_tsc up tsc_reliable extd_apicid pni cx16 lahf_lm extapic 3dnowprefetch
bogomips        : 4420.10
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management: ts fid vid ttp tm stc 100mhzsteps
 
注意,如果運行的程序跑在cpu1上,如果把cpu1關閉,則程序會遷移到cpu0上.另外cpu0是不可以被關閉的,在cpu0的sys文件系統中沒有online文件.
 
 
四)進程/線程的親和性和taskset的應用
 
1)概述:
1)CPU的親和性分爲軟親合性和硬親合性,軟親合性是使進程並不會在處理器之間頻繁遷移.硬親合性是使進程需要在您指定的處理器上運行,Linux默認是軟親合性的,所以Linux會試圖保持進程在相同的CPU上運行,因爲這樣再次應用TLB將成爲可能.
2)Linux系統通過親和性掩碼使應用程序使用哪個CPU來運行程序,Linux默認的親合性掩碼是使用所有的CPU.
3)應用程序可以在啓動時指定親和性掩碼,提交給調度系統,也可以在應用程序運行中調整它的親和性掩碼.
 
 
2)用taskset手工調整一個進程的親和性
 
我們先弄一個最簡單的程序,它是一個死循環,如下:
#include <stdio.h>
 
int
main ()
{
        while(1){
        }
        return 0;
}
編譯並運行:
gcc taskloop.c -o taskloop
./taskloop
 
我們在另一個終端查看該進程的狀態,如下:
ps -eo pid,args:30,psr 
 PID COMMAND                          PSR
 2826 ./taskloop                       0
 
注:上面的ps輸出,我們只保留了taskloop一行,PSR代表我們的程序用了哪個CPU,如果有兩個CPU,就分別CPU0,CPU1,也就是從0開始.
我們中止這個程序,用taskset來指定它用CPU1來運行,如下:
taskset 2 ./taskloop
 
我們在另一個終端查看該進程的狀態,如下:
ps -eo pid,args:30,psr 
 PID COMMAND                          PSR
 2892 ./taskloop                       1
 
注:通過taskset對親合性掩碼的設定,我們選擇了CPU1來運行這個程序,這裏要說明的是taskset指定的掩碼是從1開始計算的,我們指定用CPU1,就得用taskset 2 COMMAND來設定.
下面是親合性掩碼與CPU的對映,如下:
0x00000001是處理器1(CPU0)
0x00000002是處理器2(CPU1)
0x00000003是處理器1和處理器2(CPU0/CPU1)
0x00000004是處理器3(CPU2)
0x0000001F是前5個處理器(CPU0,CPU1,CPU2,CPU3,CPU4)
0xFFFFFFFF是所有的處理器(即32個處理器)
以此類推,上面是十六進制的掩碼方式,在taskset中可以用十六進制和十進制兩種方式,我們爲了方便,在這裏只用十進制來表示.
 
同樣的我們也可以在程序運行中來改變它的親合性掩碼,從而改變它使用的CPU.
 
上面的taskloop進程使用了CPU1,我們將它改爲使用CPU0,如下:
taskset -p 1 `pgrep taskloop`  
pid 2892's current affinity mask: 2
pid 2892's new affinity mask: 1
 
在另一個終端查看該進程的狀態:
ps -eo pid,args:30,psr
 PID COMMAND                          PSR
 2892 ./taskloop                       0
 
注:我們看到原本運行於CPU1的進程改用了CPU0,這裏要說明的是如果我們程序在sleep或pause,此時改變它的親合性掩碼但它不會選用新的CPU,只有當sleep或pause結束,它纔會應用親和性掩碼.
 
 
3)進程中的親合性設置
 
通過sched_setaffinity函數,可以設置CPU的親和性,讓指定的進程運行於指定的CPU上,我們把之前的程序做一下變動,如下:
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
 
int main(){
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(1,&mask);
    if(sched_setaffinity(0, sizeof(cpu_set_t), &mask)==-1)
        printf("sched_setaffinity set error!");
    while(1){
    }
    return 0;
}
編譯並運行:
gcc proaffinity.c -o proaffinity
./proaffinity
 
在另一個終端查看該進程的狀態:
ps -eo pid,args:20,psr|grep proaffinity|grep -v grep            
 3088 ./proaffinity          1
 
注:在程序中我們用sched_setaffinity函數,設定本程序用親合性掩碼1,也就是用第一個處理器來運行此程序.
sched_setaffinity(0, sizeof(cpu_set_t), &mask)函數中的第一個參數是PID,如果是0,則代表進程自己,第二個參數是親合性掩碼的長度,第三個參數是親合性掩碼.
CPU_ZERO(&mask)宏調用是清理掩碼mask,CPU_SET(1,&mask)是設定掩碼mask爲1.
 
 
4)線程中的親合性設置
 
通過pthread_attr_setaffinity_np函數,設定線程的親合性掩碼,也就是用第幾個處理器來運行該線程,如下:
 
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
 
int GetCpuCount()
{
    return (int)sysconf(_SC_NPROCESSORS_ONLN);
}
 
void *thread_fun()
{
    int i;
    while(1)
    {
        i = 0;
    }
 
    return NULL;
}
 
int main()
{
    int cpu_num = 0;
    cpu_num  = GetCpuCount();
    printf("The number of cpu is %d\n", cpu_num);
 
    pthread_t t1;
    pthread_t t2;
    pthread_attr_t attr1;
    pthread_attr_t attr2;
 
    pthread_attr_init(&attr1);
    pthread_attr_init(&attr2);
 
    cpu_set_t cpu_info;
    CPU_ZERO(&cpu_info);
    CPU_SET(0, &cpu_info);
    if (0!=pthread_attr_setaffinity_np(&attr1, sizeof(cpu_set_t), &cpu_info))
    {
        printf("set affinity failed");
        return;
    }
 
    CPU_ZERO(&cpu_info);
    CPU_SET(1, &cpu_info);
    if (0!=pthread_attr_setaffinity_np(&attr2, sizeof(cpu_set_t), &cpu_info))
    {
        printf("set affinity failed");
    }
 
    if (0!=pthread_create(&t1, &attr1, thread_fun, NULL))
    {
        printf("create thread 1 error\n");
        return;
    }
 
    if (0!=pthread_create(&t2, &attr2, thread_fun, NULL))
    {
        printf("create thread 2 error\n");
        return;
    }
 
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
}
 
編譯並運行:
gcc pthraffinity.c -o pthraffinity -pthread
 
./proaffinity
 
 
我們在另一個終端查看該進程中所有線程的狀態,如下:
ps -eLo pid,lwp,args:20,psr
  PID   LWP COMMAND              PSR
 3191  3191 ./pthraffinity         1
 3191  3192 ./pthraffinity         0
 3191  3193 ./pthraffinity         1
 
注:LWP一列爲線程ID,我們看到進程(PID=3191)用了CPU0,而第一個線程(LWP=3192)用了CPU1,這正是程序中設定的,而第二個線程(LWP=3193)用了CPU0,這也是程序的意圖.
 
 
 
 
五)cgroup
 
1)概述:
cgroup它的全稱爲control group.cgroup可以用於對一組進程分組,每一組進程就某種系統資源實現資源管理.
cgroup即一組進程的行爲控制.比如,我們限制進程/bin/sh的CPU使用爲20%.我們就可以建一個cpu佔用爲20%的cgroup.然後將 /bin/sh進程添加到這個cgroup中.
我們知道ulimit可以對系統資源進行限制,但ulimit以用戶的資源爲單位的,而cgroup可以針對到某個進程.
我們也可以指定某個進程使用某個cpu.或者讓某些進程使用一組CPU.
 
 
cgroup包含了多個孤立的子系統,每一個子系統代表一個單一的資源,在新的內核中cgroup控制的模塊有9個子系統,分別是:
blkio 這個子系統設置限制每個塊設備的輸入輸出控制。例如:磁盤,光盤以及usb等等。
cpu   這個子系統使用調度程序爲cgroup任務提供cpu的訪問。
cpuacct 產生cgroup任務的cpu資源報告。
cpuset  如果是多核心的cpu,這個子系統會爲cgroup任務分配單獨的cpu和內存。
devices  允許或拒絕cgroup任務對設備的訪問。
freezer   暫停和恢復cgroup任務。
memory 設置每個cgroup的內存限制以及產生內存資源報告。
net_cls   標記每個網絡包以供cgroup方便使用。
ns  名稱空間子系統。
 
有RHEL6中,有libcgroup軟件包,裏面包含了cgroup的相關服務程序,而且cgroup在RHEL6中也做爲服務出現.
同時cpuset和cgroup也做爲僞文件系統出現.如下:
grep cpuset /proc/filesystems 
nodev   cpuset
 
grep cgroup /proc/filesystems 
nodev   cgroup
 
 
 
 
2)我們可以通過cgroup中的cpuset子系統爲進程指定CPU和內存.
 
首先創建一個用於掛載cpuset文件系統的目錄,如下:
mkdir /cpusets
 
掛載cpuset文件系統以/cpusets目錄
mount -t cpuset nodev /cpusets/
注:我們也可以用,mount -t cgroup none /cpusets/ -o cpuset
 
查看
ls -l /cpusets/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.cpu_exclusive
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.cpus
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.mem_exclusive
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.mem_hardwall
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.memory_migrate
-r--r--r--. 1 root root 0 Oct 22 21:52 cpuset.memory_pressure
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.memory_pressure_enabled
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.memory_spread_page
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.memory_spread_slab
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.mems
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.sched_load_balance
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuset.sched_relax_domain_level
drwxr-xr-x. 3 root root 0 Oct 22 21:53 libvirt
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
 
查看cpuset.cpus,這裏顯示的是0-1,說明默認情況下我們的系統可以使用0,1兩個cpu.
more cpuset.cpus 
0-1
 
查看cpuset.mems,這裏顯示的是0,說明默認情況下我們的系統可以使用結點0的內存系統,這裏是單路控制,不是NUMA,所以只看到了0.
more cpuset.mems 
0
 
查看有多少個進程在這個cgroup中.如下:
more tasks 
1
2
3
4
5
9
11
 
這裏我們再建一個cgroup/cpusets,將某些進程指定到這裏,如下:
mkdir /cpusets/test
 
查看新cgroup
cd test/
[root@localhost test]# ls
cgroup.procs          cpuset.mem_exclusive   cpuset.memory_pressure     cpuset.mems                      notify_on_release
cpuset.cpu_exclusive  cpuset.mem_hardwall    cpuset.memory_spread_page  cpuset.sched_load_balance        tasks
cpuset.cpus           cpuset.memory_migrate  cpuset.memory_spread_slab  cpuset.sched_relax_domain_level
注:
我們看到新建的目錄下面包含了cpusets文件系統所有的文件.另外新的cgroup下面的task是空的,cgroup.cpus/cgroup.mems也是空的.
 
這裏指定新的cgroup/cpusets中的cpus爲0,也就是在這個cgroup中的進程只能使用第一個CPU,如下:
echo 0 > cpuset.cpus
 
內存做同樣的指定,如下:
echo 0 > cpuset.mems
 
我們這裏運行一個測試程序a.out,如下:
/root/a.out &
[1] 1848
 
查看該進程使用了哪個cpu,如下:
ps -eo pid,args:20,psr|grep a.out
 1848 /root/a.out                   1
 
將該進程PID指定到tasks文件中,也不是指定到第一塊cpu上.如下:
echo "1848" > tasks 
 
查看該進程使用的cpu,如下:
ps -eo pid,args:50,psr|grep a.out
 1848 ./a.out                       0
注:這裏我們看到a.out進程已經被指定到第1塊CPU上運行了,如下: 
 
這裏我們查看該進程的狀態,如下:
cat /proc/1848/status
 
Name:   a.out
State:  R (running)
Tgid:   1848
Pid:    1848
PPid:   1584
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
Utrace: 0
FDSize: 256
Groups: 0 1 2 3 4 6 10 
VmPeak:     1896 kB
VmSize:     1816 kB
VmLck:         0 kB
VmHWM:       276 kB
VmRSS:       276 kB
VmData:       24 kB
VmStk:        88 kB
VmExe:         4 kB
VmLib:      1676 kB
VmPTE:        20 kB
VmSwap:        0 kB
Threads:        1
SigQ:   3/7954
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: ffffffffffffffff
CapEff: ffffffffffffffff
CapBnd: ffffffffffffffff
Cpus_allowed:   1
Cpus_allowed_list:      0
Mems_allowed:   1
Mems_allowed_list:      0
voluntary_ctxt_switches:        2
nonvoluntary_ctxt_switches:     343
 
注:
Cpus_allowed:1指出該進程可以使用CPU的親和性掩碼,因爲我們指定爲第1塊CPU,所以這裏就是1,如果該進程指定爲4個CPU(如果有話),這裏就是F(1111).
Cpus_allowed_list:0指出該進程可以使用CPU的列表,這裏是0,所以只能使用第1塊CPU.
Mems_allowed:   1
Mems_allowed_list:      0
內存同CPU一樣,進程a.out只是使用了結點0的內存資源.
 
下面是init進程的status,我們可以做一下對比,如下:
cat /proc/1/status
Cpus_allowed:   3
Cpus_allowed_list:      0-1
Mems_allowed:   1
Mems_allowed_list:      0
 
 
最後我們總結一下cpusets的各子目錄的關係,如果我們有8塊cpu,在/cpusets目錄下建了子目錄test1,同時給test1中的cpusets.cpus指定爲0-3,那麼在test1目錄下再建test2子目錄,此時只能給test2子目錄中的cpuset.cpus指定爲0-3.
也就是說這是一種繼承的關係.在我們的例子中在/cpusets/test目錄下再建subtest,此時不允許向subtest目錄下的cpuset.cpus寫入1,因爲test的cpuset.cpus是0.
如下:
mkdir subtest && cd subtest
寫入失敗
echo 1 > cpuset.cpus 
-bash: echo: write error: Permission denied
 
查看test的cpuset.cpus爲0
cat ../cpuset.cpus 
0
 
對subtest的cpuset.cpus寫入0是可以的,如下:
echo 0 > cpuset.cpus 
cat cpuset.cpus 
0
 
 
 
3)我們演示一下cgroup中的memory系統,這裏我們指定某個進程只能使用300MB的虛擬內存.
 
創建用於掛載的cgroup/memory的目錄,如下:
mkdir /mnt/cgroup/
 
指定用cgroup文件系統掛載,同時指定用memory子系統,如下:
mount -t cgroup none /mnt/cgroup/ -o memory
 
查看memory子系統中包括的文件,如下:
ls /mnt/cgroup/
cgroup.procs                     memory.memsw.usage_in_bytes
libvirt                          memory.soft_limit_in_bytes
memory.failcnt                   memory.stat
memory.force_empty               memory.swappiness
memory.limit_in_bytes            memory.usage_in_bytes
memory.max_usage_in_bytes        memory.use_hierarchy
memory.memsw.failcnt             notify_on_release
memory.memsw.limit_in_bytes      release_agent
memory.memsw.max_usage_in_bytes  tasks
 
查看cgroup/memory系統中的文件,如下:
cd /mnt/cgroup/
ls
cgroup.procs        memory.limit_in_bytes        memory.memsw.max_usage_in_bytes  memory.swappiness      release_agent
libvirt             memory.max_usage_in_bytes    memory.memsw.usage_in_bytes      memory.usage_in_bytes  tasks
memory.failcnt      memory.memsw.failcnt         memory.soft_limit_in_bytes       memory.use_hierarchy
memory.force_empty  memory.memsw.limit_in_bytes  memory.stat                      notify_on_release
 
新建目錄test,如下:
mkdir test && cd test/
ls
cgroup.procs           memory.max_usage_in_bytes        memory.memsw.usage_in_bytes  memory.usage_in_bytes
memory.failcnt         memory.memsw.failcnt             memory.soft_limit_in_bytes   memory.use_hierarchy
memory.force_empty     memory.memsw.limit_in_bytes      memory.stat                  notify_on_release
memory.limit_in_bytes  memory.memsw.max_usage_in_bytes  memory.swappiness            tasks
 
查看相關的內存限制:
more memory.limit_in_bytes
9223372036854775807
 
more memory.memsw.limit_in_bytes
9223372036854775807
 
將該進程組中的內存限制開啓爲300MB,如下:
echo 300M > memory.limit_in_bytes
echo 300M > memory.memsw.limit_in_bytes
 
cat memory.limit_in_bytes
314572800
 
cat memory.memsw.limit_in_bytes
314572800
 
將當前進程的PID寫入到tasks中,如下:
echo $$ > tasks 
 
通過下面的程序,我們申請內存資源,如下:
more /tmp/test.c 
#include <stdio.h>
#include <stdlib.h>
#define MALLOC_SIZE 1024 * 1024 * 300 //1G
 
int main(void)
{
char *i = NULL;
long int j;
 
i = malloc(MALLOC_SIZE);
if(i != NULL) {
for(j = 0; j < MALLOC_SIZE; j++)
*(i+j) = 'a';
}
sleep(5);
 
return 0;
}
 
編譯後運行,如下:
gcc /tmp/test.c /tmp/test
/tmp/test
Killed
 
進程在申請了300MB後,想繼續申請,發現內存不夠用後退出,我們查看日誌,如下:
tail -f /var/log/message
 
Oct 23 00:28:38 localhost kernel: 20531 total pagecache pages
Oct 23 00:28:38 localhost kernel: 0 pages in swap cache
Oct 23 00:28:38 localhost kernel: Swap cache stats: add 0, delete 0, find 0/0
Oct 23 00:28:38 localhost kernel: Free swap  = 1760248kB
Oct 23 00:28:38 localhost kernel: Total swap = 1760248kB
Oct 23 00:28:38 localhost kernel: 262128 pages RAM
Oct 23 00:28:38 localhost kernel: 35330 pages HighMem
Oct 23 00:28:38 localhost kernel: 4333 pages reserved
Oct 23 00:28:38 localhost kernel: 17603 pages shared
Oct 23 00:28:38 localhost kernel: 103368 pages non-shared
Oct 23 00:28:38 localhost kernel: Memory cgroup out of memory: kill process 1621 (test) score 4828 or a child
Oct 23 00:28:38 localhost kernel: Killed process 1621 (test) vsz:309020kB, anon-rss:307104kB, file-rss:268kB
 
Memory cgroup out of memory正是說明cgroup啓到了作用,它kill了引起OOM的進程.
 
 
 
4)最後我們掛載一下其它的幾種cgroup子系統,看一下他們的相關配置文件,有關於更深入的分析,我手頭的資料還有限,在不斷研究後再總結出來.
mount -t cgroup none /mnt/cgroup/ -o cpu
 
ls -l /mnt/cgroup/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpu.shares
drwxr-xr-x. 3 root root 0 Oct 22 21:53 libvirt
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
 
mount -t cgroup none /mnt/cgroup/ -o cpuacct 
 
ls -l /mnt/cgroup/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
-r--r--r--. 1 root root 0 Oct 22 21:52 cpuacct.stat
-rw-r--r--. 1 root root 0 Oct 22 21:52 cpuacct.usage
-r--r--r--. 1 root root 0 Oct 22 21:52 cpuacct.usage_percpu
drwxr-xr-x. 3 root root 0 Oct 22 21:53 libvirt
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
 
mount -t cgroup none /mnt/cgroup/ -o devices
 
ls -l /mnt/cgroup/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
--w-------. 1 root root 0 Oct 22 21:52 devices.allow
--w-------. 1 root root 0 Oct 22 21:52 devices.deny
-r--r--r--. 1 root root 0 Oct 22 21:52 devices.list
drwxr-xr-x. 3 root root 0 Oct 22 21:53 libvirt
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
 
 
mount -t cgroup none /mnt/cgroup/ -o freezer 
[root@localhost ~]# ls -l /mnt/cgroup/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
drwxr-xr-x. 3 root root 0 Oct 22 21:53 libvirt
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
 
mount -t cgroup none /mnt/cgroup/ -o net_cls 
[root@localhost ~]# ls -l /mnt/cgroup/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
-rw-r--r--. 1 root root 0 Oct 22 21:52 net_cls.classid
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
 
mount -t cgroup none /mnt/cgroup/ -o blkio 
[root@localhost ~]# ls -l /mnt/cgroup/
total 0
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.io_merged
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.io_queued
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.io_service_bytes
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.io_serviced
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.io_service_time
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.io_wait_time
--w-------. 1 root root 0 Oct 22 21:52 blkio.reset_stats
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.sectors
-r--r--r--. 1 root root 0 Oct 22 21:52 blkio.time
-rw-r--r--. 1 root root 0 Oct 22 21:52 blkio.weight
-rw-r--r--. 1 root root 0 Oct 22 21:52 blkio.weight_device
-r--r--r--. 1 root root 0 Oct 22 21:52 cgroup.procs
-rw-r--r--. 1 root root 0 Oct 22 21:52 notify_on_release
-rw-r--r--. 1 root root 0 Oct 22 21:52 release_agent
-rw-r--r--. 1 root root 0 Oct 22 21:52 tasks
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章