Allocating many small objects triggers numerous garbage collections as R grows its memory, seriously degrading performance. The specific use case is in creating a STRSXP of several 1,000,000's of elements of 60-100 characters each; a simplified illustration understating the effects (because there is initially little to garbage collect, in contrast to an R session with several packages loaded) is below.

A simple solution is to provide a mechanism for the C programmer to request sufficient memory in advance. R_gc_needed might also be re-used at two other locations in memory.c (2221 and 2361) and could be exposed at the R level via a new argument, with default 0, to gc().

%> time R --vanilla -e "dyn.load('gc.so'); x = .Call('doit', 1000000, FALSE)"
> dyn.load('gc.so');  x = .Call('doit', 1000000, FALSE)

real    0m9.865s
user    0m9.697s
sys     0m0.146s

%> time R --vanilla -e "dyn.load('gc.so'); x = .Call('doit', 1000000, TRUE)"
> dyn.load('gc.so');  x = .Call('doit', 1000000, TRUE)

real    0m6.952s
user    0m6.802s
sys     0m0.132s

This is the test code

#include <stdio.h>
#include "Rdefines.h"

SEXP doit(SEXP len, SEXP needed)
{
    int i, n = asInteger(len);
    char **s = Calloc(n, char *);
    SEXP ans;

    for (i = 0; i < n; ++i) {
        s[i] = Calloc(80, char);
        sprintf(s[i], "%78d", i);
    }

    if (asLogical(needed))
        R_gc_needed(80 * n);

    PROTECT(ans = allocVector(STRSXP, n));
    for (i = 0; i < n; ++i)
        SET_STRING_ELT(ans, i, mkChar(s[i]));
    UNPROTECT(1);

    return ans;
}

and a patch

Index: src/include/R_ext/Memory.h
===================================================================
--- src/include/R_ext/Memory.h  (revision 57169)
+++ src/include/R_ext/Memory.h  (working copy)
@@ -36,6 +36,7 @@
 void   vmaxset(const void *);

 void   R_gc(void);
+void   R_gc_needed(size_t);

 char*  R_alloc(size_t, int);
 char*  S_alloc(long, int);
Index: src/main/memory.c
===================================================================
--- src/main/memory.c   (revision 57169)
+++ src/main/memory.c   (working copy)
@@ -2503,6 +2503,17 @@
     R_gc_internal(0);
 }

+void R_gc_needed(R_size_t size_needed)
+{
+    if (FORCE_GC || NO_FREE_NODES() || VHEAP_FREE() < size_needed) {
+       R_gc_internal(size_needed);
+       if (NO_FREE_NODES())
+           mem_err_cons();
+       if (VHEAP_FREE() < size_needed)
+           mem_err_heap(0);
+    }
+}
+
 static void R_gc_full(R_size_t size_needed)
 {
     num_old_gens_to_collect = NUM_OLD_GENERATIONS;


--
Computational Biology
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109

Location: M1-B861
Telephone: 206 667-2793

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to