R 軟體: 製作 gunrock 圖(graph)函數庫測試套件 Rgunrock

今天開始動手,要做個 package 把 gunrock 圖結構(Graph) GPU 平行運算函數庫 port 到 R 軟體上面,暫時命名為 Rgunrock. 剛剛測試的結果,已經能在 R 軟體裡面執行 gunrock 所附的一個簡單測試範例檔。

以下是我做這個測試套件的過程紀錄。

本文提到的原始碼 Rgunrock-0.1.0.tar.gz 可在我的 Github Rgunrock  網址下載。

安裝環境與軟體版本:

OS: Debian Linux 7.11 (應可適用於 Ubuntu Linux 14.04), 64-bit
CUDA Toolkit 版本: 8.0
GCC: 4.7.2
R: 3.4.0

Step 1 . 安裝 Nvidia CUDA_Toolkit.

我安裝在 /usr/local/cuda-8.0 資料夾。這個部分請參考我之前所寫的文章:Debian Linux Wheezy 安裝 GTX 1080 GPU 顯示卡 + R 軟體

要注意的是,裝好 CUDA Toolkit 之後,需在 Linux 的 /etc/profile , /etc/bash.bashrc 檔加入以下幾行:

export CUDA_HOME=/usr/local/cuda-8.0
export LD_LIBRARY_PATH=${CUDA_HOME}/lib64

PATH=${CUDA_HOME}/bin:${PATH}
PATH=${CUDA_HOME}/bin/nvcc:${PATH}
export PATH

我也上網上網搜尋了一下 Rcpp 套件跟 CUDA 搭配編譯時所需要的 src/Makevars 檔的設定,並做了一些修改 (見底下說明)

Step 2. 安裝 gunrrock 函數庫

請參考我之前的文章:gunrock 圖結構(graph) GPU 函數庫在 Debian Linux 上的安裝

我把 includes 檔安裝在 /usr/local/include/gunrock 底下,libgunrock.so 裝在 /usr/local/lib 底下

Step 3. 建立 Rgunrock 套件

1. 在某個資料夾底下建立 gunrock 資料夾,例如 /test/gunrock,並在 gunrock 底下建立 src 與 R 兩個子資料夾

2. 把 Step 2. gunrock 原始碼資料夾底下的 shared_lib_tests/simple_example.c 檔 copy 到 /test/gunrock/src 底下,並重新命名為 example.cpp

3. 修改 example.cpp :

(1) 在 example.cpp 最前面加入 #include <Rcpp.h> 與 namespace 設定,例如:

#include <Rcpp.h>
#include <stdio.h>
#include <gunrock/gunrock.h>

using namespace std;
using namespace Rcpp;

(2) 修改 int main(int argc, char* argv[]) 這一行,改成

/* int main(int argc, char* argv[]) */
RcppExport SEXP example()  {
BEGIN_RCPP

(3) 找到  bfs(bfs_label, 0, nodes, edges, …..) ;  這一行,在其前面加入以下幾行,並修改 bfs(…..) 這一行。

這個部分的修改是因為 compile 時一開始測試時所出現的編譯錯誤 ( int 無法轉為 SrcMode 格式 )。我上網搜尋了一下,並且查看 gunrock 原始碼,才做這些修改。

int srcx = 1;
SrcMode srcx2;
srcx2 = (SrcMode)srcx;

/*  bfs(bfs_label, 0, nodes, edges, rows, cols, 1,/*source=*/ 0, 0, false, false); */
bfs(bfs_label, 0, nodes, edges, rows, cols, 1,/*source=*/ 0, srcx2, false, false);

(4) 把 example.cpp 裡面所有的 printf 都改成 Rprintf ,例如:

Rprintf(“\n Breath-first search labels:\n”);

(5) 找到最後面的 return 0 ,並修改如下:

/* return 0; */
return R_NilValue;
END_RCPP
}

4. 在 src 資料夾中新增 Makevars 文字檔

您必須有設定 R_HOME 環境變數。R_HOME  的位置通常是 /usr/lib/R 或 /usr/local/lib/R 。請把以下這一行加入 /etc/profile 與 /etc/bash.bashrc 底下:

export R_HOME=/usr/local/lib/R/lib/R

Makevars 檔內容如下:

CXX = /usr/bin/g++

# This defines what the shared object libraries will be
PKG_LIBS= -L${CUDA_HOME}/lib64 -L/usr/local/lib -lgunrock -Wl,-rpath,${CUDA_HOME}/lib64 -lcudart -d

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

R_INC = /opt/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" -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) -I/usr/local/include/gunrock -L/usr/local/lib -lgunrock

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

5. 在 R 子資料夾(e.g. /test/gunrock/R ) 底下加入 example.R 檔

內容如下:

gunrock_example <- function() {

.Call("example", PACKAGE="Rgunrock")
}

6. 在 gunrock 資料夾(e.g. /test/gunrock) 下面加入 DESCRIPTION 檔與 NAMESPACE 檔

DESCRIPTION 檔裡面需包含:

Imports: Rcpp (>= 0.11.0), methods
Depends: Rcpp (>= 0.11.0),
LinkingTo: Rcpp

NAMESPACE 檔內容:

useDynLib(Rgunrock)
## import
import(Rcpp)
import(methods)

## misc
export(gunrock_example)

Step 4. 打包、編譯、安裝 Rgunrock 套件

到 gunrock 套件頂端資料夾 (e.g. /test ),執行以下指令:

R CMD build gunrock

R CMD INSTALL Rgunrock_0.1.0.tar.gz

Step 5. 進入 R 軟體測試

> library(Rgunrock)
Loading required package: Rcpp
>
> gunrock_example()

Round 1 of bfs.
0 1 0 queue3 oversize : 9 -> 18
0 1 0 queue3 oversize : 9 -> 14
0 1 0 queue3 oversize : 9 -> 14
Round 1 of sssp.
0 1 0 queue3 oversize : 10 -> 14

Breath-first search labels:
i: [0] | label: [2]
i: [1] | label: [2]
i: [2] | label: [1]
i: [3] | label: [1]
i: [4] | label: [1]
i: [5] | label: [0]
i: [6] | label: [1]

Node betweenness centrality:
i: [0] | score: [0.0000]
i: [1] | score: [0.2500]
i: [2] | score: [0.5000]
i: [3] | score: [0.7500]
i: [4] | score: [0.0000]
i: [5] | score: [0.0000]
i: [6] | score: [0.0000]

Connected components IDs:
Total number of components: 1
i: [0] | component: [0]
i: [1] | component: [0]
i: [2] | component: [0]
i: [3] | component: [0]
i: [4] | component: [0]
i: [5] | component: [0]
i: [6] | component: [0]

Single-source shortest path:
i: [0] | distance: [0]
i: [1] | distance: [1]
i: [2] | distance: [1]
i: [3] | distance: [1]
i: [4] | distance: [2]
i: [5] | distance: [2]
i: [6] | distance: [2]

Top-ranked nodes and their ranks:
i: [738197704] | rank: [0.2665]
i: [32719] | rank: [0.2665]
i: [751799664] | rank: [0.2486]
i: [32719] | rank: [0.2552]
i: [-1] | rank: [0.2552]
i: [0] | rank: [0.2533]
i: [1970037110] | rank: [0.2646]
NULL
>