Профилирование
Профилирование процессора
Существует два основных подхода к профилированию кода 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 для автоматической записи снимка кучи heap snapshot.
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}}– Укажите, из снимков каких задач включать информацию в отчёт. Обратите внимание, что это не управляет тем, в каких задачах собираются выборки.
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.
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.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.
Текущая реализация профилировщика выделений не сохраняет типы для всех выделений. Выделения, типы которых профилировщик не смог определить, отображаются как имеющие тип Profile.Allocs.UnknownType.
Дополнительную информацию об отсутствующих типах и планах по улучшению можно найти здесь: https://github.com/JuliaLang/julia/issues/43688.
Профилировщик выделений был добавлен в Julia 1.8.
Методы в Profile.Allocs не экспортированы и должны вызываться, например, как Profile.Allocs.fetch()
Profile.Allocs.clearФункция
Profile.Allocs.clear()
Очистить все ранее профилированные данные об выделениях из памяти.
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(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 Devtools (.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 Devtools для просмотра. Для получения дополнительной информации см. документацию Chrome Devtools.
© 2009–2023 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.9/stdlib/Profile/