编程之美1 让CPU占用率曲线听你指挥

Tag:Windows

题目

写一个程序,让用户决定Windows任务管理器(Task Manager)的CPU占用率。例如,可以实现下面三种情况:

  1. CPU的占用率固定在50%,为一条直线;
  2. CPU的占用率为一条直线,具体占用率由命令行参数决定(参数范围1-100);
  3. CPU的占用率状态是一个正弦曲线

思路与算法

观察我们的任务管理器,可以发现:
大约是1秒钟更新一次,一般情况下,使用率都很低,当用户运行一个程序,执行复杂操作时,cpu的使用率会急剧升高。
通过查阅资料可以知道:

在任务管理器的一个刷新周期内,CPU忙(执行应用程序)的时间和刷新周期总时间的比率,就是CPU的占用率。

问题一、二

1.想要操作CPU的使用率曲线,就需要使CPU在一段时间内跑busy和idle两个不同的循环。
对于一个空循环for(i = 0; i < n; i++)如何估算最合适的n值?
需要查阅资料:

假设这段代码要运行的CPU是P4 2.4Ghz(2.4 * 10 的9次方个时钟周期每秒)现代CPU每个时钟周期可以执行两条以上的代码,我们取平均值两条,CPU一秒钟可以运行空循环 2.4 * 10的9次方*2次。
我们可以使n低于这个数字,比如n = 9600000,sleep(10).

代码:

int main() {
	for(;;) {
		for(int i = 0; i < 9600000; i++) {
			;
		sleep(10);
	}
	return 0;
}

**缺点:**不能适应机器差异性

  1. 使用getTickCount和sleep
int busyTime = 10;
int idleTime = busyTime;
Int64 startTime = 0;
while(true) {
	startTime = GetTickCount();
	while((GetTickCount() - startTime) <= busyTime) 
		;
	sleep(idleTime);
}

缺点:都是假设只有当前程序在运行

  1. 使用perfmon.exe

perfrom是Windows管理工具组中的专业检测工具之一,可以获取有关操作系统、应用程序和硬件的各种效能计数器,画正弦曲线:

double split = 0.01;
int count = 200;
double pi = 3.14159265;
int interval = 300;

int main() {
	int[] busySpan[count];
	idlSpan[count];
	int half = intrnal / 2;
	double radian = 0.0;
	for(int i = 0; i < count; i++) {
		busySpan[i] = (half + (sin(pi * radian) * half));
		idleSpan[i] = interval - busySpan[i];
		radian += split;
	}
	startTime = 0;
	int j = 0;
	while(true) {
		j = j % count;
		startTime = GetTickCount();
		while((GetTickCount() - startTime) <= busySpan[j])
			;
		sleep(idleSpan[j]);
		j++;
	}
	reteurn 0;
}

问题三

想要让cpu的使用率成为一条正弦曲线,可以把一条正弦曲线0~2π之间的弧度等分成200份进行抽样,计算每个抽样点的振幅,然后每隔一段时间(例如300ms)取下一个抽样点,并让cpu工作对应振幅的时间。

代码

package arithmetic;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class drawSin implements Runnable {
    public void run() {
        final double SPLIT = 0.01;
        final int COUNT = (int)(2 / SPLIT);
        final double PI = Math.PI;
        final int interval = 100;
        long[] busy = new long[COUNT];
        long[] idle = new long[COUNT];
        int half = interval / 2;
        double x = 0.0;
        for(int i = 0; i < COUNT; i++) {
            busy[i] = (long)(half + (Math.sin(PI * x) * half))/ 2;
            idle[i] = interval - busy[i];
            x += SPLIT;
        }
        long start = 0;
        int j = 0;
        while (true) {
            j = j % COUNT;
            start = System.currentTimeMillis();
            while(System.currentTimeMillis() - start < busy[j]) ;
            try {
                Thread.sleep(idle[j]);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
            j++;
        }
    }
}
public class Main {
    public static void main(String[] args) throws Exception {
       Runtime runtime = Runtime.getRuntime();
       ExecutorService executorService = Executors.newFixedThreadPool(runtime.availableProcessors());
        for (int i = 0; i < runtime.availableProcessors(); i++){//每个核心都上一个线程
            executorService.execute(new drawSin());
        }
        executorService.shutdown();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值