让cpu占用率曲线听你指挥(多核处理器)- 编程之美 1.1


下面的程序针对多核处理器,可以设置让任何一个cpu显示相应的曲线(本文以正弦曲线为例)
代码编译环境:windows 7 64位 酷睿 i5 处理器,vs2010.
可以修改CpuSin函数的计算 busySpan 和 idleSpan的部分以显示不同的曲线。
下面的代码没有考虑cpu中其他进程的占用情况,这种情况详见第二部分
复制代码
 1 #include <windows.h>
 2 #include <stdio.h>
 3 #include <math.h>
 4 
 5 //把一条正弦曲线0~2pi 之间的弧度等分200份抽样,计算每个点的振幅
 6 //然后每隔300ms设置下一个抽样点,并让cpu工作对应振幅时间
 7 const int samplingCount = 200; //抽样点数目
 8 const double pi = 3.1415926;
 9 const int totalAmplitude = 300; //每个抽样点对应时间片
10 const double delta = 2.0/samplingCount;  //抽样弧度的增量
11 
12 int busySpan[samplingCount];//每个抽样点对应的busy时间
13 int idleSpan[samplingCount];//每个抽样点对应的idle时间
14 
15 //一个线程调用MakeUsageSin,并把该线程绑定到一个cpu,那么该cpu呈现正弦曲线
16 DWORD WINAPI MakeUsageSin(LPVOID lpParameter)
17 {
18     DWORD startTime = 0;
19     for(int j = 0; ; j = (j + 1) % samplingCount)
20     {
21         startTime = GetTickCount();
22         while ((GetTickCount() - startTime) < busySpan[j]);
23         Sleep(idleSpan[j]);
24     }
25 }
26 
27 //如果cpuindex < 0 则所有cpu都显示正弦曲线
28 //否则只有第 cpuindex个cpu显示正弦曲线
29 //cpuindex 从 0 开始计数
30 void CpuSin(int cpuIndex)
31 {
32     //计算 busySpan 和 idleSpan
33     double radian = 0;
34     int amplitude = totalAmplitude / 2;
35     for (int i = 0; i < samplingCount; i++)
36     {
37         busySpan[i] = (DWORD)(amplitude + sin(pi*radian)*amplitude);
38         idleSpan[i] = totalAmplitude - busySpan[i];
39         radian += delta;
40     }
41 
42     //获取系统cup数量
43     SYSTEM_INFO SysInfo;
44     GetSystemInfo(&SysInfo);
45     int num_processors = SysInfo.dwNumberOfProcessors;
46     if(cpuIndex + 1 > num_processors)
47     {
48         printf("error: the index of cpu is out of boundary\n");
49         printf("cpu number: %d\n", num_processors);
50         printf("your index: %d\n", cpuIndex);
51         printf("** tip: the index of cpu start from 0 **\n");
52         return;
53     }
54 
55     if(cpuIndex < 0)
56     {
57         HANDLE* threads = new HANDLE[num_processors];
58         for (int i = 0;i < num_processors;i++)
59         {
60             DWORD mask = 1<<i;
61             threads[i] = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
62             SetThreadAffinityMask(threads[i], 1<<i);//线程指定在某个cpu运行
63         }
64         WaitForMultipleObjects(num_processors, threads, TRUE, INFINITE);
65     }
66     else
67     {
68         HANDLE thread;
69         DWORD mask = 1;
70         thread = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
71         SetThreadAffinityMask(thread, 1<<cpuIndex);
72         WaitForSingleObject(thread,INFINITE);
73     }
74 
75 }
76 int main()
77 {
78 
79     CpuSin(0);
80     return 0;
81 }
复制代码
运行结果:

下面我们考虑其他进程对cpu的影响,即需要检测出某个cpu当前的使用率。
首先对于单核处理器获取cpu利用率,或者多核处理器获取总的cpu利用率,可以通过windows api “GetSystemTimes” 来实现
该函数声明如下:BOOL GetSystemTimes(LPFILETIME  IdleTime,LPFILETIME   KernelTime,LPFILETIME   UserTime),具体可以参考msdn接口介绍
cpu利用率计算公式为:CPURate=100.0-(NowIdleTime-LastIdleTime)/(NowKernelTime-LastKernelTime+NowUserTime-LastUserTime)*100.0
计算总的cpu利用率或者单核处理器cpu利用率的类实现如下:
复制代码
 1 class CCPUUseRate
 2 {
 3 public:
 4     BOOL Initialize() 
 5     {
 6         FILETIME ftIdle, ftKernel, ftUser;
 7         BOOL flag = FALSE;
 8         if (flag = GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
 9         {
10             m_fOldCPUIdleTime = FileTimeToDouble(ftIdle);
11             m_fOldCPUKernelTime = FileTimeToDouble(ftKernel);
12             m_fOldCPUUserTime = FileTimeToDouble(ftUser);
13 
14         }
15         return flag;
16     }
17     //调用Initialize后要等待1左右秒再调用此函数
18     int GetCPUUseRate()
19     {
20         int nCPUUseRate = -1;
21         FILETIME ftIdle, ftKernel, ftUser;
22         if (GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
23         {
24             double fCPUIdleTime = FileTimeToDouble(ftIdle);
25             double fCPUKernelTime = FileTimeToDouble(ftKernel);
26             double fCPUUserTime = FileTimeToDouble(ftUser);
27             nCPUUseRate= (int)(100.0 - (fCPUIdleTime - m_fOldCPUIdleTime) 
28                 / (fCPUKernelTime - m_fOldCPUKernelTime + fCPUUserTime - m_fOldCPUUserTime) 
29                 *100.0);
30             m_fOldCPUIdleTime = fCPUIdleTime;
31             m_fOldCPUKernelTime = fCPUKernelTime;
32             m_fOldCPUUserTime = fCPUUserTime;
33         }
34         return nCPUUseRate;
35     }
36 private:
37     double FileTimeToDouble(FILETIME &filetime)
38     {
39         return (double)(filetime.dwHighDateTime * 4.294967296E9) + (double)filetime.dwLowDateTime;
40     }
41 private:
42     double m_fOldCPUIdleTime;
43     double m_fOldCPUKernelTime;
44     double m_fOldCPUUserTime;
45 };
复制代码
注意:前后两次调用GetSystemTimes之间要间隔一定时间,使用方法如下:
复制代码
 1 int main()
 2 {
 3     CCPUUseRate cpuUseRate;
 4     if (!cpuUseRate.Initialize())
 5     {
 6         printf("Error! %d\n", GetLastError());
 7         getch();
 8         return -1;
 9     }
10     else
11     {
12         while (true)
13         {    
14             Sleep(1000);
15             printf("\r当前CPU使用率为:%4d%%", cpuUseRate.GetCPUUseRate());
16         }
17     }
18     return 0;
19 }
复制代码
对于计算多核处理器中单个cpu的使用率,可以使用pdh.h头文件中的接口,该头文件是visual studio自带的,包含该头文件时,还需要引入相关的lib库:
复制代码
 1 #include <TCHAR.h>
 2 #include <windows.h>
 3 #include <pdh.h>
 4 #include <cstdio>
 5 #include <cmath>
 6 #pragma comment(lib, "pdh.lib")
 7 
 8 //---------------------------------------------------comput the cpu usage rate
 9 static PDH_HQUERY cpuQuery;
10 static PDH_HCOUNTER cpuTotal;
11 
12 //cpuindex 为指定的cpu id ,从0开始
13 void init(int cpuIndex)
14 {
15     PDH_STATUS Status = PdhOpenQuery(NULL, NULL, &cpuQuery);
16     if (Status != ERROR_SUCCESS) 
17     {
18         printf("\nPdhOpenQuery failed with status 0x%x.", Status);
19         exit(-1);
20     }
21     char buf[50];
22     sprintf(buf, "\\Processor(%d)\\%% Processor Time", cpuIndex);
23     PdhAddCounter(cpuQuery, LPCSTR(buf), NULL, &cpuTotal);
24     PdhCollectQueryData(cpuQuery);
25 }
26 
27 
28 double getCpuUsageRate()
29 {
30     PDH_FMT_COUNTERVALUE counterVal;
31     PdhCollectQueryData(cpuQuery);
32     PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
33     return counterVal.doubleValue;
34 }
复制代码
注:该方法也可以计算总的cpu利用率,只要把PdhAddCounter的第二个字符串参数改为"\\Processor(_Total)\\%% Processor Time"
      前后两次调用PdhCollectQueryData之间也需要间隔一定时间
使用方法如下:
复制代码
1 int main()
2 {
3     init(0);
4     while(1)
5     {
6         Sleep(800);
7         printf("\n%f\n", getCpuUsageRate());
8     }
9 }
复制代码

利用上述方法获取cpu当前利用率后,再画正弦曲线,只需要改变进程的busy时间和idle时间,如果当前点曲线需要的cpu利用率是a%,cpu实际利用率是b%
若a>b, 那么进程的busy时间为该点时间片的(a-b)%
若a<=b,那么进程busy时间为0(实际情况中由于cpu使用率采集的不精确以及使用率的不断变化,busy时间设置为0效果不一定最好,本文中是设置为原来时间的3/4)
实际上除了当前进程外,如果cpu一直占用某个使用率,会影响曲线的形状,特别是曲线的下部分.
代码如下:
复制代码
  1 #include <TCHAR.h>
  2 #include <windows.h>
  3 #include <pdh.h>
  4 #include <cstdio>
  5 #include <cmath>
  6 #pragma comment(lib, "pdh.lib")
  7 
  8 //---------------------------------------------------comput the cpu usage rate
  9 static PDH_HQUERY cpuQuery;
 10 static PDH_HCOUNTER cpuTotal;
 11 
 12 //cpuindex 为指定的cpu id ,从0开始
 13 void init(int cpuIndex)
 14 {
 15     PDH_STATUS Status = PdhOpenQuery(NULL, NULL, &cpuQuery);
 16     if (Status != ERROR_SUCCESS) 
 17     {
 18         printf("\nPdhOpenQuery failed with status 0x%x.", Status);
 19         exit(-1);
 20     }
 21     char buf[50];
 22     sprintf(buf, "\\Processor(%d)\\%% Processor Time",cpuIndex);
 23     PdhAddCounter(cpuQuery, LPCSTR(buf), NULL, &cpuTotal);
 24     PdhCollectQueryData(cpuQuery);
 25 }
 26 
 27 
 28 double getCpuUsageRate()
 29 {
 30     PDH_FMT_COUNTERVALUE counterVal;
 31     PdhCollectQueryData(cpuQuery);
 32     PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
 33     return counterVal.doubleValue;
 34 }
 35 
 36 //--------------------------------------------------------------------cpu sin
 37 //把一条正弦曲线0~2pi 之间的弧度等分200份抽样,计算每个点的振幅
 38 //然后每隔300ms设置下一个抽样点,并让cpu工作对应振幅时间
 39 const int samplingCount = 200; //抽样点数目
 40 const double pi = 3.1415926;
 41 const int totalAmplitude = 300; //每个抽样点对应时间片
 42 const double delta = 2.0/samplingCount;  //抽样弧度的增量
 43 
 44 DWORD busySpan[samplingCount];//每个抽样点对应的busy时间
 45 int idleSpan[samplingCount];//每个抽样点对应的idle时间
 46 
 47 //一个线程调用MakeUsageSin,并把该线程绑定到一个cpu,那么该cpu呈现正弦曲线
 48 DWORD WINAPI MakeUsageSin(LPVOID lpParameter)
 49 {
 50     DWORD startTime = 0;
 51     for(int j = 0; ; j = (j + 1) % samplingCount)
 52     {
 53         startTime = GetTickCount();
 54         DWORD realBusy = busySpan[j];
 55 
 56         double currentCpuUsageRate = getCpuUsageRate();
 57         if(currentCpuUsageRate < busySpan[j]*1.0/totalAmplitude)
 58             realBusy = (busySpan[j]*1.0/totalAmplitude - currentCpuUsageRate)*totalAmplitude;
 59         else
 60             realBusy *= 0.75; 
 61 
 62         while ((GetTickCount() - startTime) < realBusy);
 63         Sleep(idleSpan[j]);
 64     }
 65 }
 66 
 67 //如果cpuindex < 0 则所有cpu都显示正弦曲线
 68 //否则只有第 cpuindex个cpu显示正弦曲线
 69 //cpuindex 从 0 开始计数
 70 void CpuSin(int cpuIndex)
 71 {
 72     //计算 busySpan 和 idleSpan
 73     double radian = 0;
 74     int amplitude = totalAmplitude / 2;
 75     for (int i = 0; i < samplingCount; i++)
 76     {
 77         busySpan[i] = (DWORD)(amplitude + sin(pi*radian)*amplitude);
 78         idleSpan[i] = totalAmplitude - busySpan[i];
 79         radian += delta;
 80     }
 81 
 82     //获取系统cup数量
 83     SYSTEM_INFO SysInfo;
 84     GetSystemInfo(&SysInfo);
 85     int num_processors = SysInfo.dwNumberOfProcessors;
 86     if(cpuIndex + 1 > num_processors)
 87     {
 88         printf("error: the index of cpu is out of boundary\n");
 89         printf("cpu number: %d\n", num_processors);
 90         printf("your index: %d\n", cpuIndex);
 91         printf("** tip: the index of cpu start from 0 **\n");
 92         return;
 93     }
 94 
 95     if(cpuIndex < 0)
 96     {
 97         HANDLE* threads = new HANDLE[num_processors];
 98         for (int i = 0;i < num_processors;i++)
 99         {
100             DWORD mask = 1<<i;
101             threads[i] = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
102             SetThreadAffinityMask(threads[i], 1<<i);//线程指定在某个cpu运行
103         }
104         WaitForMultipleObjects(num_processors, threads, TRUE, INFINITE);
105     }
106     else
107     {
108         init(cpuIndex);
109         HANDLE thread;
110         DWORD mask = 1;
111         thread = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
112         SetThreadAffinityMask(thread, 1<<cpuIndex);
113         WaitForSingleObject(thread,INFINITE);
114     }
115 
116 }
117 //-------------------------------------
118 
119 int main()
120 {
121     CpuSin(0);
122 }
复制代码
主要改动在MakeUsageSin函数,初始化在上面代码108行
结果如下:

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts