Benchmarking Utilizarea memoriei în R

URMĂREȘTE-NE
16,065FaniÎmi place
1,142CititoriConectați-vă

(Acest articol a fost publicat pentru prima dată pe Blogși a contribuit cu drag la R-Bloggers). (Puteți raporta problema despre conținutul de pe această pagină aici)


Doriți să vă împărtășiți conținutul pe R-Bloggers? Faceți clic aici dacă aveți un blog sau aici dacă nu.

Profilarea memoriei în R nu a fost niciodată o sarcină banală.
În această postare, aș dori să subliniez că metodele populare în prezent sunt destul de inexacte și, prin urmare, ar trebui utilizate cu precauție. Mai important, acestea nu ar trebui utilizate pentru a trage concluzii despre utilizarea reală a memoriei a funcțiilor R.

Cauza principală a inexactității cu multe instrumente de profilare a memoriei din R este aceea că acestea măsoară memoria alocată de R (inclusiv codul R al R). Nu iau în considerare memoria alocată folosind C.

Alocarea memoriei în R

Următorul exemplu ar trebui să fie foarte clar.

Mai jos R Bunk este conținutul memtest.R fişier.

code = "
  int nx = LENGTH(x);
  double *y = (double*)(
    LOGICAL(r_alloc)(0) ?
      R_alloc(nx, sizeof(*y)) : // allocated by R's C
      malloc(nx * sizeof(*y))   // allocated by C
  );
  double *xp = REAL(x);
  // populate y
  for (int i=0; i

Verificați egal

În primul rând, ne vom asigura că rezultatele sunt aceleași, indiferent dacă alocăm memorie de lucru temporară folosind R sau C:

Rscript -e 'source("memtest.R"); funx(x, r_alloc=TRUE)'
#(1) 1.160649e+12
Rscript -e 'source("memtest.R"); funx(x, r_alloc=FALSE)'
#(1) 1.160649e+12

Memory Benchmark folosind bench

În continuare, vom folosi cel mai popular pachet pentru profilarea memoriei, bench:

Rscript -e 'source("memtest.R"); bench::mark(funx(x, r_alloc=TRUE))'
## A tibble: 1 × 13
#  expression      min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
#                      
#1 funx(x, r_al… 577ms  577ms      1.73     763MB     1.73     1     1      577ms
Rscript -e 'source("memtest.R"); bench::mark(funx(x, r_alloc=FALSE))'
## A tibble: 1 × 13
#  expression      min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
#                      
#1 funx(x, r_al… 589ms  589ms      1.70        0B        0     1     0      589ms

După cum putem vedea în ieșirea din mark funcţie, mem_alloc se raportează că este 0b atunci când folosim mallocîn timp ce pentru R_alloc Raportează 763MB. Diferența pe care o observăm aici ar trebui să servească drept avertisment. Este pentru că bench::mark Urmărește alocările de memorie gestionate de alocatorul de memorie R și nu ține cont în mod inerent de memoria alocată direct prin funcții C, cum ar fi malloc sau calloc. Dacă cineva intenționează să folosească mark Funcție pentru a trage concluzii despre utilizarea memoriei, este crucial să examinăm, de asemenea, codul sursă al funcției fiind comparat.

Merită să rețineți că ?mark explică această problemă:

mem_allocbench_bytes Cantitatea totală de memorie alocată de R în timpul rulării expresiei. Memorie alocată în afara r. malloc() sau new În mod direct nu este urmărit, aveți grijă să evitați interpretarea greșită a rezultatelor dacă rulați cod care poate face acest lucru.

Din păcate, oamenii nu sunt conștienți de aceasta și publică adesea repere de utilizare a memoriei, crezând că sunt exacte.

Memory Benchmark folosind cgmemtime

În cele din urmă, vom folosi un proces extern pentru a măsura memoria, CGMEMTIME, propusă de Matt Dowle în 2014 în timpul lucrărilor sale pe 2B Rows Data.Frame Grouping Benchmark.

cgmemtime Măsoară utilizarea memoriei RSS cu apă ridicată+cache a unui proces și a proceselor sale descendente.

./cgmemtime Rscript -e 'source("memtest.R"); funx(x, r_alloc=TRUE)'
#child_RSS_high:    1641808 KiB
#group_mem_high:    1626264 KiB
./cgmemtime Rscript -e 'source("memtest.R"); funx(x, r_alloc=FALSE)'
#child_RSS_high:    1641096 KiB
#group_mem_high:    1625820 KiB

În timp ce cgmemtime Va raporta statistici de utilizare a memoriei foarte precise, nu poate măsura în mod direct utilizarea memoriei unui apel funcțional individual în mod izolat, deoarece urmărește amprenta de memorie a întregului proces (și procesele sale pentru copii).
Pentru a estima utilizarea memoriei funx() Apelați la acest exemplu simplu, putem măsura mai întâi procesul R fără a apela funx().

./cgmemtime Rscript -e 'source("memtest.R");'
#child_RSS_high:     860884 KiB
#group_mem_high:     843844 KiB

Și apoi scădeți această linie de bază din utilizarea memoriei când funx() este executat:

(1641096-860884)/1024
#(1) 761.9258

Mulțumesc

Sper că această postare îi va ajuta pe oameni să fie un pic mai sceptici atunci când citesc reperele de memorie ale lui R.

R version 4.5.0 (2025-04-11)
Platform: x86_64-redhat-linux-gnu
Running under: Fedora Linux 42 (Workstation Edition)

Matrix products: default
BLAS/LAPACK: FlexiBLAS OPENBLAS-OPENMP;  LAPACK version 3.12.0

locale:
 (1) LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 (3) LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 (5) LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 (7) LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 (9) LC_ADDRESS=C               LC_TELEPHONE=C            
(11) LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
(1) stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
(1) bench_1.1.4   inline_0.3.21

loaded via a namespace (and not attached):
(1) compiler_4.5.0  cli_3.6.4       pillar_1.10.2   glue_1.8.0     
(5) vctrs_0.6.5     lifecycle_1.0.4 rlang_1.1.6   
Dominic Botezariu
Dominic Botezariuhttps://www.noobz.ro/
Creator de site și redactor-șef.

Cele mai noi știri

Pe același subiect

LĂSAȚI UN MESAJ

Vă rugăm să introduceți comentariul dvs.!
Introduceți aici numele dvs.