Подтвердить что ты не робот

Использование памяти монитора в R

Можно ли контролировать объем памяти, который используется или был использован R для вызова функции? Например, у меня есть произвольная функция, например:

smallest.sv <- function(){
  A <- matrix(rnorm(1e6), 1e3);
  mysvd <- svd(A);
  return(tail(mysvd$d, 1));
}

Запуск функции просто возвращает скаляр, но для вычисления функции используется много памяти. Теперь мне нужно выполнить бенчмаркинг производительности. Время обработки прост:

system.time(x <- smallest.sv())

Однако я также хотел бы знать, сколько памяти было необходимо для этого вызова, без изменения функции (она должна работать для произвольных функций). Есть ли способ сделать это?

Изменить: немного уточнить. Меня больше всего интересует верхняя граница памяти, которая использовалась во время вызова функции, т.е. Сколько физической памяти требуется для обработки вызова функции. Во многих случаях это значительно меньше, чем общая сумма выделенной памяти, о которой я думаю.

4b9b3361

Ответ 1

R обеспечивает поддержку профилирования памяти, см. Раздел 3.3 Руководства по написанию расширений R:

3.3 Профилирование R-кода для использования памяти

Измерение использования памяти в коде R полезно, когда код занимает больше памяти, чем удобно, или когда распределение памяти и копирование объектов ответственны за медленный код. Существует три способа профилирования использования памяти с течением времени в коде R. Все три требуют, чтобы R был скомпилирован с "--enable-memory-profiling", который не используется по умолчанию, но в настоящее время используется для двоичных дистрибутивов Mac OS X и Windows. Все может вводить в заблуждение по разным причинам.

При понимании профилей памяти полезно знать немного больше о распределении памяти R. Просмотр результатов 'gc()' показывает разделение памяти на 'Vcells', используемые для хранения содержимого векторов, и 'Ncells', используемые для хранения всего остального, включая все административные издержки для векторов, такие как информация о типе и длине. Фактически векторное содержимое разделено на два пула. Память для маленьких векторов (по умолчанию 128 байтов или меньше) получается большими порциями и затем распределяется по R; память для больших векторов получается непосредственно из операционной системы.

а затем предоставляет еще три раздела.

Ответ 2

Один из вариантов - использовать Rprof. Простой подход заключается в следующем:

Rprof(tf <- "rprof.log", memory.profiling=TRUE)

[your code]

Rprof(NULL)
summaryRprof(tf)

Это даст вам некоторую информацию об использовании памяти.

Ответ 3

Rprof, Rprofmem, profmem::profmem, bench::mark или profvis::profvis могут показывать использование памяти.

smallest.sv <- function(seed=0){
    set.seed(seed)
    A <- matrix(rnorm(1e6), 1e3);
    mysvd <- svd(A);
    return(tail(mysvd$d, 1));
}

#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

Чтобы получить верхнюю границу памяти, которая используется во время обработки функции, я думаю, что вы должны использовать такой инструмент, как Rprof (и надеюсь, что вы достигнете пика), поскольку Rprofmem показывает только память, которая была накоплена, и не учитывает память, которая была освобождена во время исполнения.

Для увеличения вероятности вы можете выбрать короткий интервал времени и/или повторить процедуру.

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

Использование gctorture может повлиять на результат.

gctorture(on = TRUE)
gc()
Rprof("Rprof.out", memory.profiling=TRUE)
x <- smallest.sv()
Rprof(NULL)
gctorture(on = FALSE)
max(summaryRprof("Rprof.out", memory="both")$by.total$mem.total)
#76.4

Здесь похоже, что gctorture замедляет время выполнения и помогает достичь пика.

Ответ 4

Вы можете получить верхнюю границу памяти, которая используется во время обработки функции и команд с помощью 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 не включен.