2014-10-21 3 views
1

Я хотел бы иметь возможность использовать свою собственную функцию распределения памяти для определенных структур данных (вещественных векторов и массивов) в R. Причина этого в том, что мне нужны мои данные 64 бит и я хотел бы использовать numa library для контроля над тем, какой узел памяти используется (я работаю над вычислительными узлами с четырьмя 12-ядерными процессорами AMD Opteron 6174).Использование специальной функции выделения памяти в R

Теперь у меня есть две функции для выделения и освобождения памяти: numa_alloc_onnode и numa_free (любезно предоставлено this thread). Я использую R версии 3.1.1, поэтому у меня есть доступ к функции allocVector3 (src/main/memory.c), которая кажется мне как предполагаемым способом добавления специализированного распределителя памяти. Я также нашел структуру R_allocator в src/include/R_ext

Однако мне не ясно, как собрать эти штуки. Скажем, в R, я хочу результат res из оценки такой как

res <- Y - mean(Y) 

быть сохранен в области памяти, выделенной с моей собственной функцией, как бы я это сделать? Можно ли интегрировать allocVector3 непосредственно на уровень R? Я предполагаю, что мне нужно пройти через интерфейс R-C. Насколько я знаю, я не могу просто вернуть указатель на выделенную область, но должен передать результат в качестве аргумента. Так что в РИ называют что-то вроде

n <- length(Y) 
res <- numeric(length=1) 
.Call("R_allocate_using_myalloc", n, res) 
res <- Y - mean(Y) 

и в C

#include <R.h> 
#include <Rinternals.h> 
#include <numa.h> 

SEXP R_allocate_using_myalloc(SEXP R_n, SEXP R_res){ 
    PROTECT(R_n = coerceVector(R_n, INTSXP)); 
    PROTECT(R_res = coerceVector(R_res, REALSXP)); 
    int *restrict n = INTEGER(R_n); 

    R_allocator_t myAllocator; 
    myAllocator.mem_alloc = numa_alloc_onnode; 
    myAllocator.mem_free = numa_free; 
    myAllocator.res = NULL; 
    myAllocator.data = ???; 

    R_res = allocVector3(REALSXP, n, myAllocator); 

    UNPROTECT(2); 
} 

К сожалению, я не могу выйти за ошибки в variable has incomplete type 'R_allocator_t' компиляции (я должен был удалить .data линию, так как я не имею понятия о том, что я должен положить там). Имеет ли смысл какой-либо из вышеуказанного кода? Есть ли более простой способ достичь того, что я хочу? Кажется немного странным, чтобы выделить небольшой вектор в R и изменить его местоположение на C, чтобы иметь возможность контролировать распределение памяти и иметь вектор, доступный в R ...

Я пытаюсь избегайте использования Rcpp, поскольку я изменяю довольно большой пакет и не хочу преобразовывать все вызовы C, и думал, что смешивание различных C-интерфейсов может выполняться суб-оптимально.

Любая помощь с благодарностью.

+0

Это гипотеза: «Я пытаюсь избежать использования Rcpp, поскольку я изменяю довольно большой пакет и не хочу преобразовывать все вызовы C и думал, что смешивание различных C-интерфейсов может выполняться суб-оптимально. "_ Пожалуйста, покажите эмпирически, что Rcpp делает ваш код медленнее. –

+0

Прошу прощения, я не хотел никого обидеть, и я не хотел бы подразумевать, что использование Rcpp в этом случае - это плохая идея. Если у кого-то есть идея решить мою проблему с помощью Rcpp, я с удовольствием попробую. Возможно, было бы лучше сформулировать последний раздел следующим образом: «Я не смотрел Rcpp, потому что я изменяю довольно большой пакет, который не использует Rcpp». – nbenn

+0

Изменение возрастает. Вы просто добавили одну (новую) функцию, не требуя изменения _any_ для остальной части вашего пакета. –

ответ

0

R имеет в memory.c:

main/memory.c 
84:#include <R_ext/Rallocators.h> /* for R_allocator_t structure */ 

, так что я думаю, что вам нужно включить этот заголовок, а также получить пользовательский аллокатор (RInternals.h просто заявляет об этом, не определяя struct или включая этот заголовок)

0

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

dyn.load("myAlloc.so") 

size <- 3e9 
myBigmat <- .Call("myAllocC", size) 
print(object.size(myBigmat), units = "auto") 

rm(myBigmat) 
#include <R.h> 
#include <Rinternals.h> 
#include <R_ext/Rallocators.h> 
#include <numa.h> 

typedef struct allocator_data { 
    size_t size; 
} allocator_data; 

void* my_alloc(R_allocator_t *allocator, size_t size) { 
    ((allocator_data*)allocator->data)->size = size; 
    return (void*) numa_alloc_local(size); 
} 

void my_free(R_allocator_t *allocator, void * addr) { 
    size_t size = ((allocator_data*)allocator->data)->size; 
    numa_free(addr, size); 
} 

SEXP myAllocC(SEXP a) { 
    allocator_data* my_allocator_data = malloc(sizeof(allocator_data)); 
    my_allocator_data->size = 0; 

    R_allocator_t* my_allocator = malloc(sizeof(R_allocator_t)); 
    my_allocator->mem_alloc = &my_alloc; 
    my_allocator->mem_free = &my_free; 
    my_allocator->res = NULL; 
    my_allocator->data = my_allocator_data; 

    R_xlen_t n = asReal(a); 
    SEXP result = PROTECT(allocVector3(REALSXP, n, my_allocator)); 
    UNPROTECT(1); 
    return result; 
} 

Для компиляции кода на C, я использую R CMD SHLIB -std=c99 -L/usr/lib64 -lnuma myAlloc.c. Насколько я могу судить, это прекрасно работает. Если у кого есть улучшения/исправления, я бы с удовольствием включил их.

Одним из требований первоначального вопроса, который остается нерешенным, является проблема выравнивания.Блок памяти, возвращенный numa_alloc_local, правильно выровнен, но другие поля нового VECTOR_SEXPREC (например, заголовок sxpinfo_struct) возвращают начало массива данных. Как-то можно выровнять эту отправную точку (адрес возвращается REAL())?

Смежные вопросы