Как запустить процессор при заданной нагрузке (% загрузки процессора)? - PullRequest
4 голосов
/ 07 апреля 2011

Можно ли заморозить загрузку процессора, показанную в диспетчере задач Windows? Я хочу заморозить загрузку в виде определенных значений, таких как 20%, 50%, 70% и т. Д. Из моей программы.

(Это для анализа того, сколько энергии потребляет ПК с точки зрения использования процессора.)

Возможно ли это?

Ответы [ 2 ]

7 голосов
/ 07 апреля 2011

Моя первая наивная попытка состояла бы в том, чтобы порождать два потока как ядра - каждый поток с наивысшим приоритетом, а затем, внутри каждого потока, запустить цикл занятости и выполнить некоторую работу. (Больше потоков, чем ядер - это «украсть» все время, которое я могу получить из других потоков в windows: -)

Используя какой-то API для чтения нагрузки на процессор (возможно, WMI или счетчики производительности?), И я бы затем заставлял каждый поток «выходить» из цикла «занят» (в течение определенного времени каждый цикл спал) до тех пор, пока я не получу Примерная нагрузка в цикле обратной связи.

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

Но, я понятия не имею, правда: -)

Удачного кодирования.


Кроме того, рассмотрите возможность управления питанием - иногда оно может заблокировать процессор на «max%». Затем полностью загрузите процессор, и он достигнет максимального значения в этом пределе (По крайней мере, Windows 7 имеет встроенную функцию для этого, в зависимости от процессора и набора микросхем - вероятно, существует много инструментов сторонних производителей.)

Ситуация становится довольно запутанной с новыми процессорами, которые динамически синхронизируются в зависимости от нагрузки и температуры и т. Д.


Вот моя попытка «наивного» подхода для .NET 3.5. Обязательно включите ссылку System.Management.

Загрузка ЦП, как сообщает диспетчер задач, колеблется в пределах нескольких процентов от целевого значения - в среднем это выглядит чертовски близко - в моей системе. YMMV, но есть некоторая гибкость для настройки.

Счастливое кодирование (снова).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Threading;
using System.Diagnostics;

namespace CPULoad
{
    class Program
    {
        // What to try to get :-)
        static int TargetCpuUtilization = 50;
        // An average window too large results in bad harmonics -- keep it small.
        static int AverageWindow = 5;
        // A somewhat large number gets better results here.
        static int ThreadsPerCore = 8;
        // WMI is *very slow* compared to a PerformanceCounter.
        // It still works, but each cycle is *much* longer and it doesn't
        // exhibit as good of characteristics in maintaining a stable load.
        // (It also seems to run a few % higher).
        static bool UseWMI = false;
        // Not sure if this helps -- but just play about :-)
        static bool UseQuestionableAverage = true;

        static int CoreCount () {
            var sys = new ManagementObject("Win32_ComputerSystem.Name=\"" + Environment.MachineName + "\"");
            return int.Parse("" + sys["NumberOfLogicalProcessors"]);
        }

        static Func<int> GetWmiSampler () {
            var searcher = new ManagementObjectSearcher(
                @"root\CIMV2",
                "SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfOS_Processor");
            return () => {
                var allCores = searcher.Get().OfType<ManagementObject>().First();
                return int.Parse("" + allCores["PercentProcessorTime"]);
            };
        }

        static Func<int> GetCounterSampler () {
            var cpuCounter = new PerformanceCounter {
                CategoryName = "Processor",
                CounterName = "% Processor Time",
                InstanceName = "_Total",
            };
            return () => {
                return (int)cpuCounter.NextValue();
            };
        }

        static Func<LinkedList<int>, int> StandardAverage () {
            return (samples) => {
                return (int)samples.Average();
            };    
        }

        // Bias towards newest samples
        static Func<LinkedList<int>, int> QuestionableAverage () {
            return (samples) => {
                var weight = 4.0;
                var sum = 0.0;
                var max = 0.0;
                foreach (var sample in samples) {
                    sum += sample * weight;
                    max += weight;
                    weight = Math.Min(4, Math.Max(1, weight * 0.8));
                }
                return (int)(sum / max);
            };
        }

        static void Main (string[] args) {
            var threadCount = CoreCount() * ThreadsPerCore;
            var threads = new List<Thread>();
            for (var i = 0; i < threadCount; i++) {
                Console.WriteLine("Starting thread #" + i);                
                var thread = new Thread(() => {
                    Loader(
                        UseWMI ? GetWmiSampler() : GetCounterSampler(),
                        UseQuestionableAverage ? QuestionableAverage() : StandardAverage());
                });
                thread.IsBackground = true;
                thread.Priority = ThreadPriority.Highest;
                thread.Start();
                threads.Add(thread);
            }
            Console.ReadKey();
            Console.WriteLine("Fin!");
        }

        static void Loader (Func<int> nextSample, Func<LinkedList<int>, int> average) {
            Random r = new Random();
            long cycleCount = 0;
            int cycleLength = 10;
            int sleepDuration = 15;
            int temp = 0;
            var samples = new LinkedList<int>(new[] { 50 });
            long totalSample = 0;

            while (true) {
                cycleCount++;
                var busyLoops = cycleLength * 1000;
                for (int i = 0; i < busyLoops; i++) {
                    // Do some work
                    temp = (int)(temp * Math.PI);
                }
                // Take a break
                Thread.Sleep(sleepDuration);

                {
                    // Add new sample
                    // This seems to work best when *after* the sleep/yield
                    var sample = nextSample();
                    if (samples.Count >= AverageWindow) {
                        samples.RemoveLast();
                    }
                    samples.AddFirst(sample);
                    totalSample += sample;
                }
                var avg = average(samples);
                // should converge to 0
                var conv = Math.Abs(TargetCpuUtilization - (int)(totalSample / cycleCount));

                Console.WriteLine(string.Format("avg:{0:d2} conv:{1:d2} sleep:{2:d2} cycle-length:{3}",
                    avg, conv, sleepDuration, cycleLength));
                // Manipulating both the sleep duration and work duration seems
                // to have the best effect. We don't change both at the same
                // time as that skews one with the other.
                // Favor the cycle-length adjustment.
                if (r.NextDouble() < 0.05) {
                    sleepDuration += (avg < TargetCpuUtilization) ? -1 : 1;
                    // Don't let sleep duration get unbounded upwards or it
                    // can cause badly-oscillating behavior.
                    sleepDuration = (int)Math.Min(24, Math.Max(0, sleepDuration));
                } else {
                    cycleLength += (avg < TargetCpuUtilization) ? 1 : -1;
                    cycleLength = (int)Math.Max(5, cycleLength);
                }
            }
        }
    }
}

Хотя Windows является приоритетной операционной системой, код, который работает в Режим ядра - например, драйверы - вытесняется гораздо реже. Хотя это невозможно в C # AFAIK, это должно привести к более строгому управлению нагрузкой, чем приведенное выше, но также имеет большую сложность (и возможность сбоя всей системы: -)

Существует Process.PriorityClass, но установка этого значения на что-либо, кроме нормального, не дала бы мне последовательного поведения.

0 голосов
/ 07 апреля 2011

Я не знаю, можете ли вы это сделать, но вы можете изменить приоритет потока исполняющего потока через свойство Priority. Вы установили бы это:

Thread.CurrentThread.Priority = ThreadPriority.Lowest;

Кроме того, я не думаю, что вы действительно хотите ограничить это. Если машина в противном случае простаивает, вы хотите, чтобы она занялась этой задачей, верно? ThreadPriority помогает сообщить об этом планировщику.

Ссылка: Как ограничить использование ЦП программой C #?

...