《编程之美》学习笔记——指挥CPU占用率
问题:
写一个程序。让用户来决定Windows任务管理器(Task Manager)的CPU占用率(单核)。
有下面几种情况:
1.CPU占用率固定在50%,为一条直线
2.CPU的占用率为一条直线,详细占用率由命令行參数决定(范围1~100)
3.CPU的占用率状态为一条正弦曲线
4.多核处理器情况下上述问题怎么解决
分析与解答
首先确定CPU占用率的定义,即在任务管理器的一个刷新周期内。CPU忙(运行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率。也能够说成,任务管理器中显示的是每一个刷新周期内CPU占用率的统计平均值。
所以能够写个程序。在一个刷新周期中。一会儿忙,一会儿闲,调节忙/闲比例,就能够控制CPU占有率了。
一个刷新时间是多久,书上说,通过对任务管理器观測,大约是1秒。鼠标移动、后台程序等都会对曲线造成影响!
单核环境下。空死循环会导致100%的CPU占用率。双核环境下,CPU总占用率大约为50%。四核是25%左右。
解法一:简单解法
Busy用可循环来实现,for(i=0;i<n;i++) ;
相应的汇编语言为
loop;
mov dx i ;将i置入dx寄存器
inc dx ;将dx寄存器加1
mov dx i ;将dx中的值赋回i
cmp i n ;比較i和n
j1 loop 。i小于n时则反复循环
我的cpu是 I5 2410M 2.30GHZ(双核四线程,如图) 由于眼下的cpu每一个时钟周期可运行两条以上的代码,取平均值2,于是(2300000000*2)/5=920000000(循环/秒) 每秒能够运行循环920000000次。
不能简单的取n=920000000然后sleep(1000)。假设让cpu工作1s,歇息1s非常可能是锯齿。先达到一个峰值然后跌入一个非常低的占有率。所以我们睡眠时间改为100ms。100ms比較接近windows的调度时间,n=92000000。假设sleep时间选的太小。会造成线程频繁的唤醒和挂起,无形中添加了内核时间的不确定性因此代码例如以下:
#include <windows.h> int main(void)
{
//Run on CPU 0(0x00000001)(00000001)
//Run on CPU 1(0x00000002)(00000010)
//Run on CPU 0 AND CPU 1(0x00000003)(00000101)
//Run on CPU 2(0x00000004)(00000100)
//......
//SetProcessAffinityMask(GetCurrentProcess(),0x1);//进程与指定cpu绑定
SetThreadAffinityMask(GetCurrentThread(), 0x1);//线程与指定cpu绑定
while(true)
{
for(int i=0;i<92000000;i++)
;
Sleep(100);
}
return 0;
}
使用SetProcessAffinityMask函数。进程与CPU绑定。得到例如以下图。
使用SetThreadAffinityMask函数,进程与CPU绑定,得到例如以下图。
解法二:使用GetTickCount()和Sleep()
GetTickCount()能够得到“系统启动到如今”所经历的时间的毫秒值,最多能够统计49.7天,能够利用GetTickCount()推断循环的时间,代码例如以下:
#include <windows.h> const int busyTime=100;
const int idleTime=busyTime; int main(void)
{
double startTime;
SetProcessAffinityMask(GetCurrentProcess(), 0x1);
while(true)
{
startTime=GetTickCount();
while((GetTickCount() - startTime) <= busyTime)
{
;
}
Sleep(idleTime);
}
return 0;
}
效果例如以下图所看到的,与第一种解法效果差点儿相同,由于都如果当前系统仅仅有当前程序在执行,但实际上,操作系统有非常多程序会同一时候调试执行各种任务,如果此刻进程使用20%的cpu。那我们的程序仅仅有使用30%的cpu才干达到50%的效果。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luX2dlZWs=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
解法三:能动态适应的解法
using System;
using System.Diagnostics;
namespace CPU
{
class Program
{
static void Main(string[] args)
{
cpu(1000);
}
static void cpu(double level)
{
PerformanceCounter p = new PerformanceCounter("Processor", "% Processor Time", "_Total");
if (p == null)
{
return;
}
while (true)
{
if (p.NextValue() > level)
System.Threading.Thread.Sleep(1000);
}
}
}
}
解法四:正弦曲线
#include <windows.h>
#include <math.h>
int main(void)
{
SetProcessAffinityMask(GetCurrentProcess(), 0x1);
const double SPLIT=0.01;
const int COUNT=200;
const double PI=3.14159265;
const int INTERVAL=300;
DWORD busySpan[COUNT]; //array of busy time
DWORD idleSpan[COUNT]; //array of idle time
int half=INTERVAL/2;
double radian=0.0;
for(int i=0;i<COUNT;i++)
{
busySpan[i]=(DWORD)(half+(sin(PI*radian)*half));
idleSpan[i]=INTERVAL-busySpan[i];
radian+=SPLIT;
}
DWORD startTime=0;
int j=0;
while(true)
{
j=j%COUNT;
startTime=GetTickCount();
while((GetTickCount()-startTime)<=busySpan[j])
;
Sleep(idleSpan[j]);
j++;
}
return 0;
}
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luX2dlZWs=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
进一步讨论:
控制CPU占用率。由于要调用Windows的API。要考虑到多核、超线程的情况,要考虑到不同版本号的Windows的计时相关的API的精度不同,使问题变得相当复杂,若再考虑其他程序的CPU占用率,则该问题则变得非常烦人。(taskmgr调用了一个未公开的API)。对CPU核数的推断,书上是调用GetProcessorInfo。事实上能够直接调用GetSystemInfo,SYSTEM_INFO结构的dwNumberOfProcessors成员就是核数。
假设不考虑其他程序的CPU占用情况,能够在每一个核上开一个线程,执行指定的函数。实现每一个核的CPU占用率同样。假设CPU占用率曲线不是周期性变化,就要对每一个t值都要计算一次,否则,能够仅仅计算第一个周期内的各个t值。其他周期的直接取缓存计算结果。
#include<iostream>
#include<cmath>
#include<windows.h> static int PERIOD = 60 * 1000; //周期ms
const int COUNT = 300; //一个周期计算次数
const double GAP_LINEAR = 100; //线性函数时间间隔100ms
const double PI = 3.1415926535898; //PI
const double GAP = (double)PERIOD / COUNT; //周期函数时间间隔
const double FACTOR = 2 * PI / PERIOD; //周期函数的系数
static double Ratio = 0.5; //线性函数的值 0.5即50%
static double Max=0.9; //方波函数的最大值
static double Min=0.1; //方波函数的最小值 typedef double Func(double); //定义一个函数类型 Func*为函数指针
typedef void Solve(Func *calc);//定义函数类型,參数为函数指针Func* inline DWORD get_time()
{
return GetTickCount(); //操作系统启动到如今所经过的时间ms
} double calc_sin(double x) //调用周期函数solve_period的參数
{
return (1 + sin(FACTOR * x)) / 2; //y=1/2(1+sin(a*x))
}
double calc_fangbo(double x) //调用周期函数solve_period的參数
{
//方波函数
if(x<=PERIOD/2) return Max;
else return Min;
} void solve_period(Func *calc) //线程函数为周期函数
{
double x = 0.0;
double cache[COUNT];
for (int i = 0; i < COUNT; ++i, x += GAP)
cache[i] = calc(x);
int count = 0;
while(1)
{
unsigned ta = get_time();
if (count >= COUNT) count = 0;
double r = cache[count++];
DWORD busy = r * GAP;
while(get_time() - ta < busy) {}
Sleep(GAP - busy);
}
} void solve_linear(Func*) //线程函数为线性函数,參数为空 NULL
{
const unsigned BUSY = Ratio * GAP_LINEAR;
const unsigned IDLE = (1 - Ratio) * GAP_LINEAR;
while(1)
{
unsigned ta = get_time();
while(get_time() - ta < BUSY) {}
Sleep(IDLE);
}
} void run(int i=1,double R=0.5,double T=60000,double max=0.9,double min=0.1)
//i为输出状态,R为直线函数的值,T为周期函数的周期,max方波最大值,min方波最小值
{
Ratio=R; PERIOD=T; Max=max; Min=min;
Func *func[] = {NULL ,calc_sin,calc_fangbo}; //传给Solve的參数。函数指针数组
Solve *solve_func[] = { solve_linear, solve_period}; //Solve函数指针数组
SYSTEM_INFO info;
GetSystemInfo(&info); //得到cpu数目
int NUM_CPUS = info.dwNumberOfProcessors;
HANDLE *handle = new HANDLE[NUM_CPUS];
DWORD *thread_id = new DWORD[NUM_CPUS]; //线程id switch(i)
{
case 1: //cpu0 ,cpu1都输出直线
{
for (int i = 0; i < NUM_CPUS; ++i)
{
Func *calc = func[0];
Solve *solve = solve_func[0];
if ((handle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[i])) != NULL) //创建新线程
SetThreadAffinityMask(handle[i], i); //限定线程执行在哪个cpu上
}
WaitForSingleObject(handle[0],INFINITE); //等待线程结束
break;
}
case 2: //cpu0直线,cpu1正弦
{
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[0],
(VOID*)func[0], 0, &thread_id[1])) != NULL) //创建新线程
SetThreadAffinityMask(handle[1], 1); //限定线程执行在哪个cpu上
Func *calc = func[1];
Solve *solve = solve_func[1];
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[0])) != NULL) //创建新线程
SetThreadAffinityMask(handle[0], 2); //限定线程执行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE); //等待线程结束
break;
}
case 3: //cpu0直线,cpu1方波
{
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[0],
(VOID*)func[0], 0, &thread_id[0])) != NULL) //创建新线程
SetThreadAffinityMask(handle[0], 1); //限定线程执行在哪个cpu上
Func *calc = func[2];
Solve *solve = solve_func[1];
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[1])) != NULL) //创建新线程
SetThreadAffinityMask(handle[1], 2); //限定线程执行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE); //等待线程结束
break;
}
case 4: //cpu0正弦。cpu1方波
{
if ((handle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve_func[1],
(VOID*)func[1], 0, &thread_id[0])) != NULL) //创建新线程
SetThreadAffinityMask(handle[0], 1); //限定线程执行在哪个cpu上
Func *calc = func[2];
Solve *solve = solve_func[1];
if ((handle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)solve,
(VOID*)calc, 0, &thread_id[1])) != NULL) //创建新线程
SetThreadAffinityMask(handle[1], 2); //限定线程执行在哪个cpu上
WaitForSingleObject(handle[0],INFINITE); //等待线程结束
break;
}
default: break;
}
} void main()
{
//run(1,0.5); //cpu1 ,cpu2都输出50%的直线
run(2,0.5,30000); //cpu1 0.5直线,cpu2正弦周期30000
//run(3); //cpu1直线,cpu2方波
//run(4,0.8,30000,0.95,0.5); //cpu1正弦。cpu2 0.95-0.5的方波
}
这是是第一次CPU跑直线。第二个CPU跑正弦函数~~~~~~~~·
《编程之美》学习笔记——指挥CPU占用率的更多相关文章
- 编程之美_1.1 让CPU占用率曲线听你指挥
听到有人说让要写一个程序,让用户来决定Windows任务管理器的CPU占用率. 觉得很好奇.但第一个想法就是写个死循环.哈哈.不知道具体的占用率是多少,但至少能保证在程序运行时,CPU的占用率终会稳定 ...
- 编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器)
[目录] 不考虑其他进程,cpu画正弦曲线 获取总体cpu利用率 获取多核处理器单个cpu利用率 考虑其他进程,cpu画正弦曲线 下面的程序针对多核处理器,可以设置让任何一个cpu显示相应的曲线(本文 ...
- 让cpu占用率曲线听你指挥(多核处理器)
编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器) [版权声明]转载请注明出处 http://www.cnblogs.com/TenosDoIt/p/3242910.html [目录] 不考 ...
- 编程之美读书笔记1.1——让CPU占用率曲线听你的指挥
http://blog.csdn.net/pipisorry/article/details/36189155 <strong><span style="font-size ...
- 编程之美 之 让CPU占用率听你指挥
昨天在bbs上淘到了这本编程之美.顺手刷了第一章,很有意思.第一章的要求是要控制CPU曲线,绘制出对应的形状. 拿到这个问题,我的第一反应是, 是不是有这么一个API,能在任务管理器上的对应区域直接绘 ...
- Shell编程检测监控mysql的CPU占用率
shell编程很强大! 网站访问量大的时候mysql的压力就比较大,当mysql的CPU利用率超过300%的时候就不能提供服务了,近乎卡死状态,这时候最好的方法就是重启mysql服务.由于这种事具有不 ...
- 第1章 游戏之乐——让CPU占用率曲线听你指挥
让CPU占用率曲线听你指挥 写一个程序,让用于来决定Windows任务管理器(Task Manager)的CPU占用率.程序越精简越好,计算机语言不限.例如,可以实现下面三种情况: CPU的占用率固定 ...
- 《JavaScript DOM 编程艺术》 学习笔记
目录 <JavaScript DOM 编程艺术> 学习笔记 第一章 js简史 第二章 js语法 准备工作 语法 第三章 DOM DOM中的D DOM中的O DOM中的M 第四章 js图片库 ...
- 1.1 让CPU占用率曲线听你指挥[cpu manager]
[本文链接] http://www.cnblogs.com/hellogiser/p/cpu-manager.html [题目] 写一个程序,让用户来决定Windows任务管理器(Task Manag ...
随机推荐
- mysql读写分离
严格意义上讲,MySQL 读.写分离确实存在上述情况,这是由Master-Slave 异步复制存在延迟所导致的,且Master binlog的写入为多线程,而Slave同步的sql_thread为单线 ...
- maven 添加自己的包
mvn install:install-file -Dfile=d:/flea.jar -DgroupId=com.flea.bussiness -DartifactId=flea -Dversion ...
- nyoj-709-异形卵(水题)
异 形 卵 时间限制:1000 ms | 内存限制:65535 KB 难度: 描写叙述 我们探索宇宙,是想了解浩瀚星空的奥妙.但我们却非常少意识到宇宙深处藏匿的危急,它们无时无刻不紧盯着我们的地球 ...
- iOS圆盘转动引导图的简单实现
最近更新的一批app,好多都采用了圆盘转动的效果,比如:百度音乐.当当,大概效果如下: 看看这个是怎么实现的吧. 一.视图元素布局 首先需要明确,这些视图元素是分布在一个圆周上的,通过滑动位置,以圆周 ...
- android 中文 api (71) —— BluetoothServerSocket[蓝牙]
前言 本章内容是 android.bluetooth.BluetoothServerSocket,为Android蓝牙部分的章节翻译.服务器通讯套接字,与TCP ServerSocket类似.版本为 ...
- Ext JS学习第三天 我们所熟悉的javascript(二)
•javascript之函数 •对于Ext开发者,我还是希望你能对javascript原生的东西非常了解.甚至熟练掌握运用.那么函数,无疑是非常重要的概念.首先在前面一讲,我们知道了函数也是一种数据类 ...
- c 计算Fibonacci数列:1,1,2,3,5,8,13……这题也是很经典。
输出数字序列2/,/,/,/,/,/...,输出个数由键盘输入.注意输入使用scanf输入 比如: 输入 3输出为 / / / 输入 输出为 / / / / #include<stdio.h&g ...
- CSS的z-index(分层)
z-index是针对网页显示中的一个特殊属性.因为显示器是显示的图案是一个二维平面,拥有x轴和y轴来表示位置属性.为了表示三维立体的概念如显示元素的上下层的叠加顺序引入了z-index属性来表示z轴的 ...
- 在VS2010上使用C#调用非托管C++生成的DLL文件
背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用 ...
- Oracle数据库的安装详解
1.写在安装前的话 可能有很多的菜鸟十分害怕大型软件的安装,因为安装过程中的一些错误很让他们头疼.下面我就写一个教程,希望能对大家有帮助,在安装ORACLE之前给大家一点点的意见: (1)尽量要安装L ...