多少m等于一个g(多少m等于一个g流量)

注:是在Linux系统下实现的。1.首先,我们来看看程序运行的结果。上图是两个线程的CPU利用率曲线,是余弦曲线。2.如何计算CPU利用率计算CPU利用率我们都

注:是在Linux系统下实现的。

多少m等于一个g(多少m等于一个g流量)插图

1.首先,我们来看看程序运行的结果。

上图是两个线程的CPU利用率曲线,是余弦曲线。

2.如何计算CPU利用率

计算CPU利用率我们都是计算一段时间内的CPU利用率,而不是某个时刻的电脑利用率。

检查文件/proc/[pid]/stat,其中[pid]是要检查的进程的id。我们可以通过ps命令来检查。当我们打开stat文件时,内容大约和下面一样长。每一项都用空隔开,每一个流程项都一样,每一项的编号都不一样。

$ cat /proc//stat (fake_process) S 505 505 160 0 0 0 814 0 0 20 0 3 0 403 0 0 0 0 0 0 0 0 0 17 5 0 0 0 0 0 0

可以通过下面的命令查询文档中每个具体条目的含义(由于每个人都在手机上阅读帖子,所以不必要的内容已被删除)

$ man proc.... # 省略/proc/[pid]目录下其它文件说明,我们直接看stat文件/proc/[pid]/stat ........... (14) utime %lu Amount of time that this process has been scheduled in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)). This in‐cludes guest time, guest_time (time spent running a virtual CPU, see below), so that applications that are not aware of the guest time field do not lose that time from their calculations. (15) stime %lu Amount of time that this process has been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).......... #省略其它说明

man proc中详细解释了每个项目的含义。我们主要关心第14项和第15项的CPU利用率。Utime表示进程从开始运行到现在所占用的用户态时间,后面是%lu表示这是一个无符号的long类型字段;Stime表示进程从开始到现在所占用的内核状态时间,后面是%lu,表示这是一个无符号的long类型字段。这里需要注意的是,占用的时间单位是时钟节拍。

时钟滴答,使用sysconf(_SC_CLK_TCK)来表示一秒钟内有多少时钟滴答。一般为100,即一秒分为100个钟点,一个钟点表示1/100秒。也就是说,我们可以用下面的公式来表示一段时间内的CPU利用率。

long last = utime + stime;// 间隔一段时间:这里用一秒, 可以任意时间间隔/* ...... */int period = 1; // 1秒long curr = utime + stime; // 这里表示重新从/proc/[pid]/stat里读取utime和stimedouble ratio = (curr - last) * 1.0 / (period * sysconf(_SC_CLK_TCK)); /* 这里乘1.0是为了获取浮点数*/3.定制CPU的运行效率

比如我们需要让一个进程在一段时间内的CPU利用率为50%(我们设为P),那么我们在P/2时间内让CPU满负荷运行,在后面的P/2时间内让进程放弃CPU,整个周期内进程的CPU利用率为50%,如图:

上图中的方案1,让CPU在前50%的时间运行后放弃50%的时间,导致进程占用CPU时间不均匀。以这种方式运行的CPU占用率曲线出现峰值的可能性很高,并且曲线不够平滑。方案二,将一段时间平均分成N份,随机让N份运行,这样CPU占用率为n/N,曲线效果更好。在要求不高的情况下,第一种方案相对简单,容易实现。

4.向我展示代码-代码实现

为了实现这个想法,首先选择曲线:

一个线程根据曲线公式计算每个时刻y的值(为了便于解释和计算,我们以1秒为一个计算周期),y的值就是CPU占用率;然后把1秒分成100份,再从1到100,按照某种方式,选择Y份打开运行开关,选择100-y份关闭运行开关。比如你可以写下面的伪代码,详细代码会贴在最后:

void load(int percent) { // 确保 0 <= percent <= 100 percent = std::max(0, percent); percent = std::min(100, percent); for (size_t i = 0; i < 100; i++) { bool busy = false; if (i < percent) busy = true; // g_busy是线程是否运行的开关 g_busy = busy; // 把一秒分成100份,休眠10ms让其它线程运行 std::this_thread::sleep_for(std::chrono::milliseconds(10)); }}

一个或多个其他线程根据运行开关的打开和关闭来确定它们是否正在运行。

std::unique_lock<std::mutex> lock(_m);while (!g_busy) { g_cond.wait(lock);}busy(g_cycles); // 运行

现在我们的重点是确定我们的曲线和忙函数。

在代码中,我们认识到CPU利用率是一条余弦曲线,当然也可以按照这个思路实现其他曲线2。

余弦曲线

y的取值范围是[-1,1],x是(-无穷大,+无穷大),一条曲线的周期是2 * PI。我们使用其中X代表我们的时间,Y代表CPU占用率。那么x >: = 0,0 & lt= y & lt00 (100%),我们可以定义自己的曲线周期。最终的代码如下所示:

for (size_t i = 0; i < 200; i++) { // 以200为周期 // i * 3. / 100 的范围为[0, 2*PI],假设闭区间 // (1.0 + cos(i * 3. / 100)) 的范围为[0,2] // (1.0 + cos(i * 3. / 100)) / 2 的范围为[0,1] // (1.0 + cos(i * 3. / 100)) / 2 * max_percent 为[0, max_percent], max_percent为我们设置的最大CPU占用率 // 最后加0.5做精度损失的修正,同时防止出现负数 int percent = static_cast<int>((1.0 + cos(i * 3. / 100)) / 2 * g_percent + 0.5); load(percent);}

excel中绘制的曲线如下所示:

确定了我们的曲线之后,就该确定我们的跑步函数了。最好能最大程度的利用我们的CPU。我们可以选择开平方根函数或者其他CPU密集型函数。

for (size_t i = 0; i < cycles; i++) { result += sqrt(i) * sqrt(i + 1);}

这里的一个难点是确定周期的大小,让我们的running函数尽可能运行10ms左右。

下面是完整的代码,以及实现过程中遇到的坑。

#include <cmath>#include <algorithm>#include <mutex>#include <condition_variable>#include <vector>#include <thread>#include <atomic>#include <iostream>#include <unistd.h>#include <chrono>std::mutex _m;std::condition_variable g_cond;bool g_busy = false;std::atomic<int> g_done;int g_cycles = 0;int g_percent = 82;void load(int percent) { percent = std::max(0, percent); percent = std::min(100, percent); // Bresenham's line algorithm !!! int err = 2 * percent - 100; int count = 0; for (size_t i = 0; i < 100; i++) { bool busy = false; if (err > 0) { busy = true; err += 2 * (percent - 100); ++count; } else { err += 2 * percent; } { std::unique_lock<std::mutex> lock(_m); g_busy = busy; g_cond.notify_all(); } // 把一秒分成100份 std::this_thread::sleep_for(std::chrono::milliseconds(10)); }}double timedifference(std::chrono::steady_clock::time_point start, std::chrono::steady_clock::time_point end) { std::chrono::duration<double> d = std::chrono::duration_cast<std::chrono::duration<double>>(end - start); return d.count();}double busy(int cycles) { double result = 0; for (size_t i = 0; i < cycles; i++) { result += sqrt(i) * sqrt(i + 1); } return result; }void func() { while (g_done.load() == 0) { { // 这里主要是要释放锁,防止某个线程一直占用锁,而主线程无法修改busy std::unique_lock<std::mutex> lock(_m); while (!g_busy) { g_cond.wait(lock); } } busy(g_cycles); }}void cosine() { while (true) { for (size_t i = 0; i < 200; i++) { // 以200为周期 int percent = static_cast<int>((1.0 + cos(i * 3. / 100)) / 2 * g_percent + 0.5); load(percent); } }}double get_seconds(int cycles) { std::chrono::steady_clock::time_point tp = std::chrono::steady_clock::now(); busy(cycles); return timedifference(tp, std::chrono::steady_clock::now());}void find_cycles() { g_cycles = 800; while (get_seconds(g_cycles) < 0.01) { // 找到运行约10毫秒的cycle数 g_cycles = g_cycles + g_cycles / 4; }}int main(int argc, char const *argv[]) { std::vector<std::thread> ths; for (size_t i = 0; i < 2; i++) { ths.emplace_back(func); } find_cycles(); std::cout << "pid : " << ::getpid() << std::endl; cosine(); g_done = 1; { std::unique_lock<std::mutex> lock(_m); g_busy = true; g_cond.notify_all(); } for (auto& t : ths) { t.join(); } return 0;}

注意代码提示:

find_cycles函数,这个函数是为了找到使busy运行大约10ms时,需要循环的次数。func函数里,锁一定要在busy运行之前释放,如果不释放;可能导致本线程一直获取到锁;即计算曲线函数的线程一直获取不到锁(即我们平时说的线程被饿死),不能改变busy的状态,运行线程一直运行,导致CPU一直100%运行。load函数里用了布雷森汉姆直线演算法来开闭运行开关。

本节描述进程如何抛出任何CPU利用率。下一节将讨论如何将我们的过程参数发送到浏览器客户端进行显示。而是用boost的beast库和asio库。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/120055.html

发表回复

登录后才能评论