2015-06-03 17 views
9

Tôi đang làm việc trên tiny R package sử dụng CUDA và Rcpp, được điều chỉnh từ đầu ra của Rcpp.package.skeleton(). Trước tiên tôi sẽ mô tả những gì xảy ra trên nhánh chính cho cam kết mang tên "không gian tên cố định". Gói cài đặt thành công nếu tôi quên CUDA (tức là, nếu tôi xóa tệp src/Makefile, hãy thay đổi src/rcppcuda.cu thành src/rcppcuda.cpp và nhận xét mã xác định và gọi các hạt nhân). Nhưng như vậy, trình biên dịch không thành công.Xây dựng một gói R nhỏ với CUDA và Rcpp

Tôi cũng muốn biết cách biên dịch với Makevars hoặc Makevars.in thay vì Makefile và nói chung, hãy cố gắng làm cho nền tảng này độc lập như thực tế. Tôi đã đọc về Makevars trong R extensions manual, nhưng tôi vẫn chưa thể làm cho nó hoạt động.

Một số bạn có thể đề xuất rCUDA, nhưng những gì tôi thực sự ở đây đang cải thiện một gói lớn mà tôi đã phát triển trong một thời gian và tôi không chắc chắn rằng việc chuyển đổi có giá trị bắt đầu lại từ đầu.

Dù sao, đây là những gì sẽ xảy ra khi tôi thực hiện R CMD buildR CMD INSTALL trên this one (nhánh chính, cam kết mang tên "không gian tên cố định").

* installing to library ‘/home/landau/.R/library’ 
* installing *source* package ‘rcppcuda’ ... 
** libs 
** arch - 
/usr/local/cuda/bin/nvcc -c rcppcuda.cu -o rcppcuda.o --shared -Xcompiler "-fPIC" -gencode arch=compute_20,code=sm_20 -gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -I/apps/R-3.2.0/include -I/usr/local/cuda/include 
rcppcuda.cu:1:18: error: Rcpp.h: No such file or directory 
make: *** [rcppcuda.o] Error 1 
ERROR: compilation failed for package ‘rcppcuda’ 
* removing ‘/home/landau/.R/library/rcppcuda’ 

... thật lạ, bởi vì tôi bao gồm Rcpp.h và Rcpp được cài đặt.

$ R 

R version 3.2.0 (2015-04-16) -- "Full of Ingredients" 
Copyright (C) 2015 The R Foundation for Statistical Computing 
Platform: x86_64-unknown-linux-gnu (64-bit) 

...

> library(Rcpp) 
> sessionInfo() 
R version 3.2.0 (2015-04-16) 
Platform: x86_64-unknown-linux-gnu (64-bit) 
Running under: CentOS release 6.6 (Final) 

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] Rcpp_0.11.6 
> 

Tôi đang sử dụng CentOS,

$ cat /etc/*-release 
CentOS release 6.6 (Final) 
LSB_VERSION=base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch 
CentOS release 6.6 (Final) 
CentOS release 6.6 (Final) 

CUDA phiên bản 6,

$ nvcc --version 
nvcc: NVIDIA (R) Cuda compiler driver 
Copyright (c) 2005-2013 NVIDIA Corporation 
Built on Thu_Mar_13_11:58:58_PDT_2014 
Cuda compilation tools, release 6.0, V6.0.1 

và tôi có quyền truy cập đến 4 GPU của cùng làm và mô hình.

$ /usr/local/cuda/samples/bin/x86_64/linux/release/deviceQuery 
/usr/local/cuda/samples/bin/x86_64/linux/release/deviceQuery Starting... 

CUDA Device Query (Runtime API) version (CUDART static linking) 

Detected 4 CUDA Capable device(s) 

Device 0: "Tesla M2070" 
    CUDA Driver Version/Runtime Version   6.0/6.0 
    CUDA Capability Major/Minor version number: 2.0 
    Total amount of global memory:     5375 MBytes (5636554752 bytes) 
    (14) Multiprocessors, (32) CUDA Cores/MP:  448 CUDA Cores 
    GPU Clock rate:        1147 MHz (1.15 GHz) 
    Memory Clock rate:        1566 Mhz 
    Memory Bus Width:        384-bit 
    L2 Cache Size:         786432 bytes 
    Maximum Texture Dimension Size (x,y,z)   1D=(65536), 2D=(65536, 65535), 3D=(2048, 2048, 2048) 
    Maximum Layered 1D Texture Size, (num) layers 1D=(16384), 2048 layers 
    Maximum Layered 2D Texture Size, (num) layers 2D=(16384, 16384), 2048 layers 
    Total amount of constant memory:    65536 bytes 
    Total amount of shared memory per block:  49152 bytes 
    Total number of registers available per block: 32768 
    Warp size:          32 
    Maximum number of threads per multiprocessor: 1536 
    Maximum number of threads per block:   1024 
    Max dimension size of a thread block (x,y,z): (1024, 1024, 64) 
    Max dimension size of a grid size (x,y,z): (65535, 65535, 65535) 
    Maximum memory pitch:       2147483647 bytes 
    Texture alignment:        512 bytes 
    Concurrent copy and kernel execution:   Yes with 2 copy engine(s) 
    Run time limit on kernels:      No 
    Integrated GPU sharing Host Memory:   No 
    Support host page-locked memory mapping:  Yes 
    Alignment requirement for Surfaces:   Yes 
    Device has ECC support:      Enabled 
    Device supports Unified Addressing (UVA):  Yes 
    Device PCI Bus ID/PCI location ID:   11/0 
    Compute Mode: 
    < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) > 

...

> Peer access from Tesla M2070 (GPU0) -> Tesla M2070 (GPU1) : Yes 
> Peer access from Tesla M2070 (GPU0) -> Tesla M2070 (GPU2) : Yes 
> Peer access from Tesla M2070 (GPU0) -> Tesla M2070 (GPU3) : Yes 
> Peer access from Tesla M2070 (GPU1) -> Tesla M2070 (GPU1) : No 
> Peer access from Tesla M2070 (GPU1) -> Tesla M2070 (GPU2) : Yes 
> Peer access from Tesla M2070 (GPU1) -> Tesla M2070 (GPU3) : Yes 
> Peer access from Tesla M2070 (GPU2) -> Tesla M2070 (GPU1) : Yes 
> Peer access from Tesla M2070 (GPU2) -> Tesla M2070 (GPU2) : No 
> Peer access from Tesla M2070 (GPU2) -> Tesla M2070 (GPU3) : Yes 
> Peer access from Tesla M2070 (GPU1) -> Tesla M2070 (GPU0) : Yes 
> Peer access from Tesla M2070 (GPU1) -> Tesla M2070 (GPU1) : No 
> Peer access from Tesla M2070 (GPU1) -> Tesla M2070 (GPU2) : Yes 
> Peer access from Tesla M2070 (GPU2) -> Tesla M2070 (GPU0) : Yes 
> Peer access from Tesla M2070 (GPU2) -> Tesla M2070 (GPU1) : Yes 
> Peer access from Tesla M2070 (GPU2) -> Tesla M2070 (GPU2) : No 
> Peer access from Tesla M2070 (GPU3) -> Tesla M2070 (GPU0) : Yes 
> Peer access from Tesla M2070 (GPU3) -> Tesla M2070 (GPU1) : Yes 
> Peer access from Tesla M2070 (GPU3) -> Tesla M2070 (GPU2) : Yes 

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.0, CUDA Runtime Version = 6.0, NumDevs = 4, Device0 = Tesla M2070, Device1 = Tesla M2070, Device2 = Tesla M2070, Device3 = Tesla M2070 
Result = PASS 

Edit: nó biên dịch cho bất kỳ cam kết sau khi "namespace cố định" ở hai chi nhánh, nhưng vẫn còn có những vấn đề với cách kết hợp Rcpp và CUDA

Để biên soạn gói, hóa ra tôi chỉ cần tách mã C++ và CUDA của mình thành riêng biệt *.cpp*.cu tệp. Tuy nhiên, khi tôi thử "biên soạn cpp và Cu riêng" cam kết về chi nhánh tổng thể, tôi nhận được

> library(rcppcuda) 
> hello() 
An object of class "MyClass" 
Slot "x": 
[1] 1 2 3 4 5 6 7 8 9 10 

Slot "y": 
[1] 1 2 3 4 5 6 7 8 9 10 

Error in .Call("someCPPcode", r) : 
    "someCPPcode" not resolved from current namespace (rcppcuda) 
> 

Các lỗi sẽ biến mất trong ngành withoutCUDA trong cam kết mang tên "thêm chi nhánh withoutCUDA".

> library(rcppcuda) 
> hello() 
An object of class "MyClass" 
Slot "x": 
[1] 1 2 3 4 5 6 7 8 9 10 

Slot "y": 
[1] 1 2 3 4 5 6 7 8 9 10 

[1] "Object changed." 
An object of class "MyClass" 
Slot "x": 
[1] 500 2 3 4 5 6 7 8 9 10 

Slot "y": 
[1] 1 1000 3 4 5 6 7 8 9 10 

> 

Sự khác biệt duy nhất giữa "biên soạn cpp và Cu riêng" cam kết trên master và "thêm chi nhánh withoutCUDA" cam kết trên withoutCUDA

  • Các Makefile và someCUDAcode.cu đã mất hết từ withoutCUDA.
  • Trong withoutCUDA, tất cả các tham chiếu đến someCUDAcode() đều biến mất khỏi someCPPcode.cpp.

Ngoài ra, sẽ vẫn thuận tiện khi có thể sử dụng CUDA và Rcpp trong cùng một tệp *.cu. Tôi thực sự muốn biết cách sửa lỗi "không gian tên cố định" cam kết trên nhánh chính.

Trả lời

9

Đi qua gói của bạn có nhiều khía cạnh cần được thay đổi.

  1. Bạn không nên sử dụng 'Makefile' nhưng thay vào đó là tệp 'Makevars' để cải thiện khả năng tương thích cho nhiều bản dựng kiến ​​trúc.
  2. Hãy thử làm theo các tên biến chuẩn (ví dụ: CPPC phải là CXX), điều này làm cho mọi thứ hoạt động tốt hơn nhiều.
  3. Không tự mình cố gắng biên dịch đối tượng được chia sẻ, có các macro tốt bên trong R makefile cơ bản giúp đơn giản hơn nhiều (ví dụ: PKG_LIBS, OBJECTS, v.v.)
  4. Với nhiều trình biên dịch, bạn sẽ muốn sử dụng Macro ĐỐI TƯỢNG. Ở đây bạn sẽ ghi đè lên nỗ lực cơ bản của R để thiết lập các tập tin đối tượng được liên kết (chắc chắn rằng bạn bao gồm tất cả).
  5. Bạn cũng cần (AFAIK) để làm cho các hàm CUDA có sẵn với extern "C". Bạn sẽ thêm tiền tố cho cả hàm trong tệp .cu và khi bạn khai báo nó ở đầu tệp cpp của bạn.

Makevars sau đây đã làm việc cho tôi nhờ đó tôi đã sửa đổi CUDA_HOME, R_HOME và RCPP_INC của mình (chuyển lại cho bạn). Lưu ý, đây là nơi tệp configure được khuyến nghị để làm cho gói càng linh động càng tốt.

CUDA_HOME = /usr/local/cuda 
R_HOME = /apps/R-3.2.0 
CXX = /usr/bin/g++ 

# This defines what the shared object libraries will be 
PKG_LIBS= -L/usr/local/cuda-7.0/lib64 -Wl,-rpath,/usr/local/cuda-7.0/lib64 -lcudart -d 


######################################### 

R_INC = /usr/share/R/include 
RCPP_INC = $(R_HOME)/library/Rcpp/include 

NVCC = $(CUDA_HOME)/bin/nvcc 
CUDA_INC = $(CUDA_HOME)/include 
CUDA_LIB = $(CUDA_HOME)/lib64 

LIBS = -lcudart -d 
NVCC_FLAGS = -Xcompiler "-fPIC" -gencode arch=compute_20,code=sm_20 -gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -I$(R_INC) 

### Define objects 
cu_sources := $(wildcard *cu) 
cu_sharedlibs := $(patsubst %.cu, %.o,$(cu_sources)) 

cpp_sources := $(wildcard *.cpp) 
cpp_sharedlibs := $(patsubst %.cpp, %.o, $(cpp_sources)) 

OBJECTS = $(cu_sharedlibs) $(cpp_sharedlibs) 

all : rcppcuda.so 

rcppcuda.so: $(OBJECTS) 

%.o: %.cpp $(cpp_sources) 
     $(CXX) $< -c -fPIC -I$(R_INC) -I$(RCPP_INC) 

%.o: %.cu $(cu_sources) 
     $(NVCC) $(NVCC_FLAGS) -I$(CUDA_INC) $< -c 

Một điểm theo dõi (như bạn nói đây là một bài tập học tập):

A. Bạn chưa bằng một trong những bộ phận của Rcpp mà làm cho nó một gói tuyệt vời như vậy, cụ thể là ' thuộc tính'. Sau đây là cách tập cpp bạn nên xem xét:

#include <Rcpp.h> 
using namespace Rcpp; 

extern "C" 
void someCUDAcode(); 

//[[Rcpp::export]] 
SEXP someCPPcode(SEXP r) { 
    S4 c(r); 
    double *x = REAL(c.slot("x")); 
    int *y = INTEGER(c.slot("y")); 
    x[0] = 500.0; 
    y[1] = 1000; 
    someCUDAcode(); 
    return R_NilValue; 
} 

này sẽ tự động tạo ra tương ứng RcppExports.cppRcppExports.R tập tin và bạn không còn cần một hàm .Call mình. Bạn chỉ cần gọi hàm.Bây giờ .Call('someCPPcode', r) trở thành someCPPcode(r) :)

Để hoàn chỉnh, đây là cập nhật someCUDAcode.cu file:

__global__ void mykernel(int a){ 
    int id = threadIdx.x; 
    int b = a; 
    b++; 
    id++; 
} 


extern "C" 
void someCUDAcode() { 
    mykernel<<<1, 1>>>(1); 
} 

liên quan đến một tập tin cấu hình Với (sử dụng autoconf), bạn đều được chào đón bạn xem gpuRcuda gói của tôi sử dụng Rcpp, CUDA và ViennaCL (thư viện điện toán GPU C++).

+0

Điều này giải quyết cả hai vấn đề sau: sử dụng Makevars một cách chính xác và sử dụng Rcpp với CUDA. Cảm ơn! – landau

+0

Vui mừng được trợ giúp :-) – cdeterman

+0

Tôi nên đề cập đến việc thực hiện các thay đổi để cho phép 'someCPPcode (r)' thay vì '.Call ('someCPPcode', r)' không hoạt động đối với tôi. Tôi không thể truy cập chức năng 'someCPPcode' trong R. – landau

2

Một số gói trên cran sử dụng GPU thông qua CUDA:

Tôi sẽ bắt đầu với những điều này.

+0

Tôi đồng ý rằng đây là những ví dụ điển hình về việc kết hợp R và CUDA, nhưng không có cách nào sử dụng 'Rcpp' và mỗi loại dựa trên Makefile hoặc Makefile.in chứ không phải là Makevars. ['WideLM'] (http://cran.r-project.org/web/packages/WideLM/index.html) không sử dụng cả hai« Rcpp' và CUDA, nhưng [nó sẽ không cài đặt trên máy tôi sử dụng] (http://stackoverflow.com/questions/30631612/widelm-installation-error), vì vậy tôi không biết nó sẽ làm tốt bao nhiêu để đào sâu vào nguồn tại thời điểm này. – landau

+0

Shucks. Điểm tốt. Quên về WideLM. Tác giả của nó có một gói mới cho Rcpp, RcppArmadillo và CUDA sắp tới để bạn có thể muốn liên lạc. Nói với Mark Tôi đã nói Hi :) –

Các vấn đề liên quan