以编程方式检查应用程序正在使用的核心数 有没有一种方法可以用编程的< /强>检查C++应用程序使用的内核数?

以编程方式检查应用程序正在使用的核心数 有没有一种方法可以用编程的< /强>检查C++应用程序使用的内核数?,c++,multicore,C++,Multicore,我正在寻找Windows/Linux解决方案,但当然,独立于平台的解决方案更可取,我想这要求太高了 无法知道应用程序使用了多少内核。但是你可以通过它的线程数来猜测它 对于windows: 您将要使用microsoft所称的。更具体地说,您需要看一看这个示例,它可以获得应用程序的线程数 微软真的很喜欢让他们的例子尽可能丑陋,所以我想出了一个美化的版本,你给它一个PID,它列出了所有与之相关的线程: #include <windows.h> #include <tlhelp32.h

我正在寻找
Windows/Linux
解决方案,但当然,独立于平台的解决方案更可取,我想这要求太高了

无法知道应用程序使用了多少内核。但是你可以通过它的线程数来猜测它

对于windows:

您将要使用microsoft所称的。更具体地说,您需要看一看这个示例,它可以获得应用程序的线程数

微软真的很喜欢让他们的例子尽可能丑陋,所以我想出了一个美化的版本,你给它一个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 %u\n", PID); 
    do
    {
        if (te32.th32OwnerProcessID == PID)
        {
            printf( "THREAD ID = 0x%08X with base priority %u and delta priority %u\n", (unsigned int)te32.th32ThreadID, (unsigned int)te32.tpBasePri, (unsigned int)te32.tpDeltaPri);
        }
    }
    while (Thread32Next(thread_snap, &te32));
    printf("Done printing threads for PID %u\n\n", PID);

    //  Don't forget to clean up the snapshot object.
    CloseHandle(thread_snap);

    return true;
}

您可以假设,如果应用程序使用的线程数超过cpu拥有的核心数,则可能会使用所有线程;如果应用程序使用的线程数较少,则可能会使用x个核心数,其中x是线程数

如果您想更进一步,您可以获得每个线程的CPU使用率,以便更好地估计它使用了多少内核


另一种我不完全确定是否可行的方法是,计算应用程序所有线程的CPU使用率,并将它们相加(百分比),计算系统拥有的内核数,将该数提高到-1的幂,然后将其乘以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\u concurrency()
找到系统的内核数


或者,您也可以从那里获取一个进程的线程数,但它没有像遍历线程那样的关于每个线程的高级信息。

这里将给出第二个答案,因为最后一个答案已经足够长了,这个答案的方向将略有不同

经过进一步的研究,我确定实际上有一种方法可以精确地计算出每个线程的核心是/可以运行/运行。我编写的代码使用了大量特定于windows的库,但肯定有与linux等效的函数

更具体地说,它使用的是
wbemuid.lib
comdef.h
Wbemidl.h


代码:

使用4个工作线程运行Prime95时输出:

当Prime95使用2个工作线程运行时输出:


说明:

要稍微解释一下代码:

  • 7424
    是Prime95的PID
  • SELECT*FROM Win32\u performatteddata\u PerfProc\u Thread,其中IDProcess=7424
    是我用来列出与特定PID相关的所有线程的查询。您可以找到从Win32\u PerfFormattedData\u PerfProc\u Thread获取的所有信息的列表。您所要做的就是将给定给
    parse()
    的参数从
    ThreadID
    切换到
    PercentProcessorTime
    ,然后输出CPU使用率百分比
  • 该代码非常难看,可能不安全,它也是MSDN的一个经过大量修改的版本

亲缘关系:

函数
affinity()
将线程关联设置为新的,以获取旧的线程关联,然后将其设置回旧的线程关联。现在,我不确定如何从affinity获得实际的核心编号,我知道的是,如果它例如
1
在核心编号1上运行,如果它
2
在核心编号2上运行,如果它
7
在核心4和3上运行,或者沿着这些线运行。我还没有完全弄明白


将其移植到linux:


在linux上,这一切都有点容易,例如,可以通过像/这样的东西获得核心。通过一点谷歌搜索,我相信你也可以找到一种方法来列出与进程相关的所有线程。

我想说,很难确定这一点。您可以确定不同内核上的负载,您可以确定一个特定进程使用了多少线程,以及它使用了多少CPU总时间,但是“这个进程在这个时间点上使用了多少内核”,我认为没有任何直接的方法,我更喜欢第二种方法,它需要测试,感谢您提供的快速和信息reply@makc没问题,希望有帮助。如果你要使用我提出的公式,让我知道测试是如何进行的,我也很想知道你是否提出了一个解决方案,解决了内核不以相同速度计时的可能性。这很少见,但仍然有可能。当有东西运行时,我会在这里发布。你的答案还没有被接受,因为我仍然希望有人会有更明确的解决方案,你已经得到了我的+1:)
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
#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;   
}
IDThread : 9072 : 15
IDThread : 7052 : 15
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
IDThread : 9072 : 15
IDThread : 7052 : 15
IDThread : 2352 : 15
IDThread : 8396 : 15