4

我需要计算整个系统以及特定进程的 CPU 和 RAM 使用率。我从来没有在 C# 中这样做过。所以我能够想出以下代码(我主要从这个网站上的示例中获取):

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 回答
0

您的代码看起来不错,但总 cpu 使用计数器是错误的。你有进程而不是处理器。也不要像那样拆分百分比,因为 Windows 总是使用负载较小的 cpu,除非您的应用程序是为多线程而设计的。另一件事是你的样品,它太快了。我把它放慢了1秒。你应该从柜台得到更好的反馈

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

    using (PerformanceCounter total_cpu = new PerformanceCounter("Processor", "% 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() ;
                float p = process_cpu.NextValue();
                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(1000);
            }
        }
    }
}
catch(Exception ex)
{
    Console.WriteLine("Exception: " + ex);
}
于 2017-08-08T18:23:39.013 回答