Я отслеживаю некоторые машины, использующие WMI, используя .NET System.Management
. Я использую этот запрос:
SELECT Timestamp_Sys100NS, PercentProcessorTime
FROM Win32_PerfRawData_PerfOS_Processor
WHERE Name='_Total'
Из этого я вычисляю использование CPU% с помощью известной формулы:
double cpu_usage = (1 - (double)delta_cpu / delta_time) * 100;
Он отлично работает на каждой машине, кроме одной (до сих пор).
Проблема в том, что для одной машины, которая является сервером Windows 2003 (при включенной гиперпотоке, если это имеет значение), иногда я получаю отрицательные значения использования ЦП. Другими словами, выражение (double)delta_cpu / delta_time
дает число > 1
. Я искал в Интернете подсказки о том, почему это может произойти, но я ничего не нашел.
Является ли этот сервер Windows 2003 конкретным? Или это проблема с гиперпотоком? Или это просто ожидалось, и я должен просто закрепить значение использования ЦП или значение cpu_delta
в каком-то диапазоне?
EDIT:
Вторая странная вещь, которую я наблюдаю на этой машине, заключается в том, что значение Timestamp_Sys100NS
не указывает FILETIME
как дата (тикает с эпохи 1 января 1600 г.), но вместо этого она выглядит как тики с момента загрузки.
ИЗМЕНИТЬ 2: Теперь я проверял, что эта проблема встречается на многих серверах Windows 2003. И я, по-видимому, не единственный с той же проблемой.
ИЗМЕНИТЬ 3:
Я решил проблему с меткой времени, запросив LastBootUpTime
из Win32_OperatingSystem
и добавив это к Timestamp_Sys100NS
, когда значение Timestamp_Sys100NS
слишком далеко в прошлом. Кажется, это дает правильную дату и время. Код, обрабатывающий дату после его получения из Win32_OperatingSystem
, выглядит следующим образом:
WbemScripting.SWbemDateTime swbem_time = new WbemScripting.SWbemDateTime();
swbem_time.Value = date_str;
string time_as_file_time_str = swbem_time.GetFileTime(true);
return new DateTimeOffset(epoch.Ticks + long.Parse(time_as_file_time_str),
swbem_time.UTCSpecified
? TimeSpan.FromMinutes(swbem_time.UTC)
: TimeSpan.Zero);
... затем настройте на UTC...
boot_time = boot_time.UtcDateTime;
... тогда boot_time
просто добавляется к метке времени (current
), возвращаемой WMI в поле Timestamp_Sys100NS
...
if (time.Year < 2000)
time = boot_time + current;
ИЗМЕНИТЬ 4:
По-видимому, существует 3 класса системы по отношению к Timestamp_Sys100NS
:
- Сначала это система Vista +, где
Timestamp_Sys100NS
- время в тиках с эпохи в UTC. - Во-вторых, некоторые системы Windows 2003, где
Timestamp_Sys100NS
необходимо добавить вWin32_OperatingSystem.LastBootUpTime
, чтобы получить разумное время. - Третий класс - это системы, в которых выполнение вышеуказанного добавления по-прежнему приводит к дате выходных дней с правильной даты и времени.
РЕДАКТИРОВАТЬ 5: Некоторые из затронутых машин, возможно, были виртуальными машинами, но не все из них.