1

リソースの使用状況だけでなく、温度やファン速度などのハードウェアの状態も含めた Windows リソース モニターの改良版を作成することを考えていました。

昨日、C++ を使用してプログラミングを開始し、コンピューター上のすべてのプロセスのメモリと CPU 使用率を一覧表示して更新することができました。

ただし、ここで問題が発生します。非常に遅いです。1 秒ごとに使用状況をポーリングすると、i5 2500k@4.3 GHz の 5% が使用されます。CPU とメモリの使用率だけでなく、すべてのハード ドライブのディスク使用率、インターネットの使用率、GPU の使用率 (すべてのプロセスのすべて) も必要であり、すべての温度も監視したいため、これは受け入れられません。

これが私のコードです:

const double MB = 1024*1024;
const double KB = 1024;

struct WinProcess
{
    wstring Name;
    unsigned int ID;
    wstring UserName;
    double cpuUsage;
    long long int ramUsage;

    WinProcess(wstring name, unsigned int id) : Name(name), ID(id), UserName(L"Not set"), cpuUsage(0), ramUsage(0) {}
};

class ResourceMonitor
{
private:
    void** hquery;
    void** hcountercpu;
    void** hcountermem;

    int cpuCores;

    vector<WinProcess> Processes;
public:
    ResourceMonitor();
    ~ResourceMonitor();

    void StartResourceMonitor();
    void MeasureResourceUsage();
    void PrintUsage();
};

ResourceMonitor::ResourceMonitor() : 
    Processes(GetProcessList())    // Function GetProcessList() returns vector with all processes, their IDs and username, from which it was launched
{
    hquery = new void*[Processes.size()];
    hcountercpu = new void*[Processes.size()];
    hcountermem = new void*[Processes.size()];

    for (unsigned int i = 2; i < Processes.size(); i++)
    {
        Processes[i].Name = Processes[i].Name.substr(0, Processes[i].Name.size() - 4);
    }

    for (unsigned int i = 2; i < Processes.size(); i++)
    {
        wstring CounterPathCPU = L"\\Process(" + Processes[i].Name + L")\\% Processor Time";
        wstring CounterPathMEM = L"\\Process(" + Processes[i].Name + L")\\Private Bytes";

        if ((PdhOpenQuery(NULL, 0, &hquery[i])) != ERROR_SUCCESS
            || PdhAddCounter(hquery[i], CounterPathCPU.c_str(), 0, &hcountercpu[i]) != ERROR_SUCCESS
            || PdhAddCounter(hquery[i], CounterPathMEM.c_str(), 0, &hcountermem[i]) != ERROR_SUCCESS
            || PdhCollectQueryData(hquery[i]) != ERROR_SUCCESS)
        {
            continue;
        }
    }

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    cpuCores = sysinfo.dwNumberOfProcessors;

    wcout.setf(ios::fixed);
}

ResourceMonitor::~ResourceMonitor()
{    
    for (unsigned int i = 2; i < Processes.size(); i++)
    {
        PdhCloseQuery(hquery[i]);
        PdhRemoveCounter(hcountercpu[i]);
        PdhRemoveCounter(hcountermem[i]);
    }

    delete[] hquery;
    delete[] hcountercpu;
}

void ResourceMonitor::StartResourceMonitor()
{
    system("mode CON: COLS=150");

    while (1)
    {
        MeasureResourceUsage();
        PrintUsage();
        Sleep(1000);
    }
}

void ResourceMonitor::MeasureResourceUsage()
{
    PDH_FMT_COUNTERVALUE countervalcpu;
    PDH_FMT_COUNTERVALUE countervalmem;

    for (unsigned int i = 2; i < Processes.size(); i++)
    {
        if ((PdhCollectQueryData(hquery[i])) != ERROR_SUCCESS)
        {   
            printError(L"Error on collecting query data: ");
            continue;
        }        
        if ((PdhGetFormattedCounterValue(hcountercpu[i], PDH_FMT_LONG | PDH_FMT_NOCAP100, 0, &countervalcpu)) != ERROR_SUCCESS)
        {
            printError(L"Error on CPU usage retrieval: ");
            continue;
        }
        if ((PdhGetFormattedCounterValue(hcountermem[i], PDH_FMT_LONG, 0, &countervalmem)) != ERROR_SUCCESS)
        {
            printError(L"Error on Memory usage retrieval: ");
            continue;
        }

        Processes[i].cpuUsage = countervalcpu.longValue / (double)cpuCores;
        Processes[i].ramUsage = countervalmem.longValue;
    }
}

void ResourceMonitor::PrintUsage()
{
    system("cls");
    long long int RAMSUM = 0;
    for (unsigned int i = 2; i < Processes.size(); i++)
    {
        wcout << left << setw(40) << Processes[i].Name + L".exe: ";
        wcout << setw(6) << left << L" | ID " << setw(4) << right << Processes[i].ID;
        wcout << setw(8) << left << L" | User " << setw(15) << Processes[i].UserName;
        wcout << setw(8) << left << L" | CPU usage " << setw(10) << right << setprecision(2) << Processes[i].cpuUsage << setw(1) << L"%";
        wcout << setw(8) << left << L" | RAM usage " << setw(15) << right << setprecision(3) << Processes[i].ramUsage / MB << setw(3) << left << L" MB" << endl;

        RAMSUM += Processes[i].ramUsage;
    }
    wcout << L"Total RAM usage: " << setw(7) << right << RAMSUM / MB
        << setw(3) << left << L" MB" << endl;
}

私はこのコードに関する問題をよく認識しています: プロセス リストは更新されず、GUI もありませんが、プロセス リスト機能の取得は非常に高速であるため、これらは修正可能です。

Windowsタスクマネージャーのように、CPUとメモリの使用状況を確認する方法はありますか? 私は両方の言語を知っているので、c++ または c# を使用できます。最後に、各プロセスのネットワーク トラフィック、ディスク使用量、GPU 使用量を監視する方法がわかりません。何か案は?助けてくれてありがとう!

4

1 に答える 1

3

私が最後に cpu と mem の統計情報を扱っていたときは Delphi を使用していましたが、呼び出しは Windows API にほとんど当てはまります。この回答の最後に Delphi/pascal のソースを含めているので、実際に使用したコードを確認できます。これは CPU とメモリの使用状況をカバーしていますが、ネットワーク トラフィック、ディスクの使用状況、GPU の使用状況に関する最後の質問に対する回答はありません。

これらのリンクは、私が使用した手法をカバーしていますが、c/c++ の場合です。C# の場合、これはすべてSystem.Diagnostics.Processクラスに適切にまとめられており、非常に簡単にアクセスできます。

メモリ使用量:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683219%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684877%28v=vs.85%29.aspx

C++ で GetProcessMemoryInfo を使用するには?

C++ で Windows のメモリ使用量を取得する方法

CPU 時間:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683223%28v=vs.85%29.aspx

GetProcessTimes と FileTimeToSystemTime を使用した CPU 処理時間が 64 ビット Windows で機能しない

// this member var is referenced within the function
mLastMemInfo: TProcessMemoryCounters;

procedure TProcess.UpdateStats(handle: Cardinal);
var
  creation, exit, kernel, user: FILETIME;
  sysTime: TSystemTime;
  iKernel: Int64;
  iUser: Int64;
  totalTime: Int64;
  tickCount: Cardinal;
  tDelta: Cardinal;
begin
  if (handle <> INVALID_HANDLE) then begin
    tickCount := GetTickCount;
    tDelta := tickCount - mLastStatsTick;
    // only update stats if its been 500 ms or more since last check
    // or if we haven't checked at all yet
    if (tDelta >= 500) then begin
      // get cpu stats
      if GetProcessTimes(handle, creation, exit, kernel, user) then begin
        if (mCreationTime = 0) then begin
          if (FileTimeToSystemTime(creation, sysTime)) then begin
            mCreationTime := SystemTimeToDateTime(sysTime);
          end;
        end;
        iKernel := kernel.dwHighDateTime;
        iKernel := (iKernel shl 32) or kernel.dwLowDateTime;
        iUser := user.dwHighDateTime;
        iUser := (iUser shl 32) or user.dwLowDateTime;
        iKernel := iKernel div 10; // convert 100nanos to microseconds
        iUser := iUser div 10; // convert 100nanos to microseconds
        mLastKernelDelta := iKernel - mLastKernelTime;
        mLastUserDelta := iUser - mLastUserTime;
        totalTime := mLastKernelDelta + mLastUserDelta;
        if (totalTime <= 0) and (mLastStatsTick = 0) then begin
          mLastCpuUsage := 0;
        end else begin
          mLastCpuUsage := (totalTime / NumberOfProcessors) / (tDelta * 1000);
          if (mLastCpuUsage > 1.0) then mLastCpuUsage := 1.0;
        end;
        mLastKernelTime := iKernel;
        mLastUserTime := iUser;
      end else begin
        mLastCpuUsage := 0;
      end;
      // get memory stats
      mLastMemInfo.cb := SizeOf(mLastMemInfo);
      if not GetProcessMemoryInfo(handle, @mLastMemInfo,
                    SizeOf(mLastMemInfo)) then begin
        mLastMemInfo.cb := 0; // flag data as no good
      end;
      // set the time we got the stats
      mLastStatsTick := tickCount;
    end;
  end;
end;
于 2012-08-29T02:16:15.270 に答える