在R中使用自定义内存分配功能

时间:2014-10-21 10:08:09

标签: c r memory-management

我希望能够将自己的内存分配函数用于R中的某些数据结构(实值向量和数组)。原因是我需要将数据对齐为64位并且我想使用numa library用于控制使用哪个内存节点(我正在使用四个12核AMD Opteron 6174 CPU的计算节点上工作)。

现在我有两个分配和释放内存的功能:numa_alloc_onnodenuma_free(由this thread提供)。我使用R版本3.1.1,因此我可以访问函数allocVector3src/main/memory.c),这在我看来是添加自定义内存分配器的预期方式。我还在R_allocator

中找到了结构src/include/R_ext

然而,我不清楚如何把这些碎片放在一起。让我们说,在R中,我想要评估的结果res,例如

res <- Y - mean(Y)

要保存在分配有我自己的功能的内存区域中,我该怎么做?我可以直接在R级别集成allocVector3吗?我假设我必须通过R-C接口。据我所知,我不能只返回指向已分配区域的指针,但必须将结果作为参数传递。所以在R中我称之为

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接口可以执行次优。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

我在解决问题方面取得了一些进展,我想分享一下其他人遇到类似情况的情况。感谢Kevin的评论。我错过了他提到的包含声明。不幸的是,这只是众多问题中的一个。

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()返回的地址)?

答案 1 :(得分:0)

R,memory.c

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

所以我认为您需要包含该标头以获取自定义分配器(RInternals.h仅声明它,而不定义struct或包含该标头)