Мониторинг использования памяти в R
Можно ли контролировать объем памяти, который используется или использовался R для вызова функции? Например, у меня есть произвольная функция, например:
smallest.sv <- function(){
A <- matrix(rnorm(1e6), 1e3);
mysvd <- svd(A);
return(tail(mysvd$d, 1));
}
Запуск функции просто возвращает скаляр, но для ее вычисления использовалось много памяти. Теперь мне нужно сделать тест производительности. Время обработки легко:
system.time(x <- smallest.sv())
Однако я также хотел бы знать, сколько памяти было необходимо для этого вызова, без изменения функции (она должна работать для произвольных функций). Есть какой-либо способ сделать это?
Изменить: уточнить немного. Меня больше всего интересует верхняя граница памяти, которая использовалась во время вызова функции, то есть, сколько физической памяти требуется для обработки вызова функции. Я думаю, что во многих случаях это значительно меньше, чем общий объем выделенной памяти.
4 ответа
R обеспечивает поддержку профилирования памяти, см. Раздел 3.3 Руководства по написанию расширений R:
3.3 Профилирование R-кода для использования памяти
Измерение использования памяти в коде R полезно, когда код занимает больше памяти, чем удобно, или когда распределение памяти и копирование объектов ответственны за медленный код. Существует три способа профилирования использования памяти с течением времени в коде R. Все три требуют, чтобы R был скомпилирован с `--enable-memory-profiling', который не используется по умолчанию, но в настоящее время используется для двоичных дистрибутивов Mac OS X и Windows. Все может вводить в заблуждение по разным причинам.
При понимании профилей памяти полезно узнать немного больше о распределении памяти R. Просмотр результатов `gc()'показывает разделение памяти на`Vcells', используемое для хранения содержимого векторов, и `Ncells', используемый для хранения всего остального, включая все административные издержки для векторов, такие как информация о типе и длине. Фактически векторное содержимое разделено на два пула. Память для маленьких векторов (по умолчанию 128 байт или меньше) получается большими порциями, а затем распределяется по R; память для больших векторов получается непосредственно из операционной системы.
а затем предоставляет еще три раздела.
Одним из вариантов является использование Rprof
, Простой подход заключается в следующем:
Rprof(tf <- "rprof.log", memory.profiling=TRUE)
[your code]
Rprof(NULL)
summaryRprof(tf)
Это даст вам некоторую информацию об использовании памяти.
Вы можете получить верхнюю границу памяти, которая используется во время обработки функции и команд, с помощьюgc
:
smallest.sv <- function(){
A <- matrix(rnorm(1e6), 1e3);
mysvd <- svd(A);
return(tail(mysvd$d, 1));
}
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
x <- smallest.sv()
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#62 MB
rm(x)
На эту верхнюю границу влияет сборка мусора, поэтому включение gctorture
даст нижнюю верхнюю границу:
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
gctorture(on = TRUE)
x <- smallest.sv()
gctorture(on = FALSE)
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#53.7 MB
Другие инструменты, такие как Rprof
, Rprofmem
, profmem::profmem
, bench::mark
или profvis::profvis
может также показать использование памяти.
#Using Rprof (Enable profiling is a compile-time option: ./configure --enable-R-profiling)
gc()
Rprof("Rprof.out", memory.profiling=TRUE)
x <- smallest.sv()
Rprof(NULL)
max(summaryRprof("Rprof.out", memory="both")$by.total$mem.total)
#45.9
#Here at defined intervals the status is checked and so the result depends on if you hit the peak
#Using Rprofmem (Enable momory profiling is a compile-time option: ./configure --enable-memory-profiling)
Rprofmem("Rprofmem.out"); x <- smallest.sv(); Rprofmem(NULL) #Wen first run, there is much more in the log file
gc()
Rprofmem("Rprofmem.out")
x <- smallest.sv()
Rprofmem(NULL)
sum(as.numeric(read.table("Rprofmem.out", comment.char = ":")[,1]), na.rm=TRUE)
#88101752
#Writes out them memory amount when it is allocated
library(profmem) #uses utils::Rprofmem
gc()
total(profmem(x <- smallest.sv()))
#88101752
library(bench) #uses utils::Rprofmem
gc()
mark(x <- smallest.sv())[,"mem_alloc"]
#84MB
#Warning message:
#Some expressions had a GC in every iteration; so filtering is disabled.
library(profvis) #uses utils::Rprof
gc()
profvis(x <- smallest.sv())
#opens a browser window where you can read under Memory -23.0 | 45.9
Rprofmem
показывает память, которая была выделена кумулятивно, и не учитывает память, которая была освобождена во время выполнения. Чтобы увеличить вероятностьRprof
для достижения пика вы можете выбрать короткий интервал времени или / и повторить процедуру.
max(replicate(10, {
gc()
Rprof("Rprof.out", memory.profiling=TRUE, interval = runif(1,.005,0.02))
x <- smallest.sv()
Rprof(NULL)
max(summaryRprof("Rprof.out", memory="both")$by.total$mem.total)
}))
#76.4
Здесь я ценю более высокую, чем получаю от gc
, что демонстрирует, что на использование памяти влияет сборка мусора, и верхняя граница памяти, которая используется во время обработки функции, может варьироваться от вызова к вызову, покаgctorture
не включается.
Вы можете получить время обработки, а также пиковую память с
PeakRAM
:
library(peakRAM)
peakRAM(smallest.sv())
Function_Call Elapsed_Time_sec Total_RAM_Used_MiB Peak_RAM_Used_MiB
1 smallest.sv() 3.64 0 61.1