Изменения

Перейти к: навигация, поиск

R:Оптимизация/Компиляция в байт-код

4080 байтов добавлено, 14:45, 28 мая 2014
м
Загрузка 2881-compilation.wiki
<!-- R:Оптимизация/Компиляция в байт-код -->
 
 
 
{{CC-BY-4.0|author=автором Артём Клевцов}}
{{Pkg-req-notice}}
В данном материале рассматривается один из способов ускорения выполнения кода путём компиляции выражений, функций и скриптов R в [http://ru.wikipedia.org/wiki/Байт-код байт-код]. Байт-код - машинно-независимый код низкого уровня, генерируемый транслятором и исполняемый интерпретатором. Большинство инструкций байт-кода эквивалентны одной или нескольким командам ассемблера. Трансляция в байт-код занимает промежуточное положение между компиляцией в машинный код и интерпретацией.
Программа на байт-коде обычно выполняется интерпретатором байт-кода (обычно он называется виртуальной машиной, поскольку подобен компьютеру). Преимущество - в портируемости, т. е. один и тот же байт-код может исполняться на разных платформах и архитектурах. То же самое преимущество дают интерпретируемые языки. Однако, поскольку байт-код обычно менее абстрактный, более компактный и более «компьютерный», чем исходный код, эффективность байт-кода обычно выше, чем чистая интерпретация исходного кода, предназначенного для правки человеком.
Рассмотрим эти опции:
* <code>optimize</code> --- определяет уровень оптимизации: принимает значения от 0 до 3 (по умолчанию 2);* <code>suppressAll</code> --- управляет сообщениями: принимает значения <code>TRUE</code> или <code>FALSE</code> (по умолчанию code>FALSE</code>);* <code>suppressUndefined</code> --- управление сообщения о неопределённых (undefined) переменных: может принимать значения <code>TRUE</code> или список имён переменных (по умолчанию ".Generic", .Method", ".Random.seed", ".self").
Получить текущее значение глобальных опций компиляции можно с помощью функции <code>getCompilerOption()</code>:
{{r-code|code=<nowiki>> getCompilerOption("optimize")#> [1] 2> getCompilerOption("suppressAll")#> [1] FALSE> getCompilerOption("suppressUndefined")#> [1] ".Generic" ".Method" ".Random.seed" ".self"</nowiki>}}
== Компиляция функций и выражений ==
 
Скомпилировать отдельно взятое выражение можно с помощью функции <code>compile()</code>.
 
{{r-code|code=<nowiki># объявляем переменные
s <- as.double(0)
x <- as.double(1:1000)
# объявляем выражения
expr <- expression(for (i in x) s <- s + i)
exprc <- compile(for (i in x) s <- s + i)
# сравниваем результат работы выражений
identical(eval(expr), eval(exprc))
#> [1] TRUE
# сравниваем производительность выражений
microbenchmark(eval(expr), eval(exprc))
#> Unit: nanoseconds
#> expr min lq median uq max neval
#> eval(expr) 191031 200750 205432 210436 291039 100
#> eval(exprc) 924 1202 1346 1628 11845 100
</nowiki>}}
Компиляция функций осуществляется с помощью функции <code>cmpfun()</code>. Возьмём пример из документации к функции <code>cmpfun()</code>, вкотором предлагается сравнить производительность различных реализаций функции <code>lapply()</code>, а также их скомпилированных версий:
for(i in seq(along = X))
rval[i] <- list(FUN(X[[i]], ...))
names(rval) <- names(X) # keep `names' !
return(rval)
}
rval[[i]] <- v
}
names(rval) <- names(X) # keep `names' !
return(rval)
}</nowiki>}}
Скомпилируем эти функции в бат-код:
{{r-code|code=<nowiki>> la1c <- cmpfun(la1)> la2c <- cmpfun(la2)> lapplyc <- compfuncmpfun(lapply)</nowiki>}} Сравним производительность этих функций: {{r-code|code=<nowiki>x <- 1:1000microbenchmark(lapply(x, is.null), la1(x, is.null), la2(x, is.null), lapplyc(x, is.null), la1c(x, is.null), la2c(x, is.null))#> Unit: microseconds#> expr min lq median uq max neval#> lapply(x, is.null) 173.1 183.2 193.4 205.2 294.4 100#> la1(x, is.null) 792.3 836.1 861.1 929.9 1807.6 100#> la2(x, is.null) 965.0 1012.1 1036.6 1085.9 2769.5 100#> lapplyc(x, is.null) 171.5 182.4 189.1 200.3 265.6 100#> la1c(x, is.null) 394.2 416.0 428.0 446.9 1217.8 100#> la2c(x, is.null) 397.6 424.5 439.1 457.2 1216.0 100</nowiki>}} Обращается на себя внимание, что скомпилированная версия функции <code>lapply()</code> не превосходит по производительности оригинальную версию. Происходит это потому, что функция <code>lapply()</code> использует написанную на C, скомпилированную функцию. Также отметим, что скомпилированные версии функций <code>la1()</code> и <code>la2()</code> показываются практически одинаковую производительность, тогда как нескомпилированные версии довольно сильно различались. Это достигается за счёт высокой оптимизации работы циклов при компиляции функций.
== Компиляция скриптов ==
Ещё одна возможность, предоставляемая пакетом {{r-package|compiler|core=true}} - это компиляция R-скриптов. Создание скомпилированных файлов осуществляется с помощью функции \texttt{cmpfile()}, а загрузка скомпилированных файлов с помощью функции <code>loadcmp()</code>. Если выходной файл не указан, то выходной файл имеет тоже имя, что и входной, но с расширением <code>.Rc</code>. Пример использования:
{{r-code|code=<nowiki>> cmpfile("script.R", "script.Rc")> loadcmp("script.Rc")</nowiki>}} == JIT-компиляция == Помимо компиляции отдельных функций и выражений, пакет {{r-package|compiler|core=true}} предоставляет возможность [http://ru.wikipedia.org/wiki/JIT-компиляция JIT-компиляции] (JIT - just-in-time) или компиляции «на лету», т.е. во время непосредственного выполнения кода. Переключение режима осуществляется с помощью функции <code>enableJIT()</code>. Эта функции имеет всего один аргумент (<code>level</code>), который может принимать одно из трёх значений: * 0 --- отключение JIT-компиляции;* 1 --- компиляции функций до их первого вызова;* 2 --- тоже что и 2 плюс компиляция всех циклов <code>for</code>, <code>while</code>, <code>repeat</code> до их вызова. Отметим, что при включении JIT-компиляции при первом запуске выполнения кода компиляция всех функций и циклов займёт некоторое время.
== Примечания ==
<references />
 
== Ссылки ==
 
* [http://homepage.stat.uiowa.edu/~luke/R/compiler/compiler.pdf A Byte Code Compiler for R]
[[Категория:R]]
[[Категория:Оптимизация кода]]

Навигация