玩转双核CPU:左手画圆,右手画方

简介:

 两年前,微软亚洲研究院出版了《编程之美》一书,其中的第一章第一节“让CPU占用率曲线听你指挥”一文,可谓是在全国范围内掀起了一股玩转CPU占用率曲线热。我本人甚至在坐公交的时候都在思考如何折腾CPU占用率曲线。

     书中给出了这样一张让人耳目一新的图,吸引了万千IT少年:

      image

 

     也许您会觉得这还不够好玩。我也是。对了,今天流牛木马打算与各位看官讨论的,是以下这幅图的效果——双核的CPU,左手画圆,右手画方!

image

 

     该书出版的时候,我正在微软亚洲研究院创新工程组实习,该书的好几位作者都是我的好朋友,如李东、陈远等 ——于是我可以负责任地告诉大家,该书的所有实习生作者 ,当时他们使用的都是Intel P4 3.4Ghz单核CPU ! o(∩_∩)o

    今天突然想到了这里,就打算拿我的Thinkpad T60来试试。CPU是Genuine Intel(R) CPU T2400 @1.83Ghz , 双核。

    首先我将书中提供的C++代码翻译成了C# .翻译过程没任何技术难度,仅供各位看官了解个大概:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            const double SPLIT = 0.01;
            const int COUNT = 200;
            const double PI = 3.14159265;
            const int INTERVAL = 100;
            double[] busySpan = new double[COUNT];  //array of busy times
            double[] idleSpan = new double[COUNT];  //array of idle times
            int half = INTERVAL / 2;
            double radian = 0.0;
            for (int i = 0; i < COUNT; i++)
            {
                busySpan[i] = (double)(half + (Math.Sin(PI * radian) * half));
                idleSpan[i] = INTERVAL - busySpan[i];
                radian += SPLIT;
            }
            double startTime = 0;
            int j = 0;
            while (true)
            {
                j = j % COUNT;
                startTime = Environment.TickCount;
                while ((Environment.TickCount - startTime) <= busySpan[j]) ;
                System.Threading.Thread.Sleep((int)idleSpan[j]);
                j++;
            }
        }
    }
}

将这段代码直接F5, 运行结果如下:

1

    果然,与大家意料的一样,两个CPU中都会显示出非常扭曲、不规则的正弦曲线。

    按照书中的说法,C++程序可以使用WinAPI里的SetThreadAffinityMast()函数,将程序固定到某个特定的CPU上执行。

    查了下MSDN,当然,在.NET里,也有Manage的相似代码。见http://msdn.microsoft.com/zh-tw/library/system.diagnostics.process.processoraffinity(VS.80).aspx

    按照MSDN,在代码中加入了简单的两句:

     System.Diagnostics.Process p = System.Diagnostics.Process.GetCurrentProcess();             
          p.ProcessorAffinity = (IntPtr)0x0001;

    然后再次F5, CPU中的曲线如下图所示:

2

   1号CPU成规则的正弦曲线相当完美,2号CPU使用率一直为0.

   看来这就是书中想让大家达到的效果了。

 

   这个效果让人感觉非常枯燥乏味。2号CPU的资源就浪费掉了,有没有办法将它利用起来呢?

   让我们来分析这两句代码:

while ((Environment.TickCount - startTime) <= busySpan[j]) ;

System.Threading.Thread.Sleep((int)idleSpan[j]);

     它的意思是,在规定好的时间间隔内(程序中规定了是100毫秒),满负载运行(通过空循环)构成正弦函数需要运行的时间(由之前的计算得到),其余时间就睡觉。如运行69毫秒,睡觉31毫秒,那么在这100毫秒的时间段,CPU的平均占用率就是69%。由于CPU占用率曲线是1秒钟更新一次的,程序使用的每100毫秒一个平均值节点,曲线的平滑度足够了。

    继续发散。刚才的例子,如果是运行69毫秒,睡觉50毫秒呢? 那么当前的100毫秒CPU占用率仍然会是69%,但如果算法不加调整,仍然以100毫秒为一个平均值节点,这就影响到了下一个100毫秒的CPU占用率。前一个影响后一个,如多米诺骨牌一样,整体的曲线就完全错误了。

    也就是说,我们用来控制CPU平均占用率的时间段,每段必须相等。

    我们考虑到以上的代码中,在1号CPU中运行了69毫秒,剩下了31毫秒如果转到2号CPU中运行,1号CPU的占用就会降到0,但与此同时我们就可以在2号CPU中“画方”了。

    概括起来说就是,当1号CPU小寐的时候,程序在2号CPU中“画方”;1号CPU小寐结束的时候,2号CPU中当前周期的“方”必须完成。

    需要注意的是,假如1好CPU画了69毫秒,那么2号CPU一定只能画31毫秒。

    按照这个思路,我们先实验一下简单的:在1号CPU中画正弦曲线后的休息时间段,我们在2号CPU中画余弦曲线。呵呵,初中学的三角函数你忘了吗?

    我们将原代码中的空循环改为:

            while (true)
            {
                j = j % COUNT;
                p.ProcessorAffinity = (IntPtr)0x0001;
                startTime = Environment.TickCount;
                while ((Environment.TickCount - startTime) <= busySpan[j]) ;
                p.ProcessorAffinity = (IntPtr)0x0002;
                while ((Environment.TickCount - startTime) <= idleSpan[j]) ;
                j++;
            }

    “左手正弦,右手余弦”结果差强人意:

image

     我们注意到这个曲线没有之前单CPU运行时那么精确的。

     原因是我们切换CPU的运营占用了时间。例如,以前正弦画了69毫秒,我们计算出余弦应该画31毫秒,但切换CPU的操作可能占用了3毫秒(或更多、或每次耗时都不同),整体就不在100毫秒这个间隔范围了,所以曲线结果有误差。

 

    到这里,我的思路已经说完了,相信大家已经明白。

 

     不过, 走到这一步,追求完美的我们,的确是遇到了一点障碍。

     我经过一些周期上的微调,并且将余弦函数改为了简单的方波函数,最终效果正如本文开头展示的一样,还是不错的。

    调整办法?呵呵,真不好意思,我暂时还没有想到一个足够说服大家、可以公式化的调整办法,就请各位看官在这里八仙过海,各显神通咯~

 

image



本文转自 流牛木马 博客园博客,原文链接:http://www.cnblogs.com/azure/archive/2010/03/24/1693365.html,如需转载请自行联系原作者

相关文章
|
24天前
|
JSON Java Serverless
nacos常见问题之cpu和内存占用高如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
138 0
|
3月前
|
Linux
|
2月前
|
弹性计算
2024阿里云幻兽帕鲁/Palworld服务器价格表(CPU/内存/带宽/磁盘收费标准)
2024年阿里云幻兽帕鲁专用服务器的价格根据不同的配置有所不同。 • 4核16G配置的价格为32元/月,如果选择购买3个月,则价格为96元。 • 8核32G配置的价格为90元/月,如果选择购买3个月,则价格为271元。 另外,还有配置为4核16G10M带宽的服务器,其价格为26元/月起。而8核32G10M带宽的价格也是90元/月。
93 1
|
3月前
|
监控 关系型数据库 MySQL
innodb_buffer_pool_instances 如何根据cpu和内存进行配置
`innodb_buffer_pool_instances` 是用于配置 InnoDB 缓冲池实例数的参数。每个实例都管理缓冲池的一部分,这有助于提高并发性能。通常,你可以根据系统的 CPU 和内存来调整这个参数,以获得更好的性能。 以下是一些建议和步骤,帮助你根据 CPU 和内存进行 `innodb_buffer_pool_instances` 的配置: 1. **了解系统资源:** 首先,了解系统的硬件资源,特别是内存和CPU。检查系统上可用的物理内存和 CPU 核心数量。 2. **考虑每个实例的大小:** 在配置 `innodb_buffer_pool_instances` 时,
|
17天前
|
存储 缓存 PHP
阿里云服务器实例、CPU内存、带宽、操作系统选择参考
对于使用阿里云服务器的用户来说,云服务器的选择和使用非常重要,如果实例、内存、CPU、带宽等配置选择错误,可能会影响到自己业务在云服务器上的计算性能及后期运营状况,本文为大家介绍一下阿里云服务器实例、CPU内存、带宽、操作系统的选择注意事项,以供参考。
阿里云服务器实例、CPU内存、带宽、操作系统选择参考
|
1月前
|
弹性计算 固态存储 Linux
2024年阿里云服务器租用详细价格表(CPU/内存/带宽/系统盘)
2024阿里云服务器租用优惠价格表,轻量服务器2核2G3M带宽轻量服务器一年61元,2核4G4M带宽轻量服务器一年165元12个月,ECS云服务器e系列2核2G配置、3M固定带宽、40G ESSD Entry云盘,99元一年、2核4G服务器30元3个月、2核4G配置365元一年、2核8G配置522元一年,云服务器u1、云服务器c7、g7和r7优惠价格表,CPU内存带宽系统盘配置详细报价:
729 3
|
1月前
|
弹性计算 固态存储 调度
阿里云服务器部署配置选择全攻略,ECS实例规格、CPU内存配置
阿里云服务器部署配置选择全攻略,ECS实例规格、CPU内存配置,CPU内存、公网带宽和系统盘怎么选择?个人用户选择轻量应用服务器或ECS通用算力型u1云服务器,企业用户选择ECS计算型c7、通用型g7云服务器,阿里云百科分享阿里云服务器配置选择方法
|
1月前
|
弹性计算 固态存储 调度
阿里云服务器选购指南_2024新版CPU内存带宽系统盘选择攻略
阿里云服务器选购指南_2024新版CPU内存带宽系统盘选择攻略,CPU内存、公网带宽和系统盘怎么选择?个人用户选择轻量应用服务器或ECS通用算力型u1云服务器,企业用户选择ECS计算型c7、通用型g7云服务器,阿里云百科分享阿里云服务器配置选择方法

热门文章

最新文章