以与语言无关的方式检索性能计数器值

本文关键字:方式 检索 性能计数器 语言 | 更新日期: 2023-09-27 17:49:36

在Windows下,性能计数器有不同的名称,这取决于操作系统语言。例如,在英文Windows版本中,有一个性能计数器'Processor(_Total)'% Processor Time。相同的计数器在德文Windows版本中称为'Prozessor(_Total)'Prozessorzeit (%)

是否有任何方法可以以与语言无关的方式(使用c++或c#)检索性能计数器值?或者是否有另一种方法可以在没有性能计数器的情况下获得整个计算机的处理器负载?

以与语言无关的方式检索性能计数器值

每个PerfMon计数器都有一个唯一的(每台机器)整数ID来标识PerfMon计数器(但是在标准计数器的情况下,这个ID保证保持不变)。

连接PerfMon计数器id到它们的美国英文名称和它们的本地化名称的信息存储在注册表中的以下键:

HKEY_LOCAL_MACHINE'SOFTWARE'Microsoft'Windows NT'CurrentVersion'Perflib

一旦你使用注册表来获取PerfMon计数器名称(你可以将其作为标准计数器的常量嵌入到应用程序中),你可以使用PdhLookupPerfNameByIndex函数来查找给定计数器ID的本地化名称。

有关详细信息,请参阅在本地化语言中正确使用PDH api (Microsoft KB)。

您可能还会发现通过winreg (StackOverflow)查找性能计数器id有些相关。

添加

using System.Runtime.InteropServices;
using Microsoft.Win32;

在你的类中导入DLL(我的类名为Program)

[DllImport("pdh.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern UInt32 PdhLookupPerfIndexByName(string szMachineName, string szNameBuffer, ref uint pdwIndex);

发送您想要的操作系统语言的计数器名称,它返回英文name

public string GetEnglishName(string name)
        {
            string buffer2 = name;
            UInt32 iRet2 = new UInt32();
            iRet3 = PdhLookupPerfIndexByName(null, buffer2, ref iRet2);
            //Console.WriteLine(iRet2.ToString());
            RegistryKey pRegKey = Registry.LocalMachine;
            pRegKey = pRegKey.OpenSubKey(@"SOFTWARE'Microsoft'Windows NT'CurrentVersion'Perflib'009");
            string[] after;
            after = (string[])pRegKey.GetValue("Counter");
            string value = iRet2.ToString();
            int pos = Array.IndexOf(after, value);
            return after[pos + 1];
        }

下面是如何使用它

Program m = new Program();
            string result = m.GetEnglishName("Mémoire");
            Console.WriteLine(result);

有WinAPI函数,QueryHighPerformanceCounterQueryHighPerformanceFrequency

您是否尝试过使用Pdh辅助函数和pdhadddenglishcounter函数?

我使用PdhGetCounterInfoW的全路径定位版本。

std::wstring GetLocalizedCounterFullPath(const std::wstring& englishCounterName)
{
    std::wstring localizedCounterName;
    PDH_HQUERY queryHandle = nullptr;
    try
    {
        std::ostringstream errorText;
        auto status = PdhOpenQueryW(nullptr, 0, &queryHandle);
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhOpenQueryW failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }
        PDH_HCOUNTER counterHandle;
        status = PdhAddEnglishCounterW(queryHandle, englishCounterName.data(), 0, &counterHandle);
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhAddEnglishCounterW failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }
        DWORD bufferSize = 0;
        std::vector<unsigned char> counterInfo;
        do 
        {
            if (bufferSize != 0)
            {
                counterInfo.resize(bufferSize);
            }
            status = PdhGetCounterInfoW(counterHandle, 
                                        TRUE, 
                                        &bufferSize, 
                                        reinterpret_cast<PPDH_COUNTER_INFO_W>(counterInfo.data()));
        }
        while(static_cast<unsigned>(status) == PDH_MORE_DATA);
        
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhGetCounterInfoW failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }
        
        localizedCounterName = reinterpret_cast<PPDH_COUNTER_INFO_W>(counterInfo.data())->szFullPath;
        status = PdhCloseQuery(queryHandle);
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhCloseQuery failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }
    }
    catch (const std::exception& e)
    {
        std::wcout << e.what() << "'n";
        PdhCloseQuery(queryHandle);
    }
    
    return localizedCounterName;
}