让多核CPU占用率曲线听你指挥(Linux实现)——《编程之美》1.1继续学习
本回将尝试在Linux环境下能否在系统监视器中画出一个正弦曲线。本人环境为Ubuntu 11.04.
基本思想还是和Windows下面的相同,更换系统调用,便可以实现功能的迁移。
- #include <time.h>
- #include <sys/time.h>
- #include <unistd.h>
- #include<stdlib.h>
- #include<math.h>
- #define DWORD unsigned long
- #define UINT64 unsigned long long
- const double SPLIT = 0.01;
- const int COUNT = 200;
- const double PI = 3.14159265;
- const int INTERVAL = 300;
- int main(int argc, char* argv[] )
- {
- struct timeval tms;
- DWORD busySpan[COUNT];
- DWORD idleSpan[COUNT];
- int half = INTERVAL/2, i;
- double radian = 0.0;
- for(i = 0; i < COUNT; ++i)
- {
- busySpan[i] = (DWORD)(half + (sin(PI * radian) * half));
- idleSpan[i] = INTERVAL - busySpan[i];
- radian += SPLIT;
- }
- clock_t startTime = 0;
- int j = 0;
- while(1)
- {
- j = j % COUNT;
- timerclear(&tms);
- gettimeofday(&tms,NULL);
- UINT64 startTime = tms.tv_usec;
- while(1)//clock返回该进程从启动到现在经历的毫秒数(千分之一秒)
- {
- timerclear(&tms);
- gettimeofday(&tms,NULL);
- UINT64 nowTime = tms.tv_usec;
- if((nowTime - startTime)/1000 > busySpan[j])
- break;
- }
- if(usleep(idleSpan[j]*1000)) //精确到微秒(百万分之一秒)的函数
- exit(-1);
- j++;
- }
- return 0;
- }
gettimeofday()函数用来取得当前时间(微秒,百万分之一秒)。并通过参数传递给结构体timeval类型的tms。
int gettimeofday(struct timeval *tv, struct timezone *tz);
tz用来获取时区信息。不做介绍。
结构体timeval的定义为:
struct timeval
{
time_t tv_sec; //seconds
suseconds_t tv_usec; //microseconds
};
tz如果是NULL的话将不传递时区信息。tv提供秒为单位的和微妙为单位的从Epoch开始的计数。
结构体timeval的域为类型long的域。
此函数返回0,表示成功,-1表示失败。
Windows中,GetTickCount返回的是从系统启动到现在的毫秒。
int usleep(useconds_t usec);
定义在头文件unistd.h中。它使当前进程挂起至少usec微秒(百万分之一秒).睡眠时间可能会被任意系统活动或进程切换开销或系统计时器的精确度而轻微延迟。成功时返回0,错误时返回-1.
或者使用clock()来得到系统时间也是可以的。它返回从进程启动到现在经历的时间,单位是毫秒(千分之一秒)。定义在头文件time.h下.
clock_t clock(void);
相应代码如下。
- #include <time.h>
- #include <sys/time.h>
- #include <unistd.h>
- #include<stdlib.h>
- #include<math.h>
- #define DWORD unsigned long
- #define UINT64 unsigned long long
- const double SPLIT = 0.01;
- const int COUNT = 200;
- const double PI = 3.14159265;
- const int INTERVAL = 300;
- int main(int argc, char* argv[] )
- {
- struct timeval tms;
- DWORD busySpan[COUNT];
- DWORD idleSpan[COUNT];
- int half = INTERVAL/2, i;
- double radian = 0.0;
- for(i = 0; i < COUNT; ++i)
- {
- busySpan[i] = (DWORD)(half + (sin(PI * radian) * half));
- idleSpan[i] = INTERVAL - busySpan[i];
- radian += SPLIT;
- }
- clock_t startTime = 0;
- int j = 0;
- while(1)
- {
- j = j % COUNT;
- timerclear(&tms);
- gettimeofday(&tms,NULL);
- clock_t startTime = clock();
- while((clock()-startTime) <= busySpan[j])//clock返回该进程从启动到现在经历的毫秒数(千分之一秒)
- ;
- if(usleep(idleSpan[j]*1000)) //精确到微秒(百万分之一秒)的函数
- exit(-1);
- j++;
- }
- return 0;
- }
但对于多核CPU,如何限制进程在一个CPU上运行呢?
如何察看某个进程在哪个CPU上运行:
在控制台中输入:
#top -d 1
之后按下f.进入top Current Fields设置页面:
选中:j: P = Last used cpu (SMP)
则多了一项:P 显示此进程使用哪个CPU。
经过试验发现:同一个进程,在不同时刻,会使用不同CPU Core.这应该是Linux Kernel SMP处理的。
本程序通过这个方法查看,将会在多个CPU上运行。
想要让它在一个CPU上执行,可以这样做:
1.下载包schedtool.
在控制台中输入:sudo apt-get install schedtool,然后输入你的密码。
schedtool是Linux下用来查询或设置CPU状态的工具。通过不同的参数可以查看或设置不同的属性。
<span style="font-size:18px;">[<strong>-0</strong>|<strong>-N</strong>] [<strong>-1</strong>|<strong>-F</strong>] [<strong>-2</strong>|<strong>-R</strong>] [<strong>-3</strong>|<strong>-B</strong>] [<strong>-4</strong>|<strong>-I</strong>] [<strong>-5</strong>|<strong>-D</strong>] [<strong>-M</strong> <em>policy</em>] [<strong>-a</strong> <em>affinity</em>] [<strong>-p</strong> <em>prio</em>] [<strong>-n</strong> <em>nice_level</em>] [<strong>-e</strong> <em>command [arg ...]</em>] [<strong>-r</strong>] [<strong>-v</strong>] [<strong>-h</strong>] </span>我们这里要用到的是 -a和-e。其他可以参考这里:
http://linux.die.net/man/8/schedtool-a用来设置进程在哪个CPU上运行。-a的参数为:0x1 表示只运行在CPU0(00000001)0x2 表示只运行在CPU1(00000010)0x4表示紫云行在CPU2(00000100)0x8表示只运行在CPU3(00001000)etc.或者,多CPU运行可以这样表示,0x7表示可以运行在CPU0,1,2 (00000111)0x5表示可运行在CPU0,2 (00000101)以此类推。-e用来通过指定的参数来执行命令。后面的参数为控制台命令。
在Linux下,如何确认是多核或多CPU:
#cat /proc/cpuinfo
如果有多个类似以下的项目,则为多核或多CPU:
processor : 0
......
processor : 1
在编译后,我们执行命令:sched -a 0x1 -e ./桌面/sin
可以通过上面介绍的方法查看进程sin是否在同一个CPU上运行。
然后就可以通过系统监视器查看运行结果啦!
运行结果(橙色线):
还有一段Python的代码,运行是与上面类似的,这个来自于网上^_^:
- #!/usr/bin/env python
- import itertools, math, time, sys
- time_period = float(sys.argv[1]) if len(sys.argv) > 1 else 30 # seconds
- time_slice = float(sys.argv[2]) if len(sys.argv) > 2 else 0.04 # seconds
- N = int(time_period / time_slice)
- for i in itertools.cycle(range(N)):
- busy_time = time_slice / 2 * (math.sin(2*math.pi*i/N) + 1)
- t = time.clock() + busy_time
- while t > time.clock():
- pass
- time.sleep(time_slice - busy_time);
在控制台下输入命令:sched -a 0x1 -e python ./桌面/sin_p.py(此处写你源文件的路径).即可!
版权声明:本文为博主原创文章,未经博主允许不得转载。
linux top & cset&schedtool对于多核CPU,如何限制进程在一个CPU上运行
(2013-05-30 18:02:14)标签: it |
对于多核CPU,如何限制进程在一个CPU上运行呢?
本程序通过这个方法查看,将会在多个CPU上运行。
想要让它在一个CPU上执行,可以这样做:
在编译后,我们执行命令:sched -a 0x1 -e ./桌面/sin
可以通过上面介绍的方法查看进程sin是否在同一个CPU上运行。
然后就可以通过系统监视器查看运行结果啦!
运行结果(橙色线):
还有一段Python的代码,运行是与上面类似的,这个来自于网上^_^:
#!/usr/bin/env python import itertools, math, time, sys time_period = float(sys.argv[1]) if len(sys.argv) > 1 else 30 # seconds time_slice = float(sys.argv[2]) if len(sys.argv) > 2 else 0.04 # seconds N = int(time_period / time_slice) for i in itertools.cycle(range(N)): busy_time = time_slice / 2 * (math.sin(2*math.pi*i/N) + 1) t = time.clock() + busy_time while t > time.clock(): pass time.sleep(time_slice - busy_time);
在控制台下输入命令:sched -a 0x1 -e python./桌面/sin_p.py(此处写你源文件的路径).即可!
suse real time quick start guide
1, CPU shield类型(3种)
* root: 包括所有可用CPUS
* system: 包括所有没有屏蔽的cpus
* user: 包括所有已经屏蔽的cpus
2, 查看cpu shield情况
rtdemo:~ # cset shield
cset: **> shielding not active on system
3, 创建user shield类型cpuset
rtdemo:~ # cset shield --cpu=1,3,5-7
cset: --> activating shielding:
cset: moving 132 tasks from root into system cpuset...
[==================================================]%
cset: "system" cpuset of CPUSPEC(0,2,4) with 132 tasksrunning
cset: "user" cpuset of CPUSPEC(1,3,5-7) with 0 tasks running
rtdemo:~ # cset shield
cset: --> shielding system active with
cset: "system" cpuset of CPUSPEC(0,2,4) with 132 tasksrunning
cset: "user" cpuset of CPUSPEC(1,3,5-7) with 0 tasks running
rtdemo:~ # ps aux | wc -l
299
4, 查看cpu shield情况
rtdemo:~ # cset shield --verbose
cset: --> shielding system active with
cset: "system"&n
1.cset shield -e -- schedtool-a 0x02 -e
注意:执行cset之前,先激活CPU内核 :cset shield--cpu=0,1,2,3
Usage: cset shield [options] [path/program]
Options:
2.CPUAffinity的设置,到底在系统中会有什么样的积极影响,切换cpu和限制在同一个cpu上到底会让一个进程的效率有什么改变,为此做了一些研究,结论如下:
- CPUCache可以在绑定的情况下,提高命中率。如果一个线程在多个Processor中来回切换,可能会导致CPU的cache持续失效
- 如果多个线程访问的数据相同,设置同样的Affinity Mask可以帮助这个Processor提高命中
- 可以让一些需要高优先级的Process独享一个Processor。通过将系统其他的Process绑定到一个processor上,并将高优先级的Process绑定到空闲的Processor上
对于一个开发者来说,他可以直接使用Linux内核2.5.8版本以后提供的API函数,用来设置自己进程的AffinityMask,但是对于系统程序或者不是自己开发的进程怎么办。如果我们不能设置第三方程序的Mask,那么上文的第三点,让某个进程独享一个Processor就无法实现了。
Debian提供了一个工具:schedtool(其他发行版还没有验证),可以使用他来设置一个pid的AffinityMask。不过想要把系统所有的进程全部都设置一遍,非常的没有效率。这里有一个简单的办法,因为AffinityMask的设置是继承的,子进程会沿用父进程的Mask,我们只需要在系统的启动文件中,将pid为1的系统启动进程设置成我们想要的mask,那么后面的所有系统服务就可以继承这个值了。
修改 /etc/rc.sysinit 在最前方添加
/bin/schedtool -a 0x1 1 /bin/schedtool -a 0x1 $$
这样可以将pid为1和当前的进程的AffinityMask设置为1,也就是说只能使用第0号内核。这样,如果假设我们系统有四个核心,我们希望第一个个核心用来跑操作系统自己的相关进程和服务,后面三个核心各跑一个我们自己的服务,就只需要在自己的服务启动之后,再使用bind命令修改他们的Mask即可。
root@stacknode9:/home/localadmin/node_modules/xx#schedtool -h
get/set scheduling policies - v1.3.0, GPL'd, NO WARRANTY
USAGE: schedtoolPIDS
set scheduling policies:
----------------------------------------------------------------------------------------------
3.TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间对任务进行排序;而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定.
top - 12:38:33 up 50 days, 23:15,
Tasks: 203 total,
Cpu(s)
Mem:
Swap:
PIDUSER
25737oracle
16073oracle
16140oracle
16122oracle
22670oracle
一.
统计信息区前五行是系统整体的统计信息。
1. 第一行是任务队列信息
同 uptime
[root@localhost ~]# uptime
其内容如下:
12:38:33
up 50days
1 user
load average: 0.06, 0.60, 0.48
2. 第二、三行为进程和CPU的信息
当有多个CPU时,这些内容可能会超过两行。内容如下:
Tasks: 29 total
1 running
28 sleeping
0 stopped
0 zombie
Cpu(s): 0.3% us
1.0% sy
0.0% ni
98.7% id
0.0% wa
0.0% hi
0.0% si
3. 第四五行为内存信息。
内容如下:
Mem: 191272k total
173656k used
17616k free
22052k buffers
Swap: 192772k total
0k used
192772k free
123988k cached
二.
列名
PID
PPID
RUSER
UID
USER
GROUP
TTY
PR
NI
P
%CPU
TIME
TIME+
%MEM
VIRT
SWAP
RES
CODE
DATA
SHR
nFLT
nDRT
S
COMMAND
WCHAN
Flags
在命令行中输入 “top” 即可启动 top 。
top 的man 命令解释如下:
a: PID
b: PPID
c: RUSER
d: UID
e: USER
f: GROUP
g: TTY
h: PR
i: NI
j: P
k: %CPU
l: TIME
m: TIME+
n: %MEM
o: VIRT
p: SWAP
q: RES
r: CODE
s: DATA
t: SHR
u: nFLT
v: nDRT
w: S
x: Command
y: WCHAN
z: Flags
2.1 用快捷键更改显示内容。
(1)更改显示内容通过 f键可以选择显示的内容。
(2)按o键可以改变列的显示顺序。
注意:
进程top -c -d 5>/tmp/cpu.txt
grep -i 进程名 /tmp/cpu.txt |/tmp/cpu-01.txt
三.
详细内容可以参考MAN 帮助文档。这里列举部分内容:
命令格式:
top [-] [d] [p] [q] [c] [C][S]
参数说明:
d:
p:
q:该选项将使top没有任何延迟的进行刷新。如果调用程序有超级用户权限,那么top将以尽可能高的优先级运行。
S: 指定累计模式
s : 使top命令在安全模式中运行。这将去除交互命令所带来的潜在危险。
i:
c:
在top命令的显示窗口,我们还可以输入以下字母,进行一些交互:
帮助文档如下:
Help for Interactive Commands - procps version 3.2.7
Window 1:Def: Cumulative mode Off.
Press 'h' or '?' for help with Windows,
h或者?
k
i:忽略闲置和僵死进程。这是一个开关式命令。
q:
r:
S:切换到累计模式。
s :
f或者F :从当前显示中添加或者删除项目。
o或者O
l: 切换显示平均负载和启动时间信息。即显示影藏第一行
m: 切换显示内存信息。即显示影藏内存行
t : 切换显示进程和CPU状态信息。即显示影藏CPU行
c:
M : 根据驻留内存大小进行排序。
P:根据CPU使用百分比大小进行排序。
T: 根据时间/累计时间进行排序。
W:
taskset编辑
目录
1命令定义编辑
2命令描述编辑
0x00000001
|
代表 #0 CPU
|
0x00000003
|
代表 #0 和 #1 CPU
|
0xFFFFFFFF
|
代表 #0 到 #31 CPU
|
3参数描述编辑
-p, --pid
|
对一个现有的进程进行操作,而不是启动一个新的进程
|
-c, --cpu-list
|
使用 CPU 编号替代位标记,这可以是一个列表,列表中可以使用逗号分隔,或者使用 "-" 进行范围标记,例如:0,5,7,9-11
|
-h, --help
|
打印帮助信息
|
-V, --version
|
打印版本信息
|
4使用帮助编辑
-
使用默认的行为,用给定的 CPU 核运行位标记运行一个进程taskset mask command [arguments]
-
获取一个指定进程的 CPU 核运行位标记taskset -p pid
-
设定一个指定进程的 CPU 核运行位标记taskset -p mask pid