WMI, отрицательное значение использования ЦП и Timestamp_Sys100NS в прошлом - PullRequest
18 голосов
/ 25 ноября 2011

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

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

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

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:

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

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

Ответы [ 3 ]

1 голос
/ 26 декабря 2011

для меня это звучит как стандартная проблема "синхронизации времени".

часы вашей системы - это ... часы.в вашем случае ваши часы могут работать быстро (возможно, они заканчивают минуту за 99% фактического времени), поэтому, когда ваш компьютер синхронизируется с внешними часами (например, через службу времени Windows), ваше системное время будет прыгать назад.

альтернативно, пользователь может вручную настроить системное время (например, панель управления датой и временем), так что это то, что вы должны разработать (ваши пользователи будут очень недовольны, если установка их системного времени приведет к сбою вашего приложения!)

способ, которым я решаю это путем зажима.для прохождения всегда требуется не менее 0,0 секунд «реального времени», а также ограничение до 0,5 секунд, поскольку регулировка времени может быть скачком вперед, а не только назад.

Надеюсь, это поможет.

0 голосов
/ 08 декабря 2011

Формула, о которой вы конкретно говорите: 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, он отлично подходит.Я думаю, что вы можете игнорировать все, что меньше нуля, если вы рассчитываете с этими значениями.

0 голосов
/ 29 ноября 2011

Попробуйте использовать приложение создания кода на этом компьютере и посмотрите, правильно ли вы читаете http://www.microsoft.com/download/en/details.aspx?id=8572

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...