编程之美上的第一题,任务管理器上显示的使用率是这样计算的,在其刷新周期内实际执行的指令的条数/总共可以执行的条数。总的执行条数,可以通过主频算得,还要考虑超流水;实际执行条数就难算了。又注意到,CPU在执行运算时是全速进行的,所以可以让CPU在一小段时间内全速执行,一小段时间里什么也不干。

  另外,多核CPU会发生进程在CPU之间的切换,不过各种操作系统都有设置进程CPU亲和度的系统调用,linux系统是sched_setaffinity。

  下面这个程序可以运行在双核以上电脑上,你会看到一个CPU在画直线,另一个在画sin曲线。很好玩吧!

#include <stdio.h>
#include
<math.h>

#include
<unistd.h>
#include
<sys/times.h>
#define __USE_GNU
#include
<sched.h>


// 设置进程在哪个cpu上运行
void set_cpu(int id)
{
cpu_set_t mask;
CPU_ZERO(
&mask);
CPU_SET(id,
&mask);
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
fprintf(stderr,
"warning: could not set CPU affinity\n");
}
}

clock_t Hz;
// 时钟中断频率

void draw_line(int cpu_id)
{
set_cpu(cpu_id);

clock_t busy
= Hz / 50; // 20ms
clock_t idle = busy;
clock_t start;
while (1) {
start
= times(NULL);
// busy loop
while (times(NULL) - start <= busy)
;

// idle loop
usleep(idle * 1000 * 1000 / Hz);
}
}

#define COUNT 200 // 分成200个小区间
void draw_sin(int cpu_id)
{
set_cpu(cpu_id);

int i;
const double PI = 3.1415926;
const clock_t INTERVAL = Hz * 2;
clock_t busy_span[COUNT];
clock_t idle_span[COUNT];

clock_t half
= INTERVAL / 2;
double radian = 0.0;
for (i=0; i < COUNT; ++i) { // 预计算
busy_span[i] = half * (1 + sin(PI * radian));
idle_span[i]
= INTERVAL - busy_span[i];
radian
+= (2 / COUNT);
}

clock_t start;
for (i = 0; 1; ++i) {
i
%= COUNT;
start
= times(NULL);
while (times(NULL) - start <= busy_span[i])
;
usleep(idle_span[i]
* 1000 * 1000 / Hz);
}
}

int main()
{
Hz
= sysconf(_SC_CLK_TCK);

pid_t pid;
pid
= fork();
if (pid == 0) {
draw_line(
0);
}
else {
draw_sin(
1);
}
return 0;
}

执行的效果:

posted on 2011-06-21 11:02  yongmou-  阅读(2639)  评论(0编辑  收藏  举报