Изменения

R:Профилирование кода

18 байтов убрано, 14:01, 19 февраля 2014
м
Нет описания правки
В качестве примера ниже представлены шаги процесса профилирования функции, которая рассчитывает первичные описательные статистики (среднее, медиану, стандартное отклонение, минимум и максимум) по сгенерированным <math>10^6</math> нормально распределённым значениям.
{{r-code|code=<nowiki>
> x <- rnorm(10^6)
</nowiki>
Объявим данную функцию:
{{r-code|code=<nowiki>
<nowiki>Вставьте сюда текст, который не нужно форматировать</nowiki>
desc <- function(x) {
Шаг 1. Создание временного файла для записи лога профилирования (необязательно):
{{r-code|code=<nowiki>
> tmp.log <- tempfile(pattern = "prof-", fileext = ".log")
</nowiki>
Посмотреть путь и имя временного файла лога можно, введя имя переменной <code>tmp.log</code>:
{{r-code|code=<nowiki>
> tmp.log
[1] "/tmp/RtmpAvhCfO/prof-23b61d761805.log"
Шаг 2. Собственно процедура профилирования:
{{r-code|code=<nowiki>
# Включаем профилирование
> Rprof(tmp.log)
Шаг 3. Вывод результатов:
{{r-code|code=<nowiki>
> summaryRprof(tmp.log)
</nowiki>
Шаг 4. Удаляем временный файл:
{{r-code|code=<nowiki>
> unlink(tmp.log)
</nowiki>
Рассмотрим результаты профилирования функции <code>desc()</code>:
{{r-code|code=<nowiki>
> summaryRprof(tmp.log)
$by.self
При профилировании скриптов включение опции <code>line.profiling</code> проставляет номера строк в которых производился вызов, что позволяет проанализировать производительность всего кода:
{{r-code|code=<nowiki>
> Rprof(tmp.log, line.profiling = TRUE)
> source("/path/scritpt.R")
Также может оказаться полезной функция <code>flatProfile()</code> из пакета <code>proftools</code>. Данная функция выводит таблицу, сходную с таблицей «by.total» возвращаемую функцией <code>summaryRprof()</code>, в одну и сортирует их по общему времени выполнения в процентах или по времени выполнения функции в процентах, если указать <code>byTotal = FALSE</code>:
{{r-code|code=<nowiki>
> library(proftools)
> flatProfile(readProfileData(tmp.log))
Пакет <code>profr</code> предоставляет несколько функций для упрощения процесса профилирования, а также позволяет графически представить результаты профилирования. Результаты работы функции <code>profr</code> представляют собой таблицу, с хронологическим перечислением вызовов. Поэтому при использовании данной функции необходимо использовать однократное выполнение выражения. Вышеприведённый листинг по профилированию работы функции <code>desc()</code> будет выглядеть следующим образом:
{{r-code|code=<nowiki>
> library(profr)
> prof <- profr(desc(x))
Графическое представление результатов профилирования осуществляется с помощью стандартной функции <code>plot()</code> или <code>ggplot()</code>:
{{r-code|code=<nowiki>
> ggplot(prof)
</nowiki>
Мы переработали данную функцию, удалив зависимость от пакета <code>plyr</code> и существенно ускорив её. Код модифицированного варианта доступен в [https://bitbucket.org/psylab/r-scripts/src/master/proftable.R git-репозитории]. Импортировать данный скрипт можно с помощью функции <code>source_url()</code>, которая входит в состав пакета <code>devtools</code><ref>Штатная функция <code>source()</code> из пакета <code>base</code> не поддерживает загрузку файлов по протоколу https.</ref>:
{{r-code|code=<nowiki>
> library(devtools)
> source_url("https://bitbucket.org/psylab/r-scripts/raw/master/proftable.R")
Для корректной работы функции <code>proftable()</code> необходимо провести профилирование с включённой опцией <code>line.profiling</code>. Для удобства последующего анализа результатов можно сохранить функцию и её вызов в файл скрипта и вызывать его с помощью функции <code>source()</code>. Скрипт для профилирования имеет следующее содержимое:
{{file|lang=r|subtitle=/tmp/script.R|code=<nowiki>
desc <- function(x) {
n <- length(x)
Процедура профилирования осуществляется описанным выше способом:
{{r-code|code=<nowiki>
> Rprof(tmp.log, line.profiling = TRUE)
> source("/tmp/script.R")
Результаты работы функции <code>proftable()</code> представлены ниже.
{{r-code|code=<nowiki>
> proftable(tmp.log)
PctTime Call
Иногда, чтобы выяснить какой функции принадлежит тот или иной вызов, приходится анализировать содержимое функций. Чтобы увидеть содержимое функции, можно воспользоваться функцией <code>getAnywhere()</code>. Например:
{{r-code|code=<nowiki>
getAnywhere(median.default)
A single object matching ‘median.default’ was found
С учётом выявленных «узких» мест нашей функции и проанализировав исходный код функций, мы можем оптимизировать нашу исходную функцию для достижения максимальной производительности. Наш вариант оптимизированной функции будет выглядеть следюущим образом:
{{r-code|code=<nowiki>
desc <- function(x) {
n <- length(x)