4

システム全体と特定のプロセスの CPU と RAM の使用量を計算する必要があります。私はC#でこれをやったことがありません。そのため、次のコードを思いつくことができました (主にこの Web サイトのサンプルから取得しました)。

try
{
    Process proc = Process.GetCurrentProcess();
    string strProcName = proc.ProcessName;
    Console.WriteLine("Process: " + strProcName);

    using (PerformanceCounter total_cpu = new PerformanceCounter("Process", "% Processor Time", "_Total", true))
    {
        using (PerformanceCounter process_cpu = new PerformanceCounter("Process", "% Processor Time", strProcName, true))
        {
            for (; ; )
            {
                Console.CursorTop = 1;
                Console.CursorLeft = 0;

                float t = total_cpu.NextValue() / Environment.ProcessorCount;
                float p = process_cpu.NextValue() / Environment.ProcessorCount;
                Console.WriteLine(String.Format("Total CPU (%) = {0}\t\t\nApp CPU (%) = {1}\t\t\nApp RAM (KB) = {2}",
                    t, p, Process.GetCurrentProcess().WorkingSet64 / (1024)
                    ));

                System.Threading.Thread.Sleep(100);
            }
        }
    }
}
catch(Exception ex)
{
    Console.WriteLine("Exception: " + ex);
}

しかし、それが私に与えるのは、「マップ全体」のデータです。見てみましょう:

ここに画像の説明を入力

ここに画像の説明を入力

ここに画像の説明を入力

誰かがこれらの点に答えることができます:

  1. このようなパフォーマンス カウンターの実行は、それ自体がかなりコストのかかる操作のようです。CPU 使用率が約 5% 上昇します。私は C++ で大量の CPU カウンターを実行しましたが、実行にほとんど CPU 時間を要しませんでした。

  2. 上で言ったことに加えて、上記のループが最初に実行されると、2 秒の遅延が発生します。文字通り2 秒間ハングアップします。それは正常ですか?もしそうなら、私は彼らがそれをパフォーマンスカウンターと呼ぶ大胆さを持っていたとは信じられません:)

  3. 私の RAM の読み取り値は、タスク マネージャーによって報告された値にかなり近いですが、CPU の出力は完全にオフになっています。誰かが私がここで間違っていることを教えてもらえますか?

  4. さらに、これらすべてを説明できるPerformanceCounter クラスのドキュメントが見つからないようです: % Processor Time_Totalなど? そして最も重要なことは、それらは英語のみですか?それらはローカライズされるべきですか?

  5. そこでのプロセスは、その名前で指定されます。しかし、同じ名前で複数のプロセスが実行されている場合はどうでしょう。じゃあ何?

4

2 に答える 2

0

これが私が思いついたものですが、それはアンマネージド API を使用しています。

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetProcessTimes(IntPtr hProcess, out System.Runtime.InteropServices.ComTypes.FILETIME
    lpCreationTime, out System.Runtime.InteropServices.ComTypes.FILETIME lpExitTime, out System.Runtime.InteropServices.ComTypes.FILETIME lpKernelTime,
    out System.Runtime.InteropServices.ComTypes.FILETIME lpUserTime);

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern UInt32 GetTickCount();

static bool gbSetOldData = false;
static UInt32 gmsOldTickCount = 0;
static ulong gnsOldKernelTime = 0;
static ulong gnsOldUserTime = 0;

public static double getCPUUsageForProcess(int nProcID = 0)
{
    //Get CPU usage for the process in with ID in 'nProcID'
    //'nProcID' = process ID, or 0 for the current process
    //RETURN:
    //      = CPU usage: [0.0 - 1.0]
    //      = Negative if error
    double fCPUUsage = -1.0;
    try
    {
        IntPtr hProcess = nProcID != 0 ? Process.GetProcessById(nProcID).Handle : Process.GetCurrentProcess().Handle;

        System.Runtime.InteropServices.ComTypes.FILETIME ftCreated, ftExit, ftKernel, ftUser;
        if (GetProcessTimes(hProcess, out ftCreated, out ftExit, out ftKernel, out ftUser))
        {
            UInt32 dwmsNewTickCount = GetTickCount();

            ulong nsNewKernelTime = (ulong)ftKernel.dwHighDateTime;
            nsNewKernelTime <<= 32;
            nsNewKernelTime |= (ulong)(uint)ftKernel.dwLowDateTime;

            ulong nsNewUserTime = (ulong)ftUser.dwHighDateTime;
            nsNewUserTime <<= 32;
            nsNewUserTime |= (ulong)(uint)ftUser.dwLowDateTime;

            if (gbSetOldData)
            {
                //Adjust from 100-nanosecond intervals to milliseconds
                //100-nanosecond intervals = 100 * 10^-9 = 10^-7
                //1ms = 10^-3
                fCPUUsage = (double)((nsNewKernelTime - gnsOldKernelTime) + (nsNewUserTime - gnsOldUserTime)) /
                    (double)((dwmsNewTickCount - gmsOldTickCount) * 10000);

                //Account for multiprocessor architecture
                fCPUUsage /= Environment.ProcessorCount;

                //In case timer API report is inaccurate
                if (fCPUUsage > 1.0)
                    fCPUUsage = 1.0;
            }
            else
            {
                //For the first run, assume no CPU usage
                fCPUUsage = 0.0;
            }

            //Remember data
            gnsOldKernelTime = nsNewKernelTime;
            gnsOldUserTime = nsNewUserTime;
            gmsOldTickCount = dwmsNewTickCount;
            gbSetOldData = true;
        }
    }
    catch
    {
        //Failed
        fCPUUsage = -1.0;
    }

    return fCPUUsage;
}

そして、これはあなたがそれを呼び出す方法です:

int nDummy = 1;

for (; ; )
{
    double fCPU = getCPUUsageForProcess();

    Console.CursorTop = 1;
    Console.CursorLeft = 0;

    int nCpu = (int)(fCPU * 100);
    Console.WriteLine("CPU%: {0}\t\t", nCpu);

    //Time filler
    long j = 0;
    for (; j < 1000000; j++)
    {
        nDummy += (int)Math.Cos(1 / (j + 1));
    }

    //Don't hog all CPU time!
    System.Threading.Thread.Sleep(500);
}

.NET に同様の方法があるかどうかはわかりません。ある場合 (上記に投稿したすべての制限がない場合)、聞きたいですか?

于 2013-04-20T00:33:34.907 に答える