Изменения

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

18 байтов добавлено, 03:50, 20 февраля 2014
м
Нет описания правки
В качестве примера ниже представлены шаги процесса профилирования функции, которая рассчитывает первичные описательные статистики (среднее, медиану, стандартное отклонение, минимум и максимум) по сгенерированным <math>10^6</math> нормально распределённым значениям.
{{r-code|code=<nowiki>> x <- rnorm(10^6)
</nowiki>
}}
Объявим данную функцию:
{{r-code|code=<nowiki>desc <- function(x) {
n <- length(x)
mean <- mean(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"
</nowiki>
Шаг 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
self.time self.pct total.time total.pct
При профилировании скриптов включение опции <code>line.profiling</code> проставляет номера строк в которых производился вызов, что позволяет проанализировать производительность всего кода:
{{r-code|code=<nowiki>> Rprof(tmp.log, line.profiling = TRUE)
> source("/path/scritpt.R")
> Rprof(NULL)
Также может оказаться полезной функция <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))
total.pct total.time self.pct self.time
Пакет <code>profr</code> предоставляет несколько функций для упрощения процесса профилирования, а также позволяет графически представить результаты профилирования. Результаты работы функции <code>profr</code> представляют собой таблицу, с хронологическим перечислением вызовов. Поэтому при использовании данной функции необходимо использовать однократное выполнение выражения. Вышеприведённый листинг по профилированию работы функции <code>desc()</code> будет выглядеть следующим образом:
{{r-code|code=<nowiki>> library(profr)
> prof <- profr(desc(x))
> print(prof)
Графическое представление результатов профилирования осуществляется с помощью стандартной функции <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")
</nowiki>
Для корректной работы функции <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)
mean <- mean(x)
Процедура профилирования осуществляется описанным выше способом:
{{r-code|code=<nowiki>> Rprof(tmp.log, line.profiling = TRUE)
> source("/tmp/script.R")
> Rprof(NULL)
Результаты работы функции <code>proftable()</code> представлены ниже.
{{r-code|code=<nowiki>> proftable(tmp.log)
PctTime Call
54.464 1#4 > median > median.default > mean > sort > sort.default > sort.int
Иногда, чтобы выяснить какой функции принадлежит тот или иной вызов, приходится анализировать содержимое функций. Чтобы увидеть содержимое функции, можно воспользоваться функцией <code>getAnywhere()</code>. Например:
{{r-code|code=<nowiki>getAnywhere(median.default)
A single object matching ‘median.default’ was found
It was found in the following places
С учётом выявленных «узких» мест нашей функции и проанализировав исходный код функций, мы можем оптимизировать нашу исходную функцию для достижения максимальной производительности. Наш вариант оптимизированной функции будет выглядеть следюущим образом:
{{r-code|code=<nowiki>desc <- function(x) {
n <- length(x)
mean <- sum(x) / n