это вопрос из двух частей, я хотел бы разместить здесь свой код в стеке, чтобы помочь другим с этой же задачей.
Вопрос 1:
У меня естьподмножество кода, которое, как я считаю, правильно измеряет загрузку процессора (на столько же ядер в системе, сколько раз получено) в соответствии с интервалом измерения - я использую 1 секунду в вызове потока.
Iпришлось расшифровать это из очень немногих статей в Интернете и из кода C ++.На мой вопрос, для вопроса 1, это правильно, что я сделал?
Иногда возвращаемое значение является минусом, поэтому я умножаю на -1.Опять же, я предполагаю, что, поскольку документации очень мало, это то, что я должен делать.
У меня есть следующий код:
public static class Processor
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetSystemTimes(out ComTypes.FILETIME lpIdleTime, out ComTypes.FILETIME lpKernelTime, out ComTypes.FILETIME lpUserTime);
private static TimeSpan _sysIdleOldTs;
private static TimeSpan _sysKernelOldTs;
private static TimeSpan _sysUserOldTs;
static Processor()
{
}
public static void Test()
{
ComTypes.FILETIME sysIdle, sysKernel, sysUser;
if(GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
{
TimeSpan sysIdleTs = GetTimeSpanFromFileTime(sysIdle);
TimeSpan sysKernelTs = GetTimeSpanFromFileTime(sysKernel);
TimeSpan sysUserTs = GetTimeSpanFromFileTime(sysUser);
TimeSpan sysIdleDiffenceTs = sysIdleTs.Subtract(_sysIdleOldTs);
TimeSpan sysKernelDiffenceTs = sysKernelTs.Subtract(_sysKernelOldTs);
TimeSpan sysUserDiffenceTs = sysUserTs.Subtract(_sysUserOldTs);
_sysIdleOldTs = sysIdleTs;
_sysKernelOldTs = sysKernelTs;
_sysUserOldTs = sysUserTs;
TimeSpan system = sysKernelDiffenceTs.Add(sysUserDiffenceTs);
Double cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100) / system.TotalMilliseconds);
if (cpuUsage < 0)
{
Console.WriteLine("CPU: " + ((int) (cpuUsage)*-1) + "%");
}
else
{
Console.WriteLine("CPU: " + (int) (cpuUsage) + "%");
}
Console.WriteLine("");
}
else
{
Console.WriteLine("Couldn't get CPU usage!");
Console.WriteLine("");
}
}
private static TimeSpan GetTimeSpanFromFileTime(ComTypes.FILETIME time)
{
return TimeSpan.FromMilliseconds((((ulong)time.dwHighDateTime << 32) + (uint)time.dwLowDateTime) * 0.000001);
}
}
Вопрос2:
Есть ли у меня возможность синхронизировать поток в моей программе с потоком из диспетчера задач Windows с целью сопоставления значения измерения, например, загрузки ЦП с приведенным выше кодом?
Я имею в виду, что если вы откроете диспетчер задач Windows, вы заметите, что он опрашивает каждую секунду - что на самом деле не должно быть меньше этого.То, что я хочу сделать, это сопоставить время с моим потоком.
Так что, когда Windows Task Manager опрашивает, мой поток опрашивает.
Некоторые примечания:
Я не хотел использовать счетчики производительности или встроенные методы .NET.На самом деле, я считаю - из того, что я прочитал, в .NET нет методов для расчета использования ЦП на машине, что для этого требуются счетчики производительности.
Счетчики производительности имеют накладные расходы и, кроме того,заставить GC расти, не говоря уже о задержке вызова следующего результата .Хотя моему программному обеспечению не требуется производительность в режиме реального времени, оно должно быть максимально быстрым и использовать как можно меньше процессорного времени.Вышеуказанный код может быть вызван и возвращен менее чем за миллисекунду.На самом деле на моей машине для разработки разница во времени составляет 0 мс. Я не верю, что счетчики производительности так же отзывчивы.
Если вам интересно, мое программное обеспечение собирает несколько элементов, ЦП, память, элементы журнала событий и т. Д., Из которых этивсе должно быть собрано и сохранено в SQL CE до следующего опроса, через 1 секунду.Каждая задача, элемент, однако, находится в своем собственном потоке, чтобы облегчить это.
Кроме того, приведенный выше код в любом случае не оптимизирован, и вы заметите, что я еще не прокомментировал его.Причина в том, что я хочу убедиться, что это правильно перед оптимизацией и т. Д.
Обновление 1
В соответствии с комментарием, который я сделал в пути, я удалил лишний«Системный» промежуток времени, так как он не требуется, и изменил строку, которая извлекает «Использование ЦП» и соответственно преобразует его.
int cpuUsage = (int)(((sysKernelDifferenceTs.Add(sysUserDifferenceTs).Subtract(sysIdleDifferenceTs).TotalMilliseconds) * 100.00) / sysKernelDifferenceTs.Add(sysUserDifferenceTs).TotalMilliseconds);
Хотя я все еще не уверен в формуле.Хотя он кажется очень точным, он иногда возвращает минус, поэтому я умножаю его на -1, если это так.В конце концов, нет такой вещи - загрузка процессора -2% и т. Д.
Обновление 2
Поэтому я провел простой тест с использованием "System.Diagnostics.PerformanceCounter",Хотя это невероятно удобно и делает именно то, для чего оно предназначено, оно создает накладные расходы.
Вот мои наблюдения:
- Потребовалось намного больше времени для инициализации счетчика производительности.Примерно на три секунды дольше на моем i7 2,6 ГГц.
- Счетчик производительности, похоже, добавляет еще около 5 МБ оперативной памяти, просто используя его.Я имею в виду следующее: с кодом, приведенным выше, мое приложение достигает максимума в 7,5 МБ оперативной памяти.Со счетчиком производительности он «запускается» на 12,5 МБ.
- В течение 5 секунд, когда мой поток запускался 5 раз - раз в секунду, память моего приложения увеличивалась на 1 МБ, и это увеличение соответствовало времени, хотя в любом случае оно выравнивается, в любом случае, 3-4 МБ выше стартового. Поэтому, когда мое приложение обычно имеет 7,5 МБ ОЗУ с кодом выше, код ПК выровнялся до 16,5 МБ ОЗУ - увеличение на 9 МБ по сравнению с кодом выше. Примечание: Код выше не вызывает это увеличение.
Итак, если ваше приложение было построено таким образом, чтобы использование ресурсов и время были ключевыми, я бы рекомендовал не использовать счетчики производительности по этим причинам. В противном случае продолжайте, как это работает без всего беспорядка.
Что касается моего приложения, то счетчики производительности будут вредны для целей моего программного обеспечения.