2015-08-19 2 views
0

Мы создали приложение мониторинга для нашего корпоративного приложения, которое будет контролировать наши приложения. Счетчики производительности. Мы контролируем пару системных счетчиков (память, процессор) и около 10 собственных пользовательских счетчиков производительности. У нас есть 7 или 8 exes, которые мы контролируем, поэтому каждые пару секунд мы проверяем 80 счетчиков.Высокий процессор при использовании PerformanceCounter.NextValue

Все работает отлично, за исключением случаев, когда мы перебираем счетчики, процессор получает удар, 15% или около того на моей довольно хорошей машине, но на других машинах мы видели это намного выше. Мы хотим, чтобы наше приложение для мониторинга запускалось дискретно в фоновом режиме, ища проблемы, а не ели значительную часть процессора.

Это легко может быть воспроизведено простым классом C#. Это загружает все процессы и получает Private Bytes для каждого. Моя машина имеет 150 процессов. CallNextValue займет 1,4 секунды или около 16% процессорного времени

class test 
{ 
    List<PerformanceCounter> m_counters = new List<PerformanceCounter>(); 

    public void Load() 
    { 
     var processes = System.Diagnostics.Process.GetProcesses(); 
     foreach (var p in processes) 
     { 
      var Counter = new PerformanceCounter(); 
      Counter.CategoryName = "Process"; 
      Counter.CounterName = "Private Bytes"; 
      Counter.InstanceName = p.ProcessName; 

      m_counters.Add(Counter); 
     } 
    } 

    private void CallNextValue() 
    { 
     foreach (var c in m_counters) 
     { 
      var x = c.NextValue();    
     } 
    } 
} 

Doing это то же самое в Perfmon.exe в окнах и добавление счетчика процесса - Байт со всеми процессами выбран я вижу практически НЕТ процессора подхвачена и это также изображая все процессы.

Итак, как Perfmon получает значения? Есть ли лучший/другой способ получить эти счетчики производительности в C#?

Я пробовал использовать RawValue вместо NextValue, и я не вижу никакой разницы.

Я играл с Pdh-вызовом в C++ (PdhOpenQuery, PdhCollectQueryData, ...). Мои первые тесты не кажутся такими, как на CPP, но я еще не создал хороший образец.

+0

Вы запускаете это через некоторое время (1) или как часто это называется CallNextValue()? Когда у меня была такая же проблема, я использовал потоки, чтобы разделить ее на tpm. другое решение - это не очень хорошо, но для уменьшения количества CPU% поставлен Thread.sleep (5) после каждой итерации не запускает цикл так быстро, как это возможно –

+0

В нашем приложении для мониторинга мы вытаскиваем счетчики каждые 5 секунд , В этом тестовом приложении я просто зацепил кнопку до вызова CallNextValue, и он всегда имеет тот же результат, 16% процессор или около того. – Scott

ответ

0

Я не очень хорошо знаком с API-интерфейсом производительности .NET, но у меня есть предположение о проблеме.

В ядре Windows фактически нет API для получения подробной информации об одном процессе. Вместо этого у него есть API, который можно вызвать, чтобы «получить всю информацию обо всех процессах». Это довольно дорогостоящий вызов API. Каждый раз, когда вы выполняете c.NextValue() для одного из ваших счетчиков, система делает этот вызов API, выбрасывает 99% данных и возвращает данные об одном процессе, о котором вы просили.

PerfMon.exe использует те же API PDH, но использует шаблонный запрос - он создает единственный запрос, который получает данные для всех процессов одновременно, поэтому он по существу только вызывает c.NextValue() раз в секунду вместо того, чтобы называть его N раз (где N - количество процессов). Он получает огромную часть данных назад (данные для всех процессов), но относительно дешево сканировать эти данные.

Я не уверен, что API-интерфейс счетчика производительности .NET поддерживает шаблонные запросы. API PDH делает, и было бы намного дешевле выполнить один шаблонный запрос, чем выполнять целую цепочку запросов с одним экземпляром.

Смежные вопросы