WMI, отрицательное значение использования ЦП и Timestamp_Sys100NS в прошлом
Я отслеживаю некоторые машины, использующие 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: Некоторые из затронутых машин, возможно, были виртуальными машинами, но не все из них.
Ответы
Ответ 1
это звучит как стандартная проблема синхронизации времени.
ваши системные часы - это часы. в вашем случае ваши часы могут работать быстро (возможно, это завершает минуту в 99% от фактического времени), поэтому, когда ваш компьютер синхронизируется с внешними часами (например, через службу времени Windows), ваше системное время будет отскакивать назад.
В качестве альтернативы пользователь может вручную настроить системное время (например, панель управления "Дата и время" ), поэтому вам нужно что-то разработать (ваши пользователи будут очень недовольны, если их системное время сработает ваше приложение!)
способ, которым я решаю это, - это зажим. всегда требуется не менее 0,0 секунд "реального времени" для передачи, но также зажимать максимум до 0,5 секунды, так как регулировка времени может прыгать вперед, а не только назад.
Надеюсь, что это поможет.
Ответ 2
Попробуйте использовать приложение создания кода на этом компьютере и проверьте, не получили ли вы правильные показания
http://www.microsoft.com/download/en/details.aspx?id=8572
Ответ 3
Формула, о которой вы конкретно говорите, это PERF_100NSEC_TIMER_INV
http://msdn.microsoft.com/en-us/library/ms803963.aspx
Я лично не рассматривал эту проблему, потому что никогда не видел значений ниже нуля.
Это все, что я делал:
/// <summary>
/// PERF_100NSEC_TIMER_INV algorithm.
/// </summary>
/// <param name="n2"></param>
/// <param name="d2"></param>
/// <param name="n1"></param>
/// <param name="d1"></param>
/// <returns></returns>
public static int CalculatePerf100NsecTimerInv(long n2, UInt64 d2,
long n1, UInt64 d1)
{
int usage = 0;
try
{
double dataDiff = (n2 - n1);
double timeDiff = (d2 - d1);
double dUsage = (1 - (dataDiff / timeDiff)) * 100;
// Evaluate
usage = (dUsage >= 0.5) ? Convert.ToInt32(Math.Ceiling(dUsage)) : 0;
}
catch { }
// Return
return usage;
}
Использование:
// Calculate
int cpuTime =
MSPerformanceAlgorithms.CalculatePerf100NsecTimerInv(
current.PercentProcessorTime, current.TimestampSys100Ns,
previous.PercentProcessorTime, previous.TimestampSys100Ns);
Если я смотрю использование ЦП в диспетчере задач для окна 2003 года, он соответствует штрафу. Я думаю, вы можете игнорировать все, что меньше нуля, пока вы вычисляете эти значения.