Получить использование ЦП и ОЗУ

Мне нужно получить память RAM и использование ЦП во время выполнения процесса (процесс может выполняться иногда и более 30 минут). Я могу получить бесплатную ОЗУ, но использование ЦП не является правильным, по сравнению со значением из диспетчера задач. Я делаю что-то неправильно? Вот мой код:

class Program
{
    static List<float> AvailableCPU = new List<float>();
    static List<float> AvailableRAM = new List<float>();

    protected static PerformanceCounter cpuCounter;
    protected static PerformanceCounter ramCounter;
    static void Main(string[] args)
    {
        cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";

        ramCounter = new PerformanceCounter("Memory", "Available MBytes");

        try
        {
            System.Timers.Timer t = new System.Timers.Timer(1200);
            t.Elapsed += new ElapsedEventHandler(TimerElapsed);
            t.Start();
            Thread.Sleep(10000);
        }
        catch (Exception e)
        {
            Console.WriteLine("catched exception");
        }
        Console.ReadLine();

    }

    public static void TimerElapsed(object source, ElapsedEventArgs e)
    {
        float cpu = cpuCounter.NextValue();
        float ram = ramCounter.NextValue();
        Console.WriteLine(string.Format("CPU Value: {0}, ram value: {1}", cpu, ram));
        AvailableCPU.Add(cpu);
        AvailableRAM.Add(ram);
    }

}

Но когда я запускаю программу, вот что она напечатала на консоли, по сравнению со значениями из диспетчера задач: cpu usage

Что я делаю неправильно?

Ответ 1

В ваших значениях нет ничего плохого.

Причина, по которой вы видите различия с тем, что возвращает диспетчер задач, заключается в том, что значение "использования ЦП" вычисляется для определенного интервала, то есть между двумя вызовами NextValue(). Если диспетчер задач "не вызывает свой собственный NextValue" (если мы упрощаем его работу), вы не будете возвращать те же результаты.

Представьте себе следующий сценарий:

Time 0: 0% actual CPU usage
Time 1: 50% actual CPU usage
Time 2: 70% actual CPU usage
Time 3: 2% actual CPU usage
Time 4: 100% actual CPU usage
  • Если вы проверите значение между временем 1 и временем 3, вы вернете что-то на основе "50% и 2%".
  • Если диспетчер задач проверяет значение между временем 2 и временем 4, он возвращает что-то другое, то есть значение, основанное на "70% и 100%".

Вы можете попробовать создать несколько процессов вашего собственного приложения, вы также должны увидеть разные результаты.

Ответ 2

Вот что я нашел: я создал список с PerformanceCounter объектами для каждого ядра, добавляю процент и деля результат на число физических ядер:

    class Program
    {
        static List<float> AvailableCPU = new List<float>();
        static List<float> AvailableRAM = new List<float>();

        protected static PerformanceCounter cpuCounter;
        protected static PerformanceCounter ramCounter;
        static List<PerformanceCounter> cpuCounters = new List<PerformanceCounter>();
        static int cores = 0;
        static void Main(string[] args)
        {
            cpuCounter = new PerformanceCounter();
            cpuCounter.CategoryName = "Processor";
            cpuCounter.CounterName = "% Processor Time";
            cpuCounter.InstanceName = "_Total";

            foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
            {
                cores = cores + int.Parse(item["NumberOfCores"].ToString());
            }

            ramCounter = new PerformanceCounter("Memory", "Available MBytes");

            int procCount = System.Environment.ProcessorCount;
            for(int i = 0; i < procCount; i++)
            {
                System.Diagnostics.PerformanceCounter pc = new System.Diagnostics.PerformanceCounter("Processor", "% Processor Time", i.ToString());
                cpuCounters.Add(pc);
            }

            Thread c = new Thread(ConsumeCPU);
            c.IsBackground = true;
            c.Start();

            try
            {
                System.Timers.Timer t = new System.Timers.Timer(1200);
                t.Elapsed += new ElapsedEventHandler(TimerElapsed);
                t.Start();
                Thread.Sleep(10000);
            }
            catch (Exception e)
            {
                Console.WriteLine("catched exception");
            }
            Console.ReadLine();

        }

        public static void ConsumeCPU()
        {
            int percentage = 60;
            if (percentage < 0 || percentage > 100)
                throw new ArgumentException("percentage");
            Stopwatch watch = new Stopwatch();
            watch.Start();
            while (true)
            {
                // Make the loop go on for "percentage" milliseconds then sleep the 
                // remaining percentage milliseconds. So 40% utilization means work 40ms and sleep 60ms
                if (watch.ElapsedMilliseconds > percentage)
                {
                    Thread.Sleep(100 - percentage);
                    watch.Reset();
                    watch.Start();
                }
            }
        }

        public static void TimerElapsed(object source, ElapsedEventArgs e)
        {
            float cpu = cpuCounter.NextValue();
            float sum = 0;
            foreach(PerformanceCounter c in cpuCounters)
            {
                sum = sum + c.NextValue();
            }
            sum = sum / (cores);
            float ram = ramCounter.NextValue();
            Console.WriteLine(string.Format("CPU Value 1: {0}, cpu value 2: {1} ,ram value: {2}", sum, cpu, ram));
            AvailableCPU.Add(sum);
            AvailableRAM.Add(ram);
        }

    }

Вот скриншот с результатами (как вы можете видеть, первый метод более точный):

введите описание изображения здесь