В программной инженерии профилирование ( «программное профилирование», «программное профилирование») — это форма динамического анализа программы , которая измеряет, например, пространственную (память) или временную сложность программы , использование определенных инструкций или частоту и длительность вызовов функций. Чаще всего информация профилирования служит для помощи в оптимизации программы , а точнее, в проектировании производительности .
Профилирование достигается путем инструментирования исходного кода программы или ее двоичной исполняемой формы с помощью инструмента, называемого профайлером (или профайлером кода ). Профилировщики могут использовать ряд различных методов, таких как основанные на событиях, статистические, инструментированные и имитационные методы.
Профилировщики используют широкий спектр методов для сбора данных, включая аппаратные прерывания , инструментирование кода , моделирование набора инструкций , перехватчики операционной системы и счетчики производительности .
Инструменты анализа программ чрезвычайно важны для понимания поведения программ. Архитекторам компьютеров нужны такие инструменты для оценки того, насколько хорошо программы будут работать на новых архитектурах . Разработчикам программного обеспечения нужны инструменты для анализа своих программ и выявления критических участков кода. Разработчики компиляторов часто используют такие инструменты, чтобы узнать, насколько хорошо работает их алгоритм планирования инструкций или предсказания ветвлений ...
— АТОМ, ПЛДИ
Выходные данные профилировщика могут быть следующими:
/* ------------ источник------------------------- количество */ 0001 ЕСЛИ Х = "А" 00550002 ТОГДА ДЕЛАЙТЕ 0003 ДОБАВИТЬ 1 к XCOUNT 00320004 ИНАЧЕ0005 ЕСЛИ Х = "В" 0055
Профилировщик может быть применен к отдельному методу или в масштабе модуля или программы, чтобы выявить узкие места производительности, сделав долго выполняющийся код очевидным. [1] Профилировщик может быть использован для понимания кода с точки зрения синхронизации с целью его оптимизации для обработки различных условий выполнения [2] или различных нагрузок. [3] Результаты профилирования могут быть приняты компилятором, который обеспечивает оптимизацию на основе профиля . [4] Результаты профилирования могут быть использованы для руководства разработкой и оптимизацией отдельного алгоритма; примером является алгоритм Krauss matching wildcards . [5] Профилировщики встроены в некоторые системы управления производительностью приложений , которые агрегируют данные профилирования для предоставления информации о рабочих нагрузках транзакций в распределенных приложениях. [6]
Инструменты анализа производительности существовали на платформах IBM/360 и IBM/370 с начала 1970-х годов, обычно основанные на прерываниях таймера, которые записывали слово состояния программы (PSW) с заданными интервалами таймера для обнаружения «горячих точек» в исполняемом коде. [ требуется цитата ] Это был ранний пример выборки (см. ниже). В начале 1974 года симуляторы набора инструкций позволяли полную трассировку и другие функции мониторинга производительности. [ требуется цитата ]
Анализ программ, управляемых профилировщиком, на Unix восходит к 1973 году, [7] когда системы Unix включали базовый инструмент, prof
, который перечислял каждую функцию и сколько времени выполнения программы она использовала. В 1982 году gprof
концепция была расширена до полного анализа графа вызовов . [8]
В 1994 году Амитабх Шривастава и Алан Юстас из Digital Equipment Corporation опубликовали статью, описывающую ATOM [9] (Analysis Tools with OM). Платформа ATOM преобразует программу в свой собственный профайлер: во время компиляции она вставляет код в программу для анализа. Этот вставленный код выводит данные анализа. Эта техника — изменение программы для анализа самой себя — известна как « инструментация ».
В 2004 году gprof
статьи журнала ATOM и журнала Therapeutics появились в списке 50 самых влиятельных статей PLDI за 20-летний период, закончившийся в 1999 году. [10]
Профилировщики вычисляют среднее время вызовов на основе вызовов и не разбивают время вызовов на основе вызываемого абонента или контекста.
Профилировщики графов вызовов [8] показывают время вызова и частоту функций, а также задействованные цепочки вызовов на основе вызываемого. В некоторых инструментах полный контекст не сохраняется.
Входные чувствительные профилировщики [11] [12] [13] добавляют еще одно измерение к плоским или графовым профилировщикам вызовов, связывая показатели производительности с особенностями входных рабочих нагрузок, такими как размер входных данных или входные значения. Они генерируют диаграммы, которые характеризуют, как производительность приложения масштабируется в зависимости от его входных данных.
Профилировщики, которые также являются программами, анализируют целевые программы, собирая информацию об их выполнении. В зависимости от детализации данных и способа сбора информации профайлерами они классифицируются на событийные и статистические профайлеры. Профилировщики прерывают выполнение программы для сбора информации, что может привести к ограниченному разрешению в измерениях времени, к чему следует относиться с долей скепсиса. Базовые блочные профайлеры сообщают количество машинных тактовых циклов, выделенных на выполнение каждой строки кода, или время, основанное на их сложении; время, сообщаемое для базового блока, может не отражать разницу между попаданиями и промахами кэша . [14] [15]
Перечисленные здесь языки программирования имеют профилировщики на основе событий:
Некоторые профилировщики работают по принципу выборки . Профилировщик выборки проверяет стек вызовов целевой программы через регулярные интервалы времени, используя прерывания операционной системы . Профили выборки, как правило, менее точны и специфичны в числовом отношении, но позволяют целевой программе работать практически на полной скорости.
Полученные данные не являются точными, а представляют собой статистическую аппроксимацию. «Фактическая величина ошибки обычно больше одного периода выборки. Фактически, если значение в n раз больше периода выборки, ожидаемая ошибка в нем равна квадратному корню из n периодов выборки». [16]
На практике профилировщики выборки часто могут предоставить более точную картину выполнения целевой программы, чем другие подходы, поскольку они не так навязчивы к целевой программе и, таким образом, не имеют столько побочных эффектов (например, на кэши памяти или конвейеры декодирования инструкций). Кроме того, поскольку они не так сильно влияют на скорость выполнения, они могут обнаруживать проблемы, которые в противном случае были бы скрыты. Они также относительно невосприимчивы к переоценке стоимости небольших, часто вызываемых процедур или «жестких» циклов. Они могут показать относительное количество времени, проведенного в пользовательском режиме по сравнению с прерываемым режимом ядра, таким как обработка системных вызовов .
Тем не менее, код ядра для обработки прерываний влечет за собой незначительную потерю циклов ЦП, перенаправление использования кэша и неспособен различать различные задачи, выполняемые в непрерываемом коде ядра (активность в диапазоне микросекунд).
Специализированное оборудование может выйти за эти рамки: интерфейс JTAG процессоров ARM Cortex-M3 и некоторых последних MIPS имеет регистр PCSAMPLE, который осуществляет выборку программного счетчика совершенно незаметно, что позволяет осуществлять неинвазивный сбор плоского профиля.
Некоторые часто используемые [17] статистические профилировщики для Java/управляемого кода — это AQtime от SmartBear Software [18] и CLR Profiler от Microsoft . [19] Эти профилировщики также поддерживают профилирование собственного кода, наряду с Shark (OSX) от Apple Inc. [20] , OProfile (Linux), [21] Intel VTune и Parallel Amplifier (часть Intel Parallel Studio ), а также Oracle Performance Analyzer [ 22] и другими.
Этот метод эффективно добавляет инструкции в целевую программу для сбора необходимой информации. Обратите внимание, что инструментирование программы может вызвать изменения производительности и в некоторых случаях может привести к неточным результатам и/или гейзенбагам . Эффект будет зависеть от того, какая информация собирается, от уровня сообщаемых временных подробностей и от того, используется ли базовое профилирование блоков в сочетании с инструментированием. [23] Например, добавление кода для подсчета каждого вызова процедуры/рутины, вероятно, будет иметь меньший эффект, чем подсчет того, сколько раз выполняется каждый оператор. Некоторые компьютеры имеют специальное оборудование для сбора информации; в этом случае воздействие на программу минимально.
Инструментарий играет ключевую роль в определении уровня контроля и величины временного разрешения, доступных профилировщикам.