控制CPU使用可以使用脉冲宽度调制,控制CPU一段时间内“忙”和“闲”的比例。
CPU使用率的测量:某段时间内,CPU“忙”所占的比例。
(多核情况下,可以大于 100%)
CPU使用率的控制:通过控制一个测量周期内,CPU“忙”所占时间与总周期时间的占比。
示例说明如何控制CPU使用率:
例如控制CPU使用率在20%。我们需要做的是在一个测量周期T = 100s内,使CPU忙的时间占 Tx=20s , 空闲时间占 Ty = 80s。这样,在一个T周期内,CPU所占时间占比总的时间 = Tx / T = 20%
这样的做法使得CPU在一个T周期内的利用率并不均匀。最好的做法就是,将一个T的周期均分为若干个小的周期Tn,在每个小周期内依然按照 Tx : Ty 的比例进行CPU的“忙”/“闲”切换。
根据以上的方式我们可以调节CPU的占空比,从而在某种意义上而言我们可以控制CPU的使用率。
例如,我们要控制 60% 的使用率,那么它的波形应该如下图所示,其中波峰代表cpu busy loop,波谷代表cpu等待,这样我们在宏观上通过调整波峰与波谷的比例,将各自的时间比例维持在6:4 便可以得到一个这样的矩形波。
同样的,如果我们以一个小的Tn为单位,动态的调整波峰与波谷的时间比例,例如T0 { T x : T y = 5 : 5 } , T1 { Tx : Ty = 6 : 4 } , T0 { Tx : Ty = 7 : 3 } , . . . . . 那么我们得到的将是一个锯齿波形图。
代码
地址:
https://github.com/Anita-Mul/muduo-chenshuo/blob/master/examples/procmon/dummyload.cc
- dummyload
#include <muduo/base/Atomic.h> #include <muduo/base/Condition.h> #include <muduo/base/CurrentThread.h> #include <muduo/base/Mutex.h> #include <muduo/base/Thread.h> #include <muduo/base/Timestamp.h> #include <muduo/net/EventLoop.h> #include <boost/ptr_container/ptr_vector.hpp> #include <math.h> #include <stdio.h> using namespace muduo; using namespace muduo::net; int g_cycles = 0; int g_percent = 82; AtomicInt32 g_done; bool g_busy = false; MutexLock g_mutex; Condition g_cond(g_mutex); double busy(int cycles) { double result = 0; for (int i = 0; i < cycles; ++i) { result += sqrt(i) * sqrt(i+1); } return result; } double getSeconds(int cycles) { Timestamp start = Timestamp::now(); busy(cycles); return timeDifference(Timestamp::now(), start); } void findCycles() { g_cycles = 1000; while (getSeconds(g_cycles) < 0.001) g_cycles = g_cycles + g_cycles / 4; // * 1.25 printf("cycles %d\n", g_cycles); } void threadFunc() { while (g_done.get() == 0) { { MutexLockGuard guard(g_mutex); while (!g_busy) g_cond.wait(); } busy(g_cycles); } printf("thread exit\n"); } // this is open-loop control void load(int percent) // 设定CPU使用率 { percent = std::max(0, percent); percent = std::min(100, percent); // Bresenham's line algorithm int err = 2*percent - 100; int count = 0; for (int i = 0; i < 100; ++i) { bool busy = false; if (err > 0) { busy = true; err += 2*(percent - 100); ++count; // printf("%2d, ", i); } else { err += 2*percent; } { MutexLockGuard guard(g_mutex); g_busy = busy; g_cond.notifyAll(); } CurrentThread::sleepUsec(10*1000); // 10 ms } assert(count == percent); } void fixed() // 固定的cpu使用率 { while (true) { load(g_percent); // 对于cpu使用率固定,每次load相同的percent } // g_percent 全局变量,且峰值由参数指定 } void cosine() // 余弦曲线 { while (true) for (int i = 0; i < 200; ++i) // 以200s为一个周期,以1s为一个小周期 { // 通过余弦曲线获得当前cpu使用率数值,通过时间改变当前CPU使用率数值,可以得到一个连续的曲线 int percent = static_cast<int>((1.0 + cos(i * 3.14159 / 100)) / 2 * g_percent + 0.5); load(percent); // 设定CPU使用率 } } void sawtooth() { while (true) for (int i = 0; i <= 100; ++i) { int percent = static_cast<int>(i / 100.0 * g_percent); load(percent); } } int main(int argc, char* argv[]) { if (argc < 2) { printf("Usage: %s [fctsz] [percent] [num_threads]\n", argv[0]); return 0; } printf("pid %d\n", getpid()); // 打印 pid ,以便procmon程序监控 findCycles(); g_percent = argc > 2 ? atoi(argv[2]) : 43; int numThreads = argc > 3 ? atoi(argv[3]) : 1; boost::ptr_vector<Thread> threads; for (int i = 0; i < numThreads; ++i) { threads.push_back(new Thread(threadFunc)); threads.back().start(); } switch (argv[1][0]) // 处理参数 { case 'f': // 固定cpu使用率到某个范围,例如固定cpu使用率到30% { fixed(); } break; case 'c': // 余弦曲线 { cosine(); } break; case 'z': // 锯齿波形 { sawtooth(); } break; // TODO: square and triangle waves default: break; } g_done.getAndSet(1); { MutexLockGuard guard(g_mutex); g_busy = true; g_cond.notifyAll(); } for (int i = 0; i < numThreads; ++i) { threads[i].join(); } }