前言

目的:读取并控制CPU占用率

近期在做CPU Usage方面的事情,让CPU以一种高占用率的状态运行一定的时间,需要读取CPU各个核的占用率,网上关于这方面的资料好少,FQ也只找到了一个WMI的方法,但是感觉对比任务管理器里面的结果偏小。目前也只能读取CPU总的占用率,和任务管理器看起来差不多,也不是完全相同。

虽然还没有实现结果,但是想记录一下历程。

参考链接:

https://blog.csdn.net/wangting627/article/details/22931337

https://blog.csdn.net/fyxichen/article/details/50577580

内容

1. 任务管理器查看CPU占用率。

方法一:

方法二:

2. C++读取CPU的占用率

原理:先读取一次CPU的当前的空闲时间,内核时间和用户时间,间隔一秒,再次读取三个时间,经过公式演算,得到CPU在这一秒内的占用率。

第一次读取:

    FILETIME ftIdle, ftKernel, ftUser;
BOOL flag = FALSE;
if (flag = GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
{
m_fOldCPUIdleTime = FileTimeToDouble(&ftIdle);
m_fOldCPUKernelTime = FileTimeToDouble(&ftKernel);
m_fOldCPUUserTime = FileTimeToDouble(&ftUser); }
return flag;

第二次读取:

    FILETIME ftIdle, ftKernel, ftUser;
//检索系统定时信息,对于多处理器系统,返回值是各处理器总和的时间
//参数1:空闲时间
//参数2:内核时间
//参数3:用户时间
//函数成功,返回值为非零。函数失败,返回值为零
if (GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
{
double fCPUIdleTime = FileTimeToDouble(&ftIdle);
double fCPUKernelTime = FileTimeToDouble(&ftKernel);
double fCPUUserTime = FileTimeToDouble(&ftUser);}

计算占用率:

//CPU使用率 = (总的时间-空闲时间) / 总的时间
nCPUUseRate = (int)(100.0 - (fCPUIdleTime - m_fOldCPUIdleTime) / (fCPUKernelTime - m_fOldCPUKernelTime + fCPUUserTime - m_fOldCPUUserTime)*100.0);

3. 控制CPU占用率

原理:CPU的占用率 = (CPU总时间 - CPU空闲时间)/ CPU总时间。

举几个例子看看:

占用率 num值 空闲时间:运行时间
50% 1 1:1
66.7% 2 1:2
80% 4 1:4
90% 9 1:9

如果想要控制CPU的占用率是50%,那么就设置num = 1,空闲时间和运行时间的比例为1:1。不过这些都有个前提是,电脑中并没有运行其他的程序。但是显然不可能,所以这个占用率也只是个大概。并且想要数据比较准确,一秒之内的空闲和运行最好是间隔运行,如果控制前0.5s运行,后0.5秒Sleep,效果也是不好的,在代码中设置的是0.1s休息。

    int busytime = 100;
int idletime = busytime;
long starttime = 0;
while (true)
{
starttime = GetTickCount();
//std::cout<<starttime<<std::endl;//调试用
while ((GetTickCount() - starttime) <= busytime * num)
;
Sleep(idletime);
}

4. 效果图

以1:9的代码运行结果如下:

可以看到其实任务管理器中的值每隔一秒刷新一次,我写的程序是每隔一秒刷新一次,然后任务管理器中的值看起来比代码中的偏高一些,大胆猜测一下是因为我的程序也在运行,运行过程中也会增加占用率。

5. WMI读取CPU各个核的使用率

代码是google找到的,链接我忘了,后续找到补上,需要FQ

bool getCpuLoadInfo() {
HRESULT hres; // Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------ hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) {
cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
return 0; // Program has failed.
} // Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------ hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
); if (FAILED(hres)) {
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 0; // Program has failed.
} // Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI ------------------------- IWbemLocator *pLoc = NULL; hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLoc); if (FAILED(hres)) {
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 0; // Program has failed.
} // Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method IWbemServices *pSvc = NULL; // Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
); if (FAILED(hres)) {
cout << "Could not connect. Error code = 0x" << hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 0; // Program has failed.
} cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl; // Step 5: --------------------------------------------------
// Set security levels on the proxy ------------------------- hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
); if (FAILED(hres)) {
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 0; // Program has failed.
} // Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ---- // For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
IWbemClassObject *pclsObj;
int i;
//while (1) {
i = 1;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator); if (FAILED(hres)) {
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 0; // Program has failed.
} // Step 7: -------------------------------------------------
// Get the data from the query in step 6 ------------------- ULONG uReturn = 0; while (pEnumerator) {
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn); if (0 == uReturn) {
break;
} VARIANT vtProp; // Get the value of the Name property
//hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
hr = pclsObj->Get(L"PercentProcessorTime", 0, &vtProp, 0, 0);
wcout << " CPU Usage of CPU " << i << " : " << vtProp.bstrVal << endl;
VariantClear(&vtProp); //IMPORTANT!!
pclsObj->Release(); i++;
} //} // Cleanup
// ======== pSvc->Release();
pLoc->Release();
pEnumerator->Release();
//pclsObj->Release();
CoUninitialize(); return 0; // Program successfully completed.
}

以1:9的比例

先看一下它运行之后的效果图:

看右侧任务管理器中的图形,自始至终没有低于90%,可是WMI读出来的却有70%的出现,况且我自己设置的比例是1:9,自己加的占用率,所以感觉WMI读出来的可能有点不合理,偏低了。看资料有几种计算方法,也不知道哪个正确。

另外分享一下WMI的小技巧。文中代码就是找到“PercentProcessorTime”的值,作为CPU的占用率。一起试着在Windows中手动找一找呗。

a. win+R输入"wbemtest"

总结

问题:

试了多种方法,无法知道哪个结果更加权威,也或者是了解并不深,WMI内部的机制也并不是很清楚,任务管理器里面的计算机制是什么也不清楚,还得继续学习进步。这方面的资料很少,因此学习总结做一下分享。

源码:

目前还没有实现每个核的占用率读取,等后续学习深入补上源码。

C++第四十二篇 -- CPU Usage的更多相关文章

  1. Python之路(第四十二篇)线程相关的其他方法、join()、Thread类的start()和run()方法的区别、守护线程

    一.线程相关的其他方法 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. ​ threadin ...

  2. Android UI开发第四十二篇——实现实现易信的圆形图像和对话列表的图像显示部分

    显示图像时,很多个性化显示,圆形或圆角.气泡等等,我们这一篇文章探讨一下圆形和气泡的显示,仿照易信中的实现,先看下效果图: 代码: public class RoundImageView extend ...

  3. 第四十二篇、自定义Log打印

    1.在Xcode 8出来之后,需要我们去关闭多余的日志信息打印 2.在开发的过程中,打印调试日志是一项比不可少的工程,但是在iOS 10中NSLog打印日志被屏蔽了,就不得不使用自定义Log 3.去掉 ...

  4. 第四十二篇 入门机器学习——Numpy的基本操作——索引相关

    No.1. 使用np.argmin和np.argmax来获取向量元素中最小值和最大值的索引 No.2. 使用np.random.shuffle将向量中的元素顺序打乱,操作后,原向量发生改变:使用np. ...

  5. Spring Cloud第十二篇 | 消息总线Bus

    ​ ​本文是Spring Cloud专栏的第十二篇文章,了解前十一篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring ...

  6. 第四十二个知识点:看看你的C代码为蒙哥马利乘法,你能确定它可能在哪里泄漏侧信道路吗?

    第四十二个知识点:看看你的C代码为蒙哥马利乘法,你能确定它可能在哪里泄漏侧信道路吗? 几个月前(回到3月份),您可能还记得我在这个系列的52件东西中发布了第23件(可以在这里找到).这篇文章的标题是& ...

  7. 解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)

    解剖SQLSERVER 第十二篇   OrcaMDF 行压缩支持(译) http://improve.dk/orcamdf-row-compression-support/ 在这两个月的断断续续的开发 ...

  8. 第十二篇 SQL Server代理多服务器管理

    本篇文章是SQL Server代理系列的第十二篇,详细内容请参考原文 在这一系列的上一篇,我们查看了维护计划,一个维护计划可能会创建多个作业,多个计划.你还简单地看了SSIS子系统,并查看了维护计划作 ...

  9. 第十二篇 Integration Services:高级日志记录

    本篇文章是Integration Services系列的第十二篇,详细内容请参考原文. 简介在前一篇文章我们配置了SSIS内置日志记录,演示了简单和高级日志配置,保存并查看日志配置,生成自定义日志消息 ...

随机推荐

  1. linux用户组添加和权限的设置

    1.useradd  添加用户 useradd [选项]... 用户名 -u 用户id.-d 家目录路径.-s 登录Shell(解释器).-G 附加组 /sbin/nologin  :禁止用户登陆系统 ...

  2. 一篇文章带你搞懂 etcd 3.5 的核心特性

    作者 唐聪,腾讯云资深工程师,极客时间专栏<etcd实战课>作者,etcd活跃贡献者,主要负责腾讯云大规模k8s/etcd平台.有状态服务容器化.在离线混部等产品研发设计工作. etcd ...

  3. 【NX二次开发】拉伸的偏置方向猜想与验证

    结论:偏置的方向为曲线方向与拉伸方向的向量叉乘. 在UF_MODL_create_extrusion帮助中有这么一句话:Note that the offset direction is determ ...

  4. 如何让vscode C++ 终端不再显示调试启动信息

    按照微软的官方文档(https://go.microsoft.com/fwlink/?LinkID=533484#vscode)配置好C++环境之后. 每次按F5都会在终端输出,但是会附加一串信息.例 ...

  5. NOIP模拟测试2「排列 (搜索)·APIO划艇」

    排序 内存限制:128 MiB 时间限制:1000 ms 标准输入输出     题目描述 输入格式 数据范围与提示 对于30%的数据,1<=N<=4: 对于全部的数据,1<=N< ...

  6. RAC+DG修改sys密码

    一.版本: 操作系统版本:SUSE 11 数据库版本:11.2.0.4 二.需求 因安全要求,需要修改SYS密码 三.步骤 1节点执行命令: alter user sys identified by ...

  7. 自动删除n天前的日志(此处用于业务删除xml文件)

    Linux应用总结:自动删除n天前的日志 linux是一个很能自动产生文件的系统,日志.邮件.备份等.虽然现在硬盘廉价,我们可以有很多硬盘空间供这些文件浪费,让系统定时清理一些不需要的文件很有一种爽快 ...

  8. Mysql8关于hashjoin的代码处理方式

    Mysql8关于hashjoin的代码处理方式 目录 Mysql8关于hashjoin的代码处理方式 1 表的Schema如下所示: 2 HashJoin代码实现 3 总结 1 表的Schema如下所 ...

  9. 为什么switch里的case没有break不行

    前言 一个小姐姐拿着一个switch的选择题来问我. 之所以这么笃定地回答这个问题,并不是我知道其中原理,而是之前在一个群里,有人问了同类型的问题,我瞥了一眼记住了答案,所以才依葫芦画瓢. 小姐姐接着 ...

  10. JUnit5注解学习指引

    注解(Annotations)是JUnit的标志性技术,本文就来对它的20个注解,以及元注解和组合注解进行学习. 20个注解 在org.junit.jupiter.api包中定义了这些注解,它们分别是 ...