Очень медленный доступ для чтения счетчика производительности - как это делает диспетчер задач?

Я пытаюсь внедрить инструмент мониторинга производительности, я хочу контролировать основные вещи, такие как память и ЦП.

Я пытаюсь сделать это с помощью счетчиков производительности, поскольку считаю, что это то, что Диспетчер задач также использует за кулисами. Я понятия не имею, как диспетчер задач может это сделать, однако мне кажется, что для получения данных процесса с использованием этого метода требуется ОЧЕНЬ много времени:

class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                var pcs = Process.GetProcesses()
                    .Select(p => new PerformanceCounter("Process", "Working Set - Private", p.ProcessName));

                var sw = Stopwatch.StartNew();

                foreach (var pc in pcs)
                    pc.NextValue();

                Console.WriteLine($"Time taken to read {pcs.Count()} performance counters: {sw.ElapsedMilliseconds}ms");

                Thread.Sleep(1000);
            }
        }
    }

введите здесь описание изображения

Кто-нибудь получил какие-либо предложения о том, как это сделать или как даже диспетчер задач или Process Explorer может это сделать?


person mikeysee    schedule 04.12.2016    source источник
comment
Пробовали запускать без отладки? Отладка может существенно повлиять на производительность операторов LINQ. (просто предполагаю)   -  person Paul Stelian    schedule 04.12.2016
comment
Диспетчер задач и Process Explorer написаны на языке более низкого уровня (скорее всего, C++)   -  person Paul Stelian    schedule 04.12.2016
comment
Диспетчер задач не создает новый экземпляр PerformanceCounter внутри цикла обновления. Уберите его и добавьте .ToList() в конце, и держу пари, вы увидите намного меньше времени.   -  person Scott Chamberlain    schedule 04.12.2016
comment
@PaulStelian - Да, запуск в режиме выпуска не имеет значения, попробуйте запустить код самостоятельно. Код не работает медленно, это медленно считывается счетчиком производительности.   -  person mikeysee    schedule 04.12.2016
comment
@ScottChamberlain - перемещение GetProcess за пределы цикла не дает никакого эффекта. Обратите внимание, что время StopWatch в любом случае не связано с этой частью кода. Попробуйте запустить код самостоятельно, чтобы увидеть.   -  person mikeysee    schedule 04.12.2016
comment
Диспетчер задач использовал ZwQuerySystemInformation для этой задачи   -  person RbMm    schedule 04.12.2016
comment
Некоторые из этих значений вы можете получить непосредственно из Process экземпляр, но, например. Данные процессора имеют неверный формат.   -  person WerWet    schedule 14.04.2017


Ответы (1)


Как это делает диспетчер задач?

он использовал вызовы ZwQuerySystemInformation, ZwQueryInformationProcess, ZwQueryInformationThread .. Диспетчер задач поддерживает базу данных активных процессов и периодически обновляет эту информацию, вызывая ZwQuerySystemInformation(SystemProcessInformation,) - поэтому при выходе получил массив SYSTEM_PROCESS_INFORMATION. добавить новые записи, если найден новый процесс, но не в DB, удалить записи для умерших процессов, обновить информацию для живых SYSTEM_PROCESS_INFORMATION, уже содержащих много информации о процессе. дополнительную информацию можно получить с помощью открытого процесса и вызова ZwQueryInformationProcess с соответствующим информационным классом

если вы хотите внедрить инструмент мониторинга производительности без «квантового эффекта» (когда измерение влияет на само состояние), вам нужно использовать этот ntdll API. определения смотрите на http://processhacker.sourceforge.net/doc/ntexapi_8h_source.html несмотря на то, что это недокументировано, существующие функции и структуры не изменились как минимум с win2000 (то есть ~17 лет) - новая версия windows добавляет много новых информационных классов, некоторые поля, которые были запасными/неиспользованными в старой версии - могут стать используемыми, но старая(устаревшая) не изменена

person RbMm    schedule 04.12.2016
comment
Комментарии не для расширенного обсуждения; этот разговор был перенесено в чат. - person Bhargav Rao; 06.12.2016
comment
Я собираюсь принять это как правильный и ответить, поскольку даже если я не получил удовлетворительного ответа на то, как мне сделать это эффективно, он ответил на мой вопрос о том, как диспетчер задач может это сделать. - person mikeysee; 07.12.2016
comment
@mikeysee - я могу предложить вам начать с вызова ZwQuerySystemInformation(SystemProcessInformation,*) - по возвращении вы получите массив SYSTEM_PROCESS_INFORMATION - по одному на процесс (начиная с виртуального процесса бездействия) с большим количеством информации о каждом процессе уже (имя, количество потоков, использование памяти, время создания , количество вводов-выводов и т. д.) - поэтому не вызывайте никаких управляемых функций, а только это и ищите производительность. в любом случае это хороший обучающий тест. я могу показать код для этого, но только на c++ - person RbMm; 07.12.2016