以编程方式检查应用程序正在使用的内核数量
Programmatically check the number of cores application is using
是否有方法以编程方式检查c++应用程序正在使用多少内核?
我正在寻找Windows/Linux
解决方案,但当然平台独立的解决方案会更好,我想它要求太多了。
没有办法知道一个应用程序使用了多少核。但是你可以通过来猜测的线程数。
windows:你会想要使用微软所称的工具帮助库。更具体地说,你会想看看遍历线程列表的例子,它可以让你得到一个应用程序拥有的线程数。
微软真的很喜欢让他们的例子尽可能丑陋,所以这里是我想出的一个漂亮的版本,你给它一个PID,它列出了所有与之相关的线程:
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <cstdio>
bool list(unsigned int PID);
int main(void)
{
list(5532);
list(GetCurrentProcessId());
return 0;
}
bool list(unsigned int PID)
{
HANDLE thread_snap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
thread_snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (thread_snap == INVALID_HANDLE_VALUE) return false;
// Fill in the size of the structure before using it.
te32.dwSize = (DWORD)sizeof(THREADENTRY32);
// Retrieve information about the first thread, and exit if unsuccessful
if (!Thread32First(thread_snap, &te32))
{
CloseHandle(thread_snap);
return false;
}
// Now walk the thread list of the system, and display information about each thread associated with the specified process
printf("Printing threads for PID %un", PID);
do
{
if (te32.th32OwnerProcessID == PID)
{
printf( "THREAD ID = 0x%08X with base priority %u and delta priority %un", (unsigned int)te32.th32ThreadID, (unsigned int)te32.tpBasePri, (unsigned int)te32.tpDeltaPri);
}
}
while (Thread32Next(thread_snap, &te32));
printf("Done printing threads for PID %unn", PID);
// Don't forget to clean up the snapshot object.
CloseHandle(thread_snap);
return true;
}
输入: 5532
(我的蒸汽服务进程ID), GetCurrentProcessId()
Printing threads for PID 5532
THREAD ID = 0x00000BCC with base priority 8 and delta priority 0
THREAD ID = 0x0000041C with base priority 8 and delta priority 0
THREAD ID = 0x00001924 with base priority 8 and delta priority 0
THREAD ID = 0x00000C9C with base priority 8 and delta priority 0
Done printing threads for PID 5532
Printing threads for PID 9836
THREAD ID = 0x000000FC with base priority 8 and delta priority 0
Done printing threads for PID 9836
你可以假设,如果一个应用程序使用的线程数多于cpu的核数,它可能会使用所有的线程,如果它使用的线程数较少,它可能会使用x个核数,其中x是线程数。
如果你想更进一步,你可以得到每个线程的CPU使用情况,以便更好地近似它使用了多少内核。
另一种方法,我不完全确定的工作是会的所有线程应用程序的CPU使用率和相加(百分比),核心系统的数量,提高这一数字的力量和乘以100 (x^-1*100
)其中x是核的数量,然后将所有线程的CPU使用量的比例的百分比多少核心可以处理它所使用的近似多少核。
给定4个内核和4个线程的应用程序,每个内核中有2个CPU使用率为25%,另外2个CPU使用率为11%。
你可以假设它使用:
(25+25+11+11)/((4^-1)*100) = 2.88个内核
问题:
可能不是所有的内核都以相同的速度运行。在这种情况下,它不会像预期的那样工作。
如果你使用的是c++11,你可以通过std::thread::hardware_concurrency()
找到系统的内核数。
或者你也可以遍历进程列表并从中获得进程的线程数,但它不像遍历线程那样具有每个线程的高级信息。
我要在这里给出第二个答案,因为上一个已经足够长了,而这个答案将在一个稍微不同的方向上。
经过进一步的研究,我确定实际上有一种方法可以精确地找出每个线程是/可以运行/运行的内核。我编写的代码大量使用了windows特定的库,但肯定有linux等效的函数。
更具体地说就是使用wbemuuid.lib
, comdef.h
和Wbemidl.h
。
代码:
#define _WIN32_DCOM
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>
#include <cstdarg>
#include <string>
#pragma comment(lib, "wbemuuid.lib")
using namespace std;
DWORD affinity(unsigned int ID)
{
HANDLE threadh = OpenThread(THREAD_SET_INFORMATION | THREAD_QUERY_INFORMATION, FALSE, ID);
DWORD mask = 1;
DWORD old = 0;
while (mask)
{
old = SetThreadAffinityMask(threadh, mask);
if (old)
{
SetThreadAffinityMask(threadh, old);
return old;
}
else
{
if (GetLastError() != ERROR_INVALID_PARAMETER) return 0;
}
mask <<= 1;
}
return 0;
}
HRESULT connect(IWbemLocator** pLoc, IWbemServices** pSvc)
{
HRESULT hres;
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
return hres;
}
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
CoUninitialize();
return hres;
}
hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&(*pLoc));
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object." << " Error code = 0x" << hex << hres << endl;
CoUninitialize();
return hres;
}
hres = (*pLoc)->ConnectServer(_bstr_t(L"ROOT\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &(*pSvc));
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x" << hex << hres << endl;
(*pLoc)->Release();
CoUninitialize();
return hres;
}
hres = CoSetProxyBlanket((*pSvc), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
(*pSvc)->Release();
(*pLoc)->Release();
CoUninitialize();
return hres;
}
return hres;
}
HRESULT query(IWbemLocator** pLoc, IWbemServices** pSvc, IEnumWbemClassObject** pEnum, const char* qry)
{
HRESULT hres;
hres = (*pSvc)->ExecQuery(bstr_t("WQL"), bstr_t(qry), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &(*pEnum));
if (FAILED(hres))
{
cout << "Query for operating system name failed." << " Error code = 0x" << hex << hres << endl;
(*pSvc)->Release();
(*pLoc)->Release();
CoUninitialize();
return 1;
}
return hres;
}
HRESULT parse(IWbemLocator** pLoc, IWbemServices** pSvc, IEnumWbemClassObject** pEnum, IWbemClassObject** pCls, size_t n_args, ...)
{
HRESULT hres;
ULONG uReturn = 0;
while (pEnum)
{
hres = (*pEnum)->Next(WBEM_INFINITE, 1, &(*pCls), &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
va_list vl;
va_start(vl, n_args);
for (size_t i = 0; i < n_args; i++)
{
const char* name = va_arg(vl, const char*);
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
wchar_t* wname = new wchar_t[wchars_num];
MultiByteToWideChar(CP_UTF8 , 0, name, -1, wname, wchars_num);
hres = (*pCls)->Get(wname, 0, &vtProp, 0, 0);
wcout << wname << " : " << std::to_wstring((size_t)vtProp.bstrVal) << " : " << affinity((DWORD)vtProp.bstrVal) << endl;
delete[] wname;
}
va_end(vl);
VariantClear(&vtProp);
}
return hres;
}
int main(int argc, char **argv)
{
string qry = "SELECT * FROM Win32_PerfFormattedData_PerfProc_Thread WHERE IDProcess = 7424";
HRESULT hres;
IWbemLocator* pLoc = NULL;
IWbemServices* pSvc = NULL;
IEnumWbemClassObject* pEnum = NULL;
IWbemClassObject* pCls = NULL;
hres = connect(&pLoc, &pSvc);
if (FAILED(hres)) return 1;
hres = query(&pLoc, &pSvc, &pEnum, qry.c_str());
if (FAILED(hres)) return 1;
hres = parse(&pLoc, &pSvc, &pEnum, &pCls, 1, "IDThread");
if (FAILED(hres)) return 1;
pSvc->Release();
pLoc->Release();
pEnum->Release();
pCls->Release();
CoUninitialize();
return 0;
}
Prime95停止时输出:
IDThread : 9072 : 15
IDThread : 7052 : 15
Prime95运行时有4个工作线程时的输出:
IDThread : 9072 : 15
IDThread : 7052 : 15
IDThread : 5600 : 1
IDThread : 5888 : 2
IDThread : 2888 : 4
IDThread : 9348 : 8
PercentProcessorTime : 0
PercentProcessorTime : 0
PercentProcessorTime : 70
PercentProcessorTime : 83
PercentProcessorTime : 80
PercentProcessorTime : 75
Prime95运行时有2个工作线程的输出:
IDThread : 9072 : 15
IDThread : 7052 : 15
IDThread : 2352 : 15
IDThread : 8396 : 15
解释:
稍微解释一下代码:
-
7424
为Prime95的PID。 -
SELECT * FROM Win32_PerfFormattedData_PerfProc_Thread WHERE IDProcess = 7424
是我用来列出与特定PID相关的所有线程的查询。你可以在这里找到Win32_PerfFormattedData_PerfProc_Thread
提供的所有信息。你所要做的就是把给parse()
的参数从ThreadID
切换到PercentProcessorTime
,它将输出CPU使用百分比。 - 代码是非常丑陋和可能不安全的,它也是一个严重修改版本的例子:从MSDN从本地计算机获取WMI数据。
亲和力:
函数affinity()
设置一个新的线程亲和性来获取旧的线程亲和性,然后再设置回旧的线程亲和性。现在,我不确定如何从亲和中得到实际的核数,我所知道的是,如果是1
,它在核数1上运行,如果是2
,它在核数2上运行,如果是7
,它在核数4和3上运行,或者沿着这些线。我还没有完全弄明白。
移植到linux:
在linux上这就简单多了,例如可以通过sched_getcpu
/sched_getaffinity
来获取内核。用一点谷歌,我相信你可以找到一个方法来列出与进程相关的所有线程。
- 如何在c++中为模板函数实例创建快捷方式
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 以螺旋方式打印矩阵的程序.(工作不好)
- 如何在内核C++中使用1920x1080x16M图形或类似的16M颜色?(VGA)
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 创建引用向量的优雅方式
- CUDA内核和数学函数的显式命名空间
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 码头化的C++应用程序是否向后兼容早期的内核版本
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 不同/较旧的处理器运行c++代码的方式是否不同
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 如果条件为TRUE(最佳方式?),则在do while循环中后置增量
- 重载方法的方式会在使用临时调用时生成编译器错误
- 在reactor中存储eventHandlers的最佳方式是什么
- 将我的应用程序与内核连接的最佳方式是什么
- 以编程方式检查应用程序正在使用的内核数量
- 将常量参数传递给CUDA内核的最快(或最优雅)的方式
- 剪切字符串的字符串安全方式(Windows内核)