Счетчики производительности в приложениях .NET Framework

95 Исходники для статьи

Наши статьи по оптимизации приложений посвящены вопросам повышения производительности приложений для .NET. Следует понимать, что нельзя улучшить какие-либо характеристики, не измерив их предварительно. Именно поэтому эта статья посвящена инструментам и приемам измерения производительности. Построение догадок и преждевременных выводов об узких местах в приложении - это самое худшее, что может сделать разработчик. Как было показано в предыдущей статье существует множество любопытных характеристик производительности, которые могут играть важную роль в оценке производительности приложения в целом, а в этой статье мы узнаем, как измерять их.

Подходы к измерению производительности

Измерение производительности приложений может выполняться разными способами, во многом зависящих от контекста, сложности приложения, типа требуемой информации и точности получаемых результатов.

Один из подходов к тестированию небольших программ или библиотечных методов называется тестированием по принципу «стеклянного ящика». Этот подход основан на исследовании исходного кода, анализе его сложности, изменении и добавлении кода, выполняющего измерения. Этот подход, который иногда называется микрохронометраж (microbenchmarking), особенно ценен - и часто незаменим - когда требуется высочайшая точность результатов хронометража небольших фрагментов кода, где каждая машинная инструкция на счету, но требует больших трудозатрат при оценке больших приложений. Кроме того, не зная наперед, какие фрагменты программ следует тестировать, выявление узких мест без применения автоматизированных инструментов может оказаться чрезвычайно трудной задачей.

Для больших программ чаще используется подход, называемый тестированием по принципу «черного ящика», когда параметры производительности определяются человеком и затем измеряются с применением инструментов. Применяя этот подход, разработчик не должен строить какие-либо гипотезы об узких местах в приложении.

В наших статьях мы познакомимся с большим количеством инструментов, автоматически анализирующих производительность приложения и предоставляющих результаты измерений в простом и понятном виде. В числе этих инструментов будут упомянуты счетчики производительности (performance counters), механизм трассировки событий для Windows (Event Tracing for Windows, ETW) и коммерческие профилировщики.

Инструменты измерения производительности сами могут отрицательно влиять на производительность. Лишь немногие из них способны дать точную информацию, не добавляя свои накладные расходы. Перемещаясь от одного инструмента к другому, всегда помните, что точность инструмента часто искажается накладными расходами, которые они вносят при применении к приложению.

Прежде, чем обратиться к коммерческим инструментам, требующим предварительной установки, познакомимся сначала с инструментами, которые может предложить Windows «из коробки». Счетчики производительности являются составной частью Windows вот уже почти два десятилетия. Не так давно (в 2006 г.) в Windows Vista появился еще один инструмент хронометража - механизм трассировки событий для Windows (Event Tracing for Windows). Оба входят в состав всех разновидностей Windows и могут использоваться для оценки производительности с минимальными накладными расходами.

Счетчики производительности

Счетчики производительности - это встроенный механизм Windows позволяющий оценивать производительность и состояние системы в целом. С помощью счетчиков производительности пользователи и администраторы могут исследовать работу различных компонентов, включая ядро Windows, драйверы, базы данных и CLR. Как дополнительное преимущество, счетчики производительности для подавляющего большинства компонентов системы уже включены по умолчанию, поэтому вам не придется вносить поправки на дополнительные накладные расходы, связанные с их использованием.

Прочитать информацию из счетчиков производительности в локальной или удаленной системе чрезвычайно просто. Встроенный инструмент Perfomance Monitor (Системный монитор) - perfmon.exe может отображать все счетчики производительности, доступные в системе и сохранять информацию в файле для последующего изучения, а также автоматически генерировать оповещения, когда значение того или иного счетчика производительности превышает некоторый установленный порог. Инструмент Performance Monitor может также подключаться к удаленным системам, если вы обладаете привилегиями администратора и возможностью подключения к удаленной системе по локальной сети.

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

Категории счетчиков производительности (или объектов производительности) представляют наборы отдельных счетчиков для определенных компонентов системы. В качестве примеров категорий можно привести: .NET CLR Memory, Processor Information, TCPv4 и PhysicalDisk.

Счетчики производительности

Это отдельные числовые свойства в категориях. Обычно принято указывать категорию и название счетчика производительности, разделяя их обратным слешем, например, Process\Private Bytes. Счетчики производительности могут иметь разные типы, включая простые числовые значения (Process\Thread Count), скорости следования событий (Print Queue\Bytes Printed/sec), проценты (PhysicalDisk\%Idle Time) и средние значения (ServiceModelOperation 3.0.0.0\Calls Duration).

Экземпляры категорий счетчиков производительности (вхождения)

Используются с целью создания разных наборов счетчиков для разных экземпляров компонентов системы. Например, в системе может иметься несколько процессоров, поэтому для каждого из них имеется свой экземпляр в категории Processor Information (Сведения о процессоре), а также общий экземпляр _Total). Одни категории счетчиков производительности могут иметь несколько экземпляров (таковых большинство), другие - единственный экземпляр (например, категория Memory (Память)).

Исследовав полный список счетчиков производительности, предоставляемых типичной системой Windows, где выполняются приложения для .NET, легко понять, что многие проблемы производительности могут быть выявлены без использования других инструментов. По крайней мере, счетчики производительности позволяют получить общее представление о причинах низкой производительности, а исследование файлов журналов поможет понять, насколько поведение системы отличается от нормального.

Ниже перечислены ситуации, когда системный администратор или разработчик, занимающийся проблемами производительности, сможет получить представление о том, где находится узкое место в приложении, прежде чем применить более мощные инструменты:

Мониторинг использования памяти с применением счетчиков производительности

В этом коротком эксперименте предлагается провести мониторинг использования памяти демонстрационным приложением и с помощью программы Performance Monitor (Системный монитор) выявить наличие утечек памяти, как описывалось выше.

  1. Запустите программу Performance Monitor - это можно сделать, отыскав пункт Performance Monitor (Системный монитор) в меню Start (Пуск) или запустив программу perfmon.exe непосредственно (Win+R).

  2. Запустите приложение MemoryLeak.exe из папки с исходниками для этой статьи.

  3. Щелкните на пункте "Системный монитор" в панели слева и затем щелкните на кнопке с изображением зеленого плюса (+).

  4. В категории .NET CLR Memory (Память CLR .NET) выберите счетчики # Bytes in all Heaps (Байт во всех кучах) и Allocated Bytes/sec (Выделено байт/сек), в списке снизу выберите экземпляр MemoryLeak.exe и щелкните на кнопке Add (Добавить).

    Добавление счетчиков производительности для приложения
  5. В категории Process (Процесс) выберите счетчик Private Bytes (Байт исключительного пользования), в списке выберите экземпляр MemoryLeak и щелкните на кнопке Add.

  6. Щелкните на кнопке ОК, чтобы подтвердить свой выбор и понаблюдайте за изменениями на графике.

  7. Вам может понадобиться щелкнуть правой кнопкой мыши на строке со счетчиком в таблице, находящейся внизу окна и выбрать пункт контекстного меню Scale selected counters (Масштабировать выделенные счетчики), чтобы линии появились на графике.

Вы должны увидеть, что линии, соответствующие счетчикам Private Bytes (Байт исключительного пользования) и # Bytes in all Heaps (Байт во всех кучах) изменяются синхронно (как на первом рисунке выше). Это указывает на утечки памяти в управляемой куче.

В типичной системе Windows существуют, буквально, тысячи счетчиков производительности. И ни один, даже самый опытный разработчик, не в состоянии запомнить назначение их всех. Поэтому в диалоге «Add Counters» (Добавить счетчики) есть возможность отметить флажок «Show zdescription» (Отображать описание). Когда флажок установлен, в нижней части окна будет отображаться дополнительное описание, которое сообщит, например, что счетчик «System\Processor Queue Length» (Система\Длина очереди процессора) - это количество потоков выполнения, ожидающих своей очереди, или, что счетчик «.NET CLR Locks And Threads\Contention Rate/sec» (Блокировки и потоки .NET CLR\Частота конфликтов/сек) - это количество неудачных попыток (в секунду) предпринятых потоками выполнения, чтобы получить управляемую блокировку.

Журналы и оповещения производительности

Добавить сохранение в журнал значений счетчиков производительности очень просто, и есть даже возможность передать системным администраторам XML-шаблон, чтобы они с его помощью могли добавить автоматическую запись счетчиков без необходимость делать это вручную. После записи данных, журнал можно открыть на любом компьютере и проиграть его, как если это были оперативные данные. (Есть даже некоторые встроенные наборы счетчиков, которые не требуется настраивать вручную для записи в журнал.)

Инструмент Performance Monitor позволяет также определять настройки оповещений - выполнения определенных заданий при превышении указанными счетчиками установленных пороговых значений. Данную возможность можно использовать для создания упрощенной инфраструктуры мониторинга, способной отправлять электронные письма или сообщения системному администратору при нарушении ограничений производительности.

Например, оповещение можно настроить так, что оно автоматически будет перезапускать процесс при достижении опасного предела используемого объема памяти, или когда система исчерпает все свободное пространство на диске. Мы настоятельно рекомендуем поэкспериментировать с системным монитором, чтобы поближе познакомиться с предлагаемыми им возможностями.

Настройка записи значений счетчиков в журнал

Чтобы настроить запись значений счетчиков в журнал, откройте Performance Monitor и выполните описываемые ниже действия. (Здесь предполагается, что вы пользуетесь Windows 8. В предыдущих версиях операционной системы системный монитор имел несколько иной интерфейс - если вы пользуетесь такими версиями, обращайтесь к документации за более подробными инструкциями.)

  1. В дереве слева разверните ветку Data Collector Sets (Группы сборщиков данных).

  2. Щелкните правой кнопкой мыши на пункте User Defined (Особые) и выберите пункт New --> Data Collector Set (Создать --> Группа сборщиков данных) контекстного меню.

  3. Введите имя группы, выберите радиокнопку Create manually (Advanced) (Создать вручную (для опытных)) и щелкните на кнопке Next.

  4. Выберите радиокнопку Create data logs (Создать журналы данных), отметьте флажок Performance counter (Счетчик производительности) и щелкните на кнопке Next.

  5. Щелкните на кнопке Add и добавьте счетчики производительности (в открывшемся стандартном диалоге Add Counters (Добавить счетчики)). Закончив добавление, настройте значение в поле Sample Interval (Интервал выборки) (по умолчанию замеры производятся один раз в 15 секунд) и щелкните на кнопке Next.

  6. Укажите каталог, где будут сохраняться журналы и щелкните на кнопке Next.

  7. Выберите радиокнопку Open properties for this data collector set (Открыть свойства группы сборщиков данных) и щелкните на кнопке Finish (Готово).

  8. В открывшемся диалоге выполните настройки на разных вкладках - здесь можно определить расписание для автоматического запуска, условия останова (например, после сбора определенного объема данных) и задание, которое следует запустить после прекращения сбора данных (например, выгрузить результаты в централизованное хранилище). Завершив настройки, щелкните на кнопке ОК.

  9. Разверните ветку дерева User Defined (Особые), щелкните правой кнопкой мыши на вновь созданной группе сборщиков данных и выберите пункт контекстного меню Start (Пуск).

  10. В результате начнется накопление данных в журнале, хранящемся в выбранном вами каталоге. Сбор данных можно остановить в любой момент, щелкнув на группе правой кнопкой мыши и выбрав пункт контекстного меню Stop.

Когда после завершения сбора данных вам потребуется исследовать их с помощью системного монитора, выполните следующие действия:

  1. Разверните ветку дерева User Defined.

  2. Щелкните правой кнопкой мыши на группе сборщиков данных и выберите пункт контекстного меню Latest Report (Последний отчет).

  3. В появившемся окне вы сможете добавить или удалить счетчики из списка в журнале, настроить диапазон изменения времени и масштаб изменения данных, щелкнув правой кнопкой мыши на графике и выбрав пункт контекстного меню Properties (Свойства).

Наконец, чтобы проанализировать данные на другом компьютере, необходимо скопировать каталог с журналами на этот компьютер, открыть ветку дерева Performance Monitor и щелкнуть на второй кнопке слева в панели инструментов (или нажать комбинацию клавиш Ctrl + L). В появившемся диалоге выберите радиокнопку Log files (Файлы журнала) и добавьте файлы с помощью кнопки Add (Добавить...).

Собственные счетчики производительности

Системный монитор - чрезвычайно удобный инструмент, однако значения счетчиков производительности можно читать из любого приложения для .NET, с помощью класса PerformanceCounter из пространства имен System.Diagnostics. Более того, можно даже создавать собственные счетчики производительности и добавлять их к множеству уже имеющихся.

Ниже описаны некоторые ситуации, когда может пригодиться создание собственных категорий счетчиков:

Следующий фрагмент кода - это все, что необходимо, чтобы экспортировать из приложения категорию счетчиков производительности, имеющую единственный экземпляр, и обновлять их периодически. Предполагается, что класс MyUsers хранит информацию о количестве зарегистрировавшихся к настоящему моменту пользователей в вашем приложении, и вы хотите экспортировать эту информацию в виде счетчика производительности. (Чтобы скомпилировать этот фрагмент, потребуется добавить пространство имен System.Diagnostics.)

using System;
using System.Threading;
using System.Diagnostics;

namespace PerfomanceOptimization
{
    // Вспомогательный класс, не имеющий реализации
    public class MyUsers
    {
        public static int UsersCount { get; set; }
    }

    public class Program
    {
        // Вспомогательный метод для создания категории счетчика
        public static void CreateCounterCategory()
        {
            if (PerformanceCounterCategory.Exists("MyUsers"))
                PerformanceCounterCategory.Delete("MyUsers");

            CounterCreationDataCollection counters = new CounterCreationDataCollection();

            CounterCreationData usersAtWork = new CounterCreationData("# Пользователи онлайн",
                "Количество пользователей, работающих в данный момент с вашим приложением",
                PerformanceCounterType.NumberOfItems32);

            counters.Add(usersAtWork);

            PerformanceCounterCategory.Create("MyUsers", "Информация о пользователях онлайн", counters);
        }

        // Этот метод нужно использовать для запуска счетчика
        public static void StartUpdatingCounters()
        {
            PerformanceCounter usersAtWork = new PerformanceCounter("MyUsers",
                "# Пользователи онлайн", false);

            Timer updateTimer = new Timer(_ =>
            {
                // Обновляем значение счетчика
                usersAtWork.RawValue = MyUsers.UsersCount;
            }, 
            null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
        }
    }
}

Как видите, нужно совсем немного усилий, чтобы определить собственные счетчики производительности, и они могут предоставлять весьма важную информацию. Корреляции системного и пользовательского счетчиков производительности часто бывает достаточно, чтобы понять причины, вызывающие проблемы с производительностью или настройками.

Системный монитор можно использовать и для сбора другой информации, не имеющей отношения к счетчикам производительности. Например, его можно применять для сбора информации о системных настройках - значений ключей из реестра, свойств объектов WMI и даже содержимого файлов на диске. Поддерживается также возможность захватывать данные, поставляемые провайдерами механизма ETW для последующего анализа. Используя XML-шаблоны, администраторы могут создавать группы сборщиков данных на других компьютерах и генерировать отчеты, выполнив всего несколько простых операций по настройке.

Счетчики производительности позволяют получить массу интересной информации о производительности, но они не могут использоваться как высокопроизводительная инфраструктура мониторинга и журналирования. Не существует системных компонентов, способных обновлять счетчики производительности чаще нескольких раз в секунду, а сама программа Performance Monitor не позволяет читать значения счетчиков чаще, чем один раз в секунду. Если для анализа потребуется выполнять замеры каких-либо характеристик тысячи раз в секунду, счетчики производительности окажутся непригодными для этого.

Пройди тесты
Лучший чат для C# программистов