Профилирование
Применение @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
или передайте процессу Julia сигналSIGINFO
, т. е.% kill -INFO $julia_pid
. -
В Linux: передайте процессу Julia сигнал
SIGUSR1
, т. е.% kill -USR1 $julia_pid
. -
В Windows: в настоящее время не поддерживается.
Сначала отображается одна трассировка стека на момент передачи сигнала, затем собирается профиль за период в одну секунду, а затем выдается отчет о профилировании в следующей точке выхода. Если код не содержит точек выхода, например представляет собой сплошной цикл, то может использоваться момент завершения задачи.
Вы также можете присвоить переменной среды JULIA_PROFILE_PEEK_HEAP_SNAPSHOT
значение 1
, чтобы автоматически получить моментальный снимок кучи.
julia> foo()
##== Пользователь отправляет активирующий сигнал во время выполнения foo ==##
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
— Macro
@profile
Макрос @profile <expression>
выполняет ваше выражение, периодически записывая обратные трассировки. Они добавляются во внутренний буфер обратных трассировок.
Методы в Profile
не экспортируются, и их необходимо вызывать, например как Profile.print()
.
#
Profile.print
— Function
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
: ограничивает формат:tree
глубинойmaxdepth
. -
sortedby
: контролирует упорядочение в формате: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}}
: указывает задачи, моментальные снимки которых следует включить в отчет. Обратите внимание, что это не определяет, из каких задач осуществляется выборка.
print([io::IO = stdout,] data::Vector, lidict::LineInfoDict; kwargs...)
Выводит результаты профилирования в поток ввода-вывода (io
). Этот вариант используется для анализа результатов, экспортированных предыдущим вызовом retrieve
. Необходимо указать вектор обратных трассировок data
и словарь строк данных lidict
.
Пояснение допустимых именованных аргументов см. в описании Profile.print([io], data)
.
#
Profile.init
— Function
init(; n::Integer, delay::Real)
Настраивает задержку (delay
) между обратными трассировками (в секундах), а также число указателей инструкций n
, которое можно хранить для каждого потока. Каждый указатель инструкций соответствует одной строке кода. Как правило, обратные трассировки состоят из длинного списка таких указателей. Каждая трассировка использует шесть позиций указателей для хранения метаданных и двух конечных маркеров NULL. Для получения текущих настроек можно вызывать эту строку без аргументов. Каждый аргумент можно задавать независимо с помощью именованных аргументов или в порядке (n, delay)
.
#
Profile.fetch
— Function
fetch(;include_meta = true) -> data
Возвращает копию буфера обратных трассировок профилей. Обратите внимание, что значения в data
имеют смысл только на текущем компьютере в текущем сеансе, так как они зависят от конкретных адресов памяти, используемых при JIT-компиляции. Эта функция предназначена в основном для внутреннего использования. Для большинства пользователей более оптимальной будет retrieve
. По умолчанию функция включает метаданные, такие как идентификатор потока (threadid) и задачи (taskid). Чтобы отбросить метаданные, задайте для include_meta
значение false
.
#
Profile.retrieve
— Function
retrieve(; kwargs...) -> data, lidict
«Экспортирует» результаты профилирования в портируемом формате, возвращая набор всех обратных трассировок (data
) и словарь, сопоставляющий указатели инструкций (относящиеся к сеансу) в data
со значениями LineInfo
, хранящими имя файла, имя функции и номер строки. Эта функция позволяет сохранить результаты профилирования для анализа в будущем.
#
Profile.callers
— Function
callers(funcname, [data, lidict], [filename=<filename>], [linerange=<start:stop>]) -> Vector{Tuple{count, lineinfo}}
Принимает на вход предыдущий запуск профилирования и определяет, какой объект вызывал ту или иную функцию. Если указать имя файла (и, необязательно, диапазон номеров строк, в которых определена функция), то можно устранить неоднозначность перегружаемого метода. Возвращаемым значением является вектор, содержащий счетчик количества вызовов и строку информации о вызывающем объекте. При необходимости можно предоставить обратную трассировку data
, полученную от retrieve
. В противном случае используется текущий внутренний буфер профилирования.
#
Profile.clear_malloc_data
— Function
clear_malloc_data()
Очищает хранимые данные выделения памяти при использовании Julia с --track-allocation
. Выполните команды, которые хотите протестировать (чтобы принудительно осуществить JIT-компиляцию), после чего вызовите clear_malloc_data
. Затем выполните команды повторно, выйдите из Julia и проанализируйте результирующие файлы *.mem
.
#
Profile.get_peek_duration
— Function
get_peek_duration()
Получает длительность профиля peek (в секундах), активируемого с помощью SIGINFO
или SIGUSR1
в зависимости от платформы.
#
Profile.set_peek_duration
— Function
set_peek_duration(t::Float64)
Задает длительность профиля peek (в секундах), активируемого с помощью SIGINFO
или SIGUSR1
в зависимости от платформы.
Профилирование памяти
#
Profile.Allocs.@profile
— Macro
Profile.Allocs.@profile [sample_rate=0.0001] 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)
Лучшим способом визуализации на данный момент является пакет PProf.jl, который вызывается с помощью PProf.Allocs.pprof
.
Текущая реализация профилировщика выделения записывает не все типы выделения ресурсов. Случаи выделения ресурсов, для которых профилировщик не смог записать тип, представляются с типом |
Совместимость: Julia 1.8
Профилировщик выделения ресурсов был добавлен в версии Julia 1.8. |
Методы в Profile.Allocs
не экспортируются, и их необходимо вызывать, например как Profile.Allocs.fetch()
.
#
Profile.Allocs.clear
— Function
Profile.Allocs.clear()
Очищает из памяти всю ранее записанную информацию профилирования выделения ресурсов.
#
Profile.Allocs.fetch
— Function
Profile.Allocs.fetch()
Получает записанное выделение ресурсов и декодирует его в объекты Julia, пригодные для анализа.
#
Profile.Allocs.start
— Function
Profile.Allocs.start(sample_rate::Real)
Начинает запуск выделения ресурсов с указанной частотой выборки. При частоте выборки 1.0 будут записываться все случаи, а при 0.0 ничего не записывается.
Моментальные снимки кучи
#
Profile.take_heap_snapshot
— Function
Profile.take_heap_snapshot(io::IOStream, all_one::Bool=false)
Profile.take_heap_snapshot(filepath::String, all_one::Bool=false)
Profile.take_heap_snapshot(all_one::Bool=false)
Записывает моментальный снимок кучи в формате JSON, используемом средством просмотра моментальных снимков кучи в составе инструментов разработчика Chrome (расширение .heapsnapshot), в файл ($pid_$timestamp.heapsnapshot
) в текущем каталоге, по указанному пути или в поток ввода-вывода. Если all_one
имеет значение true, для каждого объекта указывается единичный размер, что упрощает подсчет объектов. В противном случае указывается фактический размер.
Методы в Profile
не экспортируются, и их необходимо вызывать, например как Profile.take_heap_snapshot()
.
julia> using Profile
julia> Profile.take_heap_snapshot("snapshot.heapsnapshot")
Отслеживает и регистрирует объекты Julia в куче. Регистрируются только объекты, известные сборщику мусора Julia. Память, выделенная внешними библиотеками, которыми не управляет сборщик мусора, не включается в моментальный снимок.
Полученный файл с моментальным снимком кучи можно передать в инструменты разработчика Chrome для просмотра. Дополнительные сведения см. в документации к инструментам разработчика Chrome.