2016-08-19 3 views
0

Когда я тестирую небольшие куски кода/функции, написанные на RcppArmadillo, я вижу иногда невероятное (55x против R для вложенных циклов в простых операциях) до скромного (1.3x против R в течение длительного времени функции). Впечатленный этим, я решил перевести около 400 строк кода, чтобы создать одну C++-функцию (с некоторыми небольшими соседними функциями C++), чтобы заменить интенсивно вычислительный массив моего приложения R.Rcpp/RcppArmadillo C++/R баланс для производительности

Старые результаты: Код RcppArmadillo работает ~ 3 раза медленнее, чем исходный R (обновление - возможно, плохой бенчмарк - работает над ним). Гибридный RcppArmadillo & R варианта коды работает ~ 1.10 раз быстрее, чем R.

Обновления/Уроки: C++ интенсивного код выполняется ~ 6x быстрее, чем гибридный код R & C++. Для всех прохожих ошибки, которые я сделал, следующие:

  • Я не учитывал переменную экземпляра в своем R-контролере (несправедливое сравнение).
  • Неверные вычисления внутри вложенного цикла C++. В варианте R они были вне указанной петли (включая большой FFT и т. Д.). Человеческая ошибка.
  • Передано большое количество параметров функции (большие векторы, матрицы, с литьем и т. Д.). Решил это, портируя больше кода.
  • Я не работал с памятью эффективно. Вместо того, чтобы просто использовать их, делались дополнительные копии. Эти копии способствовали читабельности, но, вероятно, повредили производительность. Легко исправить.
  • Использование глобальных переменных для уменьшения функции, проходящей над головой, и удаления нескольких крупных временных векторов из некоторых вычислений (векторный размер: 2^15).

Edit (извините за разрывами с первым комментарием на этот пост) Старые вопросы:

  • Является ли глобальная переменная экземпляра/предварительное распределение памяти рекомендуется в кодовом пространстве RcppArmadillo, чтобы спасти от многих переменных деклараций в корпусе функции/сборщик мусора? Или Rcpp обрабатывает их так же своевременно, как R?
  • Правильно ли я полагаю, что Rcpp теряет определенную производительность из-за сопряжения с R (защитные переменные, сбор мусора и т. Д.)? Если да, где я могу найти код (имя файла)/документацию, где эти операции обрабатываются, чтобы я мог научиться работать с ним лучше.

Любой практический совет оценен. Прошу прощения за неопределенный вопрос: я новичок в SO, новичок в пакете RcppArmadillo, и не написал C++ через 10 лет.

+3

Это очень много (читайте: слишком много) вопросов для одного вопроса. Сделать это быстро: (1) нет; (2) нет; (3) нет; (4) да - все это; но он не медленнее, чем сам R для любого из них; он * медленнее, когда вам нужно преобразовать/скопировать между представлениями объектов R и C++; (5) да, если вы не сделаете что-то не так. Вопрос в том, являются ли эти выгоды достаточно большими, чтобы стоить того. Вопрос, на который нельзя ответить в целом. –

+0

Спасибо Konrad, я думаю, это то, что мне нужно было знать. Я попытаюсь снизить параметры, переданные функции Rcpp, и посмотреть, как это происходит. Если все остальное не работает, я полагаю, что моя программа будет близка к полностью переносится на C++, для чего этот пакет (RcppArmadillo) мог бы помочь в этом. – caseyk

+1

FWIW Я согласен с «слишком много вопросов» Конрада. Я не согласен с тем, что «будет ли это медленнее». Ответ заключается в том, что идентификационный код на идентичном аппарате, построенный под идентичными переключателями **, должен, конечно, выполняться одинаково под всеми метриками. Компьютеры детерминированы. Если ваш «рабочий код» ниже - это чистый код Armadillo, то будет то же самое, независимо от того, вы или нет интерфейс от R. Который не очень медленнее, чем сопряжение вручную через типы «SEXP», как мы показали в тестах. –

ответ

2

Код RcppArmadillo работает ~ 3x медленнее, чем родной R. Гибридный RcppArmadillo & R вариант кода работает ~ 1,10 раза быстрее, чем R.

Вы должны копировать много. Это просто не правдоподобно. Может быть, время для профайла вашего кода?

Принимаем любой размещен пример. Возможно, из галереи Rcpp, которая имеет несколько сообщений. Возможно, из 250 (!!) пакетов CRAN с использованием RcppArmadillo. Начните с чего-то простого, и время это.

Вы должны увидеть коэффициент ~ 50x для циклов, преобразованных из R в C++. Вы должны увидеть что-то близкое, возможно, в 1,5 раза быстрее для чисто векторизованного кода (поскольку R, как правило, делает больше ошибок, проверяя этот код, который мы пишем в небольших расширениях).

Edit: Вот тривиальных тест, показывающий, как тривиальное это установить один. Вы действительно можете (и должны!) Время все части, которые вы подозреваете, неэффективны. Мы все делаем ошибки, как в дизайне, так и в исполнении. Хорошо, что у вас есть как инструменты , так и множество размещенных примеров, которые помогут вам.

R> Rfunc <- function(N) { s <- 0; for (i in 1:N) for (j in 1:N) s <- s+1; s } 
R> Rfunc(10) 
[1] 100 
R> 
R> library(Rcpp) 
R> cppFunction("double Cppfunc(int N) { double s=0; for (int i=0; i<N; i++) for (int j=0; j<N; j++) s++; return(s); }") 
R> Cppfunc(10) 
[1] 100 
R> 
R> library(rbenchmark) 
R> N <- 1000 
R> benchmark(Rfunc(N), Cppfunc(N), order="relative")[,1:4] 
     test replications elapsed relative 
2 Cppfunc(N)   100 0.073 1.000 
1 Rfunc(N)   100 12.596 172.548 
R> 
+0

Я не совсем уверен, что сказать о том, правдоподобно или нет. Возможно, мой тест ошибочен, поскольку мне пришлось использовать proc.time() из-за того, насколько массивным является код. В настоящее время я работаю над переносом большего количества кода, поэтому не существует 20 некоторых нечетных параметров (cx_vec, cx_mat, cx_cubes и т. Д.). Я обновлю свое оригинальное сообщение, когда узнаю больше ... – caseyk

+0

Посмотрите мои изменения прямо сейчас. Попробуйте разложить на кусочки, а затем время и проверить эти штуки. –

+0

Спасибо Дирк. Некоторые из моих ошибок: огромный вызов функции over-head, цикл копировал слишком много переменных внутри C++, поскольку, поскольку вариант R был векторизован, я упустил вычисление внутри вложенного цикла, что в варианте R было вне вложенного цикла , Мой контрольный показатель был ошибочным, поскольку он не создавал экземпляр всех переменных, которые я использовал, что является несправедливым сравнением. Я начинаю ценить эти библиотеки Rcpp. Есть немного кривая обучения, но производительность стоит того. Теперь он работает ~ 6 раз быстрее, чем гибриды R и C++. Извините, мой вопрос был подпарам. – caseyk

Смежные вопросы