WMI, отрицательное значение использования процессора и Timestamp_Sys100NS в прошлом

Я отслеживаю некоторые машины с помощью WMI, используя System.Management от .NET. Я использую следующий запрос:

SELECT Timestamp_Sys100NS, PercentProcessorTime 
FROM Win32_PerfRawData_PerfOS_Processor 
WHERE Name='_Total'

Из него я вычисляю % использования процессора, используя хорошо известную формулу:

double cpu_usage = (1 - (double)delta_cpu / delta_time) * 100;

Это работает очень хорошо на всех машинах, кроме одной (пока).

Проблема в том, что для одной машины, которая является Windows 2003 server (с включенной гиперпоточностью, если это имеет значение), я иногда получаю отрицательные значения использования CPU. Другими словами, выражение (double)delta_cpu / delta_time дает число > 1. Я искал в Интернете подсказки, почему это может происходить, но ничего не нашел.

Является ли это спецификой Windows 2003 server? Или это проблема, связанная с гиперпоточностью? Или это просто ожидаемо, и я должен просто зажать значение использования процессора или cpu_delta в какой-то диапазон?

EDIT: Вторая странность, которую я наблюдаю на этой машине, заключается в том, что значение Timestamp_Sys100NS не показывает FILETIME как дату (тики с эпохи 1 января 1600 года), а вместо этого выглядит как тики с момента загрузки.

EDIT 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;

EDIT 4: Похоже, что существует 3 класса систем относительно Timestamp_Sys100NS:

  1. Первый - это системы Vista+, где Timestamp_Sys100NS - это время в тиках от эпохи в UTC.
  2. Во-вторых, это некоторые системы Windows 2003, где Timestamp_Sys100NS нужно добавить к Win32_OperatingSystem.LastBootUpTime, чтобы получить разумное время.
  3. Третий класс - это системы, в которых выполнение вышеуказанного добавления все равно приводит к дате, на несколько дней отклоняющейся от правильной даты и времени.

EDIT 5: Некоторые из пострадавших машин могли быть виртуальными машинами, но не все.

18
задан wilx 5 February 2016 в 19:40
поделиться