在 R 中使用自定义内存分配函数
Posted
技术标签:
【中文标题】在 R 中使用自定义内存分配函数【英文标题】:Using a custom memory allocation function in R 【发布时间】:2014-10-21 10:08:08 【问题描述】:我希望能够对 R 中的某些数据结构(实值向量和数组)使用我自己的内存分配函数。这样做的原因是我需要我的数据是 64 位对齐的,我想使用numa library 用于控制使用哪个内存节点(我正在处理具有四个 12 核 AMD Opteron 6174 CPU 的计算节点)。
现在我有两个用于分配和释放内存的函数:numa_alloc_onnode
和 numa_free
(由 this thread 提供)。我使用的是 R 版本 3.1.1,所以我可以访问函数 allocVector3
(src/main/memory.c
),这在我看来是添加自定义内存分配器的预期方式。我还在src/include/R_ext
中找到了结构R_allocator
但是,我不清楚如何将这些部分组合在一起。假设,在 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 接口可能会表现不佳。
非常感谢任何帮助。
【问题讨论】:
这是一个猜想:“我试图避免使用 Rcpp,因为我正在修改一个相当大的包并且不想转换所有 C 调用并认为混合不同的 C接口的性能可能不是最优的。” 请凭经验证明 Rcpp 会使您的代码变慢。 对不起,我不想冒犯任何人,也不想暗示在这种情况下使用 Rcpp 是个坏主意。如果有人知道如何使用 Rcpp 解决我的问题,我很乐意尝试一下。或许最好将最后一部分表述为:“我没有看过 Rcpp,因为我正在修改一个不使用 Rcpp 的相当大的包。” 变化是增量的。您可以只添加一个(新)功能,而无需对包的其余部分进行任何更改。 我尝试使用 Rcpp 解决我的问题,但收到了long vectors not supported yet
错误。我正在使用Rcpp_0.11.3
。我做错了什么还是实际上还不支持长向量?
【参考方案1】:
我在解决我的问题方面取得了一些进展,我想分享一下,以防其他人遇到类似情况。感谢凯文的评论。我错过了他提到的包含声明。不幸的是,这只是众多问题之一。
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()
返回的地址)?
【讨论】:
【参考方案2】:R 有,在memory.c
:
main/memory.c
84:#include <R_ext/Rallocators.h> /* for R_allocator_t structure */
所以我认为您还需要包含该标头以获取自定义分配器(RInternals.h
仅声明它,未定义 struct
或包含该标头)
【讨论】:
以上是关于在 R 中使用自定义内存分配函数的主要内容,如果未能解决你的问题,请参考以下文章