Интерпретация вывода профилирования памяти `Rprof` - PullRequest
2 голосов
/ 05 октября 2019

Я пытаюсь использовать профилирование, чтобы увидеть, какая часть моего кода отвечает за максимальное использование 3 ГБ памяти (как сообщает статистика gc() по максимально используемой памяти, см. Здесь ). Я запускаю профилирование памяти следующим образом:

Rprof(line.profiling = TRUE, memory.profiling = TRUE)
graf(...) # ... here I run the profiled code
Rprof(NULL)
summaryRprof(lines = "both", memory = "both")

И вывод следующий:

$by.total
                       total.time total.pct mem.total self.time self.pct
"graf"                     299.12     99.69   50814.4      0.02     0.01
#2                         299.12     99.69   50814.4      0.00     0.00
"graf.fit.laplace"         299.06     99.67   50787.2      0.00     0.00
"doTryCatch"               103.42     34.47    4339.2      0.00     0.00
"chol"                     103.42     34.47    4339.2      0.00     0.00
"tryCatch"                 103.42     34.47    4339.2      0.00     0.00
"tryCatchList"             103.42     34.47    4339.2      0.00     0.00
"tryCatchOne"              103.42     34.47    4339.2      0.00     0.00
"chol.default"             101.62     33.87    1087.0    101.62    33.87
graf.fit.laplace.R#46       85.80     28.60    3633.2      0.00     0.00
"backsolve"                 78.82     26.27    1635.2     58.40    19.46

Как мне интерпретировать mem.total? Что это такое и какова его единица? Я попытался взглянуть на документацию, а именно ?Rprof и ?summaryRprof, но, похоже, она недостаточно хорошо документирована: - /

РЕДАКТИРОВАТЬ: Здесь говорятчто Rprof "проверяет общее использование памяти R через регулярные промежутки времени". Но это не подходит к 50 ГБ, которые намного превосходят возможности моей памяти! (8 ГБ физический + 12 ГБ Pagefile сейчас).

Точно так же, как указывает Р. Йода, ?summaryRprof говорит, что с памятью = "оба" это означает "изменение общего объема памяти". Но что это такое (это общая память или изменение общей памяти), и как оно соотносится с числом 50 ГБ?

РЕДАКТИРОВАТЬ: тот же анализ, проведенный в profvis- когда я наведите курсор мыши на 50812, он покажет «Выделение памяти (МБ)» и наведет курсор на черную полосу рядом с вертикальной линией «Процент пикового выделения и освобождения памяти». Не уверен, что это значит ... Это похоже на 50 ГБ, что означает, что, возможно, это может быть сумма всех выделений (??) ... определенно не пиковое использование памяти:

enter image description here

1 Ответ

1 голос
/ 06 октября 2019

?summaryRprof говорит:

Если память = "оба" один и тот же список, но с использованием памяти в МБ в дополнение к таймингу.

Итак mem.total в МБ

С памятью = "оба" сообщается об изменении общего объема памяти (обрезается до нуля) [...]

У вас 8 ГБ ОЗУСвоп + 12 ГБ, но mem.total заявляет, что вы использовали 50 ГБ?

Поскольку это агрегированная дельта между двумя последующими пробами (снимки использования памяти, сделанные Rprof через регулярные промежутки времени: Если зондирование выполняется во время выполнения функции f Дельта использования памяти до последнего зондирования добавляется к mem.total из f).

Дельта использования памяти может быть отрицательной но я никогда не видел отрицательных mem.total значений, поэтому я предполагаю (!) только положительные значения добавляются к mem.total.

Это объясняет общее использование 50 ГБ, которое вы видите: Это необъем выделенной памяти в течение одной точки времени, но суммарная дельта памятиполное время выполнения.

Это также объясняет тот факт, что gc показывает только 3 ГБ как «максимальное использованное (МБ)» : память выделяется и освобождается / освобождается много разтак что вы не столкнетесь с нехваткой памяти, но это будет стоить много времени (перемещение большого количества данных в ОЗУ делает недействительными все кэши и, следовательно, работает медленно) поверх логики вычислений, которую применяет ЦП. ИМХО) также, кажется, скрывает тот факт, что сборщик мусора (gc) запускается в недетерминированные моменты времени для очистки освобожденной памяти.

Поскольку gc запускается ленивым (не-детерминистически) ИМХО было бы несправедливо приписывать отрицательные дельты памяти одной только что проверенной функции.

Я бы интерпретировал mem.total как mem.total.used.during.runtime, что, возможно, было бы лучшей меткой для столбца.

profvis содержит более подробную сводку об использовании памяти (как вы можете видеть на скриншоте в вашем вопросе): он также объединяет отрицательное дельtas (освобожденная память), но документация profvis также предупреждает о недостатках:

Панель кода также показывает распределение и освобождение памяти. Интерпретация этой информации может быть немного хитрой, потому что она не обязательно отражает память, выделенную и отключенную в этой строке кода. Профилировщик выборки записывает информацию о распределении памяти, которое происходит между предыдущей выборкой и текущей. Это означает, что значения выделения / освобождения в этой строке могли действительно иметь место в предыдущей строке кода.

Более подробный ответ потребует больше времени для исследования (у меня нет) - чтобы посмотретьв источник C и R - чтобы понять (воспроизвести) логику агрегирования summaryRprof на основе файлов данных, созданных Rprof

Rprof файлов данных (Rprof.out), выглядят следующим образом:

:376447:6176258:30587312:152:1#2 "test" 1#1 "test2"

Первые четыре числа (разделенные двоеточиями) означают (см. ?summaryRprof) - R_SmallVallocSize: векторная память [количество сегментов] в маленьких блоках в куче R - R_LargeVallocSize: векторная память [числоячеек] в больших блоках (из malloc) - память в узлах в куче R - количество вызовов внутренней функции duplicate во временном интервале (используется для дублирования векторов, например, в случае копирования на первое место)-записать семантику аргументов функции)

Строки представляют собой стек вызовов функций.

Только первые два числа имеют значение для вычисления текущей памятииспользование (векторов) в МБ:

TotalBuckets = R_SmallVallocSize + R_LargeVallocSize
mem.used = TotalBuckets * 8 Bytes / 1024 / 1024
# 50 MB in the above `Rprof` probe line:
# (376447 + 6176258) * 8 / 1024 / 1024

Подробнее о Vcells см. ?Memory.

Кстати: я хотел попробовать summaryRProf(memory = "stats", diff = F), чтобы получить текущую памятьрезюме, но я получаю сообщение об ошибке с 64-битным R3.4.4 в Ubuntu:

Error in tapply(seq_len(1L), list(index = c("1::#File", "\"test2\":1#1",  : 
  arguments must have same length

Можете ли вы воспроизвести это (похоже, что "статистика" не работает)?

...