zoukankan      html  css  js  c++  java
  • C++第四十二篇 -- CPU Usage

    前言

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

    近期在做CPU Usage方面的事情,让CPU以一种高占用率的状态运行一定的时间,需要读取CPU各个核的占用率,网上关于这方面的资料好少,翻墙也只找到了一个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;
    View Code

    第二次读取:

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

    计算占用率:

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

    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);
        }
    View Code

    4. 效果图

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

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

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

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

    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 rootcimv2 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.
    }
    View Code

    以1:9的比例

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

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

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

    a. win+R输入"wbemtest"

    总结

    问题:

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

    源码:

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

  • 相关阅读:
    洛谷P1208 [USACO1.3]混合牛奶 Mixing Milk 题解 结构体排序
    信息学竞赛中C语言的输入输出
    Python 关键字参数和可变参数
    大白话讲解神经网络算法,原理如此简单!
    idea debug flink1.12 sqlClient 源码
    Flink SQL如何保证分topic有序
    Flink 1.12.0 SQL Connector支持 Oracle
    Flink实战之Flink SQL connector支持并行度配置
    java程序中执行脚本时具有的是那个用户的权限呢?
    clickhouse日期等函数的使用
  • 原文地址:https://www.cnblogs.com/smart-zihan/p/13073137.html
Copyright © 2011-2022 走看看