Профилирование
Профилирование процессора
Существует два основных подхода к профилированию кода julia:
Через @profile
Где профилирование включено для данного вызова с помощью макроса @profile
julia> using Profile
julia> @profile foo()
julia> Profile.print()
Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
╎147 @Base/client.jl:506; _start()
╎ 147 @Base/client.jl:318; exec_options(opts::Base.JLOptions)
...
Вызванное во время выполнения
Задачи, которые уже выполняются, также могут быть профилированы в течение фиксированного периода времени в любой момент, инициируемый пользователем.
Для запуска профилирования:
- MacOS & FreeBSD (платформы на основе BSD): Используйте
ctrl-tили отправьте сигналSIGINFOпроцессу julia, например% kill -INFO $julia_pid - Linux: Отправьте сигнал
SIGUSR1процессу julia, например% kill -USR1 $julia_pid - Windows: В настоящее время не поддерживается.
Сначала показывается один стек вызовов в момент броска сигнала, затем собирается профиль продолжительностью 1 секунда, за которым следует отчет о профиле в следующей точке передачи управления, которая может быть завершением задачи для кода без точек передачи управления, например, для плотных циклов.
По желанию установите переменную среды JULIA_PROFILE_PEEK_HEAP_SNAPSHOT в 1 для автоматической сборки снимков кучи снимок кучи.
julia> foo()
##== the user sends a trigger while foo is running ==##
load: 2.53 cmd: julia 88903 running 6.16u 0.97s
======================================================================================
Information request received. A stacktrace will print followed by a 1.0 second profile
======================================================================================
signal (29): Information request: 29
__psynch_cvwait at /usr/lib/system/libsystem_kernel.dylib (unknown line)
_pthread_cond_wait at /usr/lib/system/libsystem_pthread.dylib (unknown line)
...
======================================================================
Profile collected. A report will print if the Profile module is loaded
======================================================================
Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
Thread 1 Task 0x000000011687c010 Total snapshots: 572. Utilization: 100%
╎147 @Base/client.jl:506; _start()
╎ 147 @Base/client.jl:318; exec_options(opts::Base.JLOptions)
...
Thread 2 Task 0x0000000116960010 Total snapshots: 572. Utilization: 0%
╎572 @Base/task.jl:587; task_done_hook(t::Task)
╎ 572 @Base/task.jl:879; wait()
...
Настройка
Продолжительность профилирования может быть изменена с помощью Profile.set_peek_duration
Отчет о профиле разбивается по потокам и задачам. Передайте функцию без аргументов в Profile.peek_report[] для переопределения этого. Например, Profile.peek_report[] = () -> Profile.print() для удаления любой группировки. Это также может быть переопределено внешним потребителем данных профиля.
Справочник
Profile.@profileМакрос
@profile
@profile <expression> выполняет ваше выражение, периодически делая обратные трассировки. Они добавляются в внутренний буфер обратных трассировок.
Методы в Profile не экспортируются и должны вызываться, например, как Profile.print()
Profile.clearФункция
clear()
Очистка всех существующих обратных трассировок из внутреннего буфера.
Profile.printФункция
print([io::IO = stdout,] [data::Vector = fetch()], [lidict::Union{LineInfoDict, LineInfoFlatDict} = getdict(data)]; kwargs...)
Выводит результаты профилирования в io (по умолчанию, stdout). Если вы не предоставите вектор data, будет использован внутренний буфер накопленных обратных трассировок.
Ключевые аргументы могут быть любой комбинацией:
format– Определяет, печатаются ли обратные трассировки с (по умолчанию,:tree) или без (:flat) отступов, указывающих структуру дерева.C– Еслиtrue, показываются обратные трассировки из кода C и Fortran (обычно они исключаются).combine– Еслиtrue(по умолчанию), указатели инструкций объединяются, соответствующие одной строке кода.maxdepth– Ограничивает глубину, большую, чемmaxdepthв формате:treesortedby– Управление порядком в формате:flat.:filefuncline(по умолчанию) сортирует по строке исходного кода,:countсортирует в порядке количества собранных образцов, а:overheadсортирует по количеству образцов, полученных каждой функцией отдельно.groupby– Управляет группировкой по задачам и потокам или без группировки. Варианты::none(по умолчанию),:thread,:task,[:thread, :task], или[:task, :thread], где последние два обеспечивают вложенную группировку.noisefloor– Ограничивает кадры, превышающие эвристическую порог шума образца (применяется только к формату:tree). Рекомендованное значение для этого – 2.0 (по умолчанию 0). Этот параметр скрывает образцы, для которыхn <= noisefloor * √N, гдеn— количество образцов в этой строке, аN— количество образцов для вызываемой функции.mincount– Ограничивает вывод только строками с по крайней мереmincountвхождениями.recur– Управление обработкой рекурсии в формате:tree.:off(по умолчанию) выводит дерево как обычно.:flatвместо этого сжимает любую рекурсию (по ip), показывая приблизительный эффект преобразования любой саморекурсии в итератор.:flatcделает то же самое, но также включает сжатие кадров C (может делать странные вещи вокругjl_apply).threads::Union{Int,AbstractVector{Int}}– Укажите потоки, чьи снимки включать в отчете. Обратите внимание, что это не контролирует потоки, в которых собираются образцы (которые также могли быть собраны на другой машине).tasks::Union{Int,AbstractVector{Int}}– Укажите задачи, чьи снимки включать в отчете. Обратите внимание, что это не контролирует задачи, внутри которых собираются образцы.
Ключевые аргументы groupby, threads, и tasks были добавлены в Julia 1.8.
Профилирование на Windows ограничено главным потоком. Другие потоки не были проанализированы и не будут отображаться в отчете.
print([io::IO = stdout,] data::Vector, lidict::LineInfoDict; kwargs...)
Выводит результаты профилирования в io. Этот вариант используется для анализа результатов, экспортированных предыдущим вызовом retrieve. Передайте вектор data обратных трассировок и словарь lidict информации о строках.
См. Profile.print([io], data) для объяснения допустимых ключевых аргументов.
Profile.initФункция
init(; n::Integer, delay::Real)
Настройте delay между обратными трассировками (в секундах) и количество n указателей инструкций, которые могут храниться на поток. Каждый указатель инструкции соответствует одной строке кода; обратные трассировки, как правило, представляют собой длинный список указателей инструкций. Обратите внимание, что 6 указателей инструкций на обратную трассировку используются для хранения метаданных и двух маркеров NULL.
Текущие настройки могут быть получены, вызвав эту функцию без аргументов, и каждый может быть установлен независимо, используя ключевые слова или в порядке (n, delay).
Profile.fetchФункция
fetch(;include_meta = true) -> data
Возвращает копию буфера обратных трассировок профиля. Обратите внимание, что значения в data имеют смысл только на этой машине в текущей сессии, потому что зависят от точных используемых физических адресов памяти при JIT-компиляции. Эта функция предназначена в основном для внутреннего использования; retrieve может быть лучшим выбором для большинства пользователей. По умолчанию включаются метаданные, такие как threadid и taskid. Установите include_meta в false для удаления метаданных.
Profile.retrieveФункция
retrieve(; kwargs...) -> data, lidict
«Экспортирует» результаты профилирования в переносимом формате, возвращая набор всех обратных трассировок (data) и словарь, который сопоставляет (специфичные для сессии) указатели инструкций в data со значениями LineInfo, хранящими имя файла, имя функции и номер строки. Эта функция позволяет сохранять результаты профилирования для последующего анализа.
Profile.callersФункция
callers(funcname, [data, lidict], [filename=<filename>], [linerange=<start:stop>]) -> Vector{Tuple{count, lineinfo}}
Учитывая предыдущую сессию профилирования, определите, кто вызвал определенную функцию. Указание имени файла (и необязательно диапазона номеров строк, в которых определена функция) позволяет уточнить перегруженный метод. Возвращаемое значение – вектор, содержащий количество вызовов и информацию о строке вызывающей функции. Необязательно можно предоставить обратную трассировку data полученную из retrieve; в противном случае используется текущий внутренний буфер профиля.
Profile.clear_malloc_dataФункция
clear_malloc_data()
Очищает любые сохраненные данные об аллокации памяти при запуске julia с --track-allocation. Выполните команды, которые вы хотите протестировать (чтобы принудительно выполнить JIT-компиляцию), затем вызовите clear_malloc_data. Затем снова выполните свои команды, выйдите из Julia и просмотрите полученные *.mem файлы.
Profile.get_peek_durationФункция
get_peek_duration()
Получить продолжительность в секундах «просмотра» профиля, вызванного SIGINFO или SIGUSR1, в зависимости от платформы.
Profile.set_peek_durationФункция
set_peek_duration(t::Float64)
Установить продолжительность в секундах «просмотра» профиля, вызываемого SIGINFO или SIGUSR1, в зависимости от платформы.
Профилирование памяти
Profile.Allocs.@profileМакрос
Profile.Allocs.@profile [sample_rate=0.1] expr
Профилировать выделения, которые происходят во время expr, возвращая как результат, так и структуру AllocResults.
Частота 1.0 запишет все; 0.0 — ничего.
julia> Profile.Allocs.@profile sample_rate=0.01 peakflops()
1.03733270279065e11
julia> results = Profile.Allocs.fetch()
julia> last(sort(results.allocs, by=x->x.size))
Profile.Allocs.Alloc(Vector{Any}, Base.StackTraces.StackFrame[_new_array_ at array.c:127, ...], 5576)
Дополнительную информацию можно найти в учебнике по профилированию в документации Julia.
В более старых версиях Julia не удавалось захватывать типы во всех случаях. В более старых версиях Julia, если вы видите выделение типа Profile.Allocs.UnknownType, это означает, что профайлер не знает, какой тип объекта был выделен. Это, главным образом, происходило, когда выделение поступало из сгенерированного кода, созданного компилятором. Дополнительную информацию см. в вопросе #43688.
Начиная с Julia 1.11, все выделения должны иметь указанный тип.
Профилировщик выделений был добавлен в Julia 1.8.
Методы в Profile.Allocs не экспортируются и должны вызываться, например, как Profile.Allocs.fetch().
Profile.Allocs.clearФункция
Profile.Allocs.clear()
Очистить все ранее профилированные данные об аллокации из памяти.
Profile.Allocs.printФункция
Profile.Allocs.print([io::IO = stdout,] [data::AllocResults = fetch()]; kwargs...)
Выводит результаты профилирования в io (по умолчанию, stdout). Если вы не предоставите вектор data, будет использоваться внутренний буфер накопленных стековых следов.
См. Profile.print для объяснения допустимых ключевых аргументов.
Profile.Allocs.fetchФункция
Profile.Allocs.fetch()
Извлечь записанные аллокации и декодировать их в объекты Julia, которые можно проанализировать.
Profile.Allocs.startФункция
Profile.Allocs.start(sample_rate::Real)
Начать запись аллокаций с заданной частотой выборки. Частота выборки 1.0 запишет все; 0.0 — ничего не запишет.
Profile.Allocs.stopФункция
Profile.Allocs.stop()
Остановить запись аллокаций.
Снимки кучи
Profile.take_heap_snapshotФункция
Profile.take_heap_snapshot(filepath::String, all_one::Bool=false, streaming=false) Profile.take_heap_snapshot(all_one::Bool=false; dir::String, streaming=false)
Записать снимок кучи в формате JSON, ожидаемом просмотрщиком снимков кучи Chrome Devtools (.heapsnapshot расширение), в файл ($pid_$timestamp.heapsnapshot) в текущем каталоге по умолчанию (или в tempdir, если текущий каталог недоступен для записи), или в dir, или в указанный полный путь к файлу, или в поток ввода-вывода.
Если all_one истинно, то размер каждого объекта указывается как единица, чтобы их можно было легко подсчитать. В противном случае, указывается фактический размер.
Если all_one истинно, мы выведем данные снимка в четыре файла, используя filepath в качестве префикса, чтобы избежать необходимости удерживать весь снимок в памяти. Этот параметр следует использовать в любой ситуации, когда у вас ограничена память. Эти файлы затем можно собрать, вызвав Profile.HeapSnapshot.assemble_snapshot(), что можно сделать автономно.
ПРИМЕЧАНИЕ. Мы настоятельно рекомендуем установить streaming=true по соображениям производительности. Восстановление снимка из частей требует удержания всего снимка в памяти, поэтому, если снимок большой, у вас может не хватить памяти при его обработке. С потоковой передачей вы можете восстановить снимок автономно после завершения вашей рабочей нагрузки. Если вы попытаетесь собрать снимок со значением streaming=false (по умолчанию, для обратной совместимости), и ваш процесс будет завершен, обратите внимание, что это всегда сохранит части в том же каталоге, что и ваш предоставленный filepath, так что вы все еще можете восстановить снимок позже, используя assemble_snapshot().
Методы в Profile не экспортируются и должны вызываться, например, как Profile.take_heap_snapshot().
julia> using Profile
julia> Profile.take_heap_snapshot("snapshot.heapsnapshot")
Отслеживает и записывает объекты Julia в куче. Это записывает только объекты, известные сборщику мусора Julia. Память, выделенная внешними библиотеками, не управляемыми сборщиком мусора, не будет отображаться в снимке.
Чтобы избежать исчерпания памяти во время записи снимка, мы добавили параметр потоковой передачи для потоковой передачи снимка кучи в четыре файла,
julia> using Profile
julia> Profile.take_heap_snapshot("snapshot"; streaming=true)
где «snapshot» — это путь к файлу в качестве префикса для создаваемых файлов.
После создания файлов снимка их можно собрать автономно с помощью следующей команды:
julia> using Profile
julia> Profile.HeapSnapshot.assemble_snapshot("snapshot", "snapshot.heapsnapshot")
Полученный файл снимка кучи можно загрузить в Chrome Devtools для просмотра. Дополнительную информацию см. в документации Chrome Devtools. Альтернативой для анализа снимков кучи Chromium является расширение VS Code ms-vscode.vscode-js-profile-flame.
Снимки кучи Firefox имеют другой формат, и в настоящее время Firefox не может использоваться для просмотра снимков кучи, созданных Julia.
© 2009–2024 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.11/stdlib/Profile/