【发布时间】:2015-12-13 01:35:27
【问题描述】:
我正在开发基于 JNI 的 CUDA 程序,为此我有一个具有主要功能的 java 类,即 jclass.java(包含本机 func jniEntry() 声明) 和从 javah 生成的 jclass.h 。我有 JNI 桥 cEntry.c,其中包含声明为的本机函数实现 JNIEXPORT void JNICALL Java_jclass_jniEntry(JNIEnv* env, jobject thisObj) 上述函数调用 CUDA 宿主函数,即 cudaprogram.h 中的 jniEntry()。 jniEntry() 函数然后调用包含在 cudaprogram.cu 中的设备函数
我似乎无法从生成的 .o 文件中生成 .so 文件,即来自 cudaprogram.cu 的 cudaprogram.o 和来自 cEntry.c 的 cEntry.o(这是 JNI 的桥梁,即 jclass.java -> jclass。类(来自 javac)和 jclass.h(来自 javah -jni) 我的makefile是:
INCLUDES := -I$(CUDASDK_PATH)/inc -I$(CUDA_PATH)/include -I$(JDK_PATH)/include -I$(JDK_PATH)/include/linux -I.
LIBRARIES := -lrt -lm -lcudart -lcufft -lcublas -L$(CUDA_PATH)/lib64 -L.
JAVASRC_PATH := ../
NATIVESRC_PATH := ./
NVCC := /opt/cuda-6.5//bin/nvcc -ccbin g++
cujni1: cEntry.o cudaprog.o makefile jclass.h cudaprog.h
g++ $(INCLUDES) $(LIBRARIES) -v -m64 -shared -fPIC -o libcujni1.so cEntry.o cudaprog.o
cEntry.o: cEntry.c jclass.h cudaprog.o
gcc $(INCLUDES) -v -m64 -fPIC -o $@ cEntry.c -c
cudaprog.o: cudaprog.cu jclass.h cudaprog.h
$(NVCC) $(INCLUDES) -v -m64 -o $@ -c cudaprog.cu
run: build
$(EXEC) ./cujni1
jclass.h:jclass.class
javah -jni -classpath $(JAVASRC_PATH) jclass
jclass.class:
javac $(JAVASRC_PATH)/jclass.java
生成时没有错误的文件是 jclass.class、jclass.h、cudaprogram.o、cEntry.o,但 libcujni1.so 没有生成,因为我收到类似的错误
/usr/bin/ld: cudaprog.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
cudaprog.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
make: *** [cujni1] Error 1
如您所见,我使用 nvcc 编译 .cu 文件,因此无法使用 -fPIC 选项,因为它返回 |unknown option -fPIC" 的错误
作为参考,我还附上了其他源文件 jclass.java:
public class jclass {
static {
System.loadLibrary("cujni1");
}
private native void jniEntry();
public static void main(String[] args){
System.out.print("1:Hello" + "JNI CUder\n");
new jclass().jniEntry();
}
}
cEntry.c:
#include <jni.h>
#include "jclass.h"
#include "cudaprog.h"
JNIEXPORT void JNICALL Java_jclass_jniEntry(JNIEnv* env, jobject thisObj)
{
printf("2:cEntry.c-->Java_jclass_jniEntry!\n");
jniEntry();
return;
}
生成的jclass.h:
#ifndef CUDAPROG_H_
#define CUDAPROG_H_
#ifdef __cplusplus
extern "C" {
#endif
void jniEntry();
#ifdef __cplusplus
}
#endif
#endif /* CUDAPROG_H_ */
cudaprogram.cu:
// includes, system
#include <string.h>
#include <math.h>
#include "jclass.h"
#include "cudaprog.h"
#include <stdio.h>
#include <iostream>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <ctime>
// CUDA runtime
#include <cuda_runtime.h>
// Helper functions and utilities to work with CUDA
#include <helper_functions.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define LO -100.0f
#define HI 100.0f
#define BlockSize 16
#define VECTORLENGTH 100
#define MATRIXLENGTH 4000
__global__ void
calDistanceMatrixCUDA(float *Out, float *In)
{
// Block index
// int bx = blockIdx.x;
// int by = blockIdx.y;
// Thread index
// int tx = threadIdx.x;
// int ty = threadIdx.y;
int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;
if (i < MATRIXLENGTH && j < MATRIXLENGTH)
{
float fDim = 0.0f;
float fDist = 0.0f;
float(&InM)[4000][100] = *reinterpret_cast<float(*)[4000][100]>(In);
float(&OutM)[4000][4000] = *reinterpret_cast<float(*)[4000][4000]>(Out);
for (int k = 0; k < VECTORLENGTH; k++){//not blockSize because numElements = 100 < 128
fDim = InM[i][k] - InM[j][k];
fDim *= fDim;
fDist += fDim;
}
fDist = sqrt(fDist);
OutM[i][j] = fDist;
}
}
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C"
{
#endif
void jniEntry()
{
clock_t time1, time2, time3, time4;
double tDiff1, tDiff2, tDiff3, tDiff4;
unsigned int numElements = VECTORLENGTH;//dims
unsigned int numVectors = MATRIXLENGTH;
dim3 dimsVector(VECTORLENGTH, 1, 1);
dim3 dimsVectorArray(MATRIXLENGTH, VECTORLENGTH, 1);
dim3 dimsDistMatrix(MATRIXLENGTH, MATRIXLENGTH, 1);
size_t sizeVector = VECTORLENGTH * sizeof(float);
size_t sizeVectorArray = sizeVector * MATRIXLENGTH;
size_t sizeMatrix = MATRIXLENGTH * MATRIXLENGTH * sizeof(float);
unsigned int nSizeVector = dimsVector.x * dimsVector.y;
unsigned int mem_SizeVector = sizeof(float) * nSizeVector;
unsigned int nSizeVectorArray = dimsVectorArray.x * dimsVectorArray.y;
unsigned int mem_SizeVectorArray = sizeof(float) * nSizeVectorArray;
unsigned int nSizeDistMatrix = dimsDistMatrix.x * dimsDistMatrix.y;
unsigned int mem_SizeDistMatrix = sizeof(float) * nSizeDistMatrix;
float *distMatrix = (float *)malloc(mem_SizeDistMatrix);///Destination
/////////////////////////////////////////
///initialize Vector
time1 = clock();
float *featureV100 = (float *)malloc(mem_SizeVectorArray);
for (int i = 0; i < nSizeVectorArray; ++i)
{
featureV100[i] = LO + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (HI - LO)));;
// printf("i:%d, == %5.2f\n", i, featureV100[i]);
}
time2 = clock();
///////////////////////////
float *d_featureV100, *d_DistMatrix;
cudaError_t error;
error = cudaMalloc((void **)&d_featureV100, mem_SizeVectorArray);
if (error != cudaSuccess)
{
printf("cudaMalloc d_featureV100 returned error code %d, line(%d)\n", error, __LINE__);
exit(EXIT_FAILURE);
}
error = cudaMalloc((void **)&d_DistMatrix, mem_SizeDistMatrix);
if (error != cudaSuccess)
{
printf("cudaMalloc d_DistMatrix returned error code %d, line(%d)\n", error, __LINE__);
exit(EXIT_FAILURE);
}
error = cudaMemcpy(d_featureV100, featureV100, mem_SizeVectorArray, cudaMemcpyHostToDevice);
if (error != cudaSuccess)
{
printf("cudaMemcpy (d_featureV100,featureV100) returned error code %d, line(%d)\n", error, __LINE__);
exit(EXIT_FAILURE);
}
//////////////////////
// Allocate CUDA events that we'll use for timing
cudaEvent_t start;
error = cudaEventCreate(&start);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to create start event (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
cudaEvent_t stop;
error = cudaEventCreate(&stop);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to create stop event (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
// Record the start event
error = cudaEventRecord(start, NULL);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to record start event (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
// Setup execution parameters
// int threads = /*128*/512; //sufficient for vector of 100 elements
dim3 threads(512); //sufficient for vector of 100 elements
// dim3 grid(MATRIXLENGTH / threads, MATRIXLENGTH / threads);
dim3 grid(512);
calDistanceMatrixCUDA<<<grid, threads>>>(d_DistMatrix, d_featureV100);
// Record the stop event
error = cudaEventRecord(stop, NULL);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to record stop event (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
// Wait for the stop event to complete
error = cudaEventSynchronize(stop);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to synchronize on the stop event (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
float msecTotal = 0.0f;
error = cudaEventElapsedTime(&msecTotal, start, stop);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to get time elapsed between events (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
// Compute and print the performance
float msec = msecTotal ;
printf(
"Performance= Time= %.3f msec, WorkgroupSize= %d,%d,%d threads/block & %d,%d,%d blocks/grid\n",
msec,
threads.x,threads.y,threads.z,
grid.x,grid.y,grid.z);
error = cudaGetLastError();
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to launch calDistanceMatrixCUDA (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
error = cudaMemcpy(distMatrix, d_DistMatrix, mem_SizeDistMatrix, cudaMemcpyDeviceToHost);
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to copy d_DistMatrix from device to host distMatrix (error code %s)!\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
cudaFree(d_featureV100);
cudaFree(d_DistMatrix);
free(featureV100);
free(distMatrix);
error = cudaDeviceReset();
if (error != cudaSuccess)
{
fprintf(stderr, "Failed to deinitialize the device! error=%s\n", cudaGetErrorString(error));
exit(EXIT_FAILURE);
}
printf("Done\n");
}
#ifdef __cplusplus
}
#endif
不用说,上面的 cudaprogam.cu 在作为 CUDA 应用程序(即没有 JNI)运行时可以正常运行而没有错误 请指导我在 makefile 中使用正确的选项,因为我是创建 makefile 的新手。谢谢。
编辑:
在您在下面的答案中提到的更改之后。 ldd 命令给出 `
ldd libcujni1.so
linux-vdso.so.1 => (0x00007ffd919b6000)
libcudart.so.6.5 => /opt/cuda-6.5//lib64/libcudart.so.6.5 (0x00007f47bde41000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f47bdb3d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f47bd778000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f47bd574000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f47bd356000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f47bd14e000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f47bce48000)
/lib64/ld-linux-x86-64.so.2 (0x00007f47be297000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f47bcc32000)
make 命令行显示
make all
javac ..//jclass.java
javah -jni -classpath ../ jclass
/opt/cuda-6.5//bin/nvcc -ccbin g++ -I/home/faizan/workspace/common//inc -I/opt/cuda-6.5//include -I/usr/lib/jvm/jdk1.8.0_60//include -I/usr/lib/jvm/jdk1.8.0_60//include/linux -I. -Xcompiler -fPIC -m64 -o cudaprog.o -c *.cu # -v
cudaprog.cu(89): warning: variable "time1" was set but never used
cudaprog.cu(89): warning: variable "time2" was set but never used
cudaprog.cu(89): warning: variable "time3" was declared but never referenced
cudaprog.cu(89): warning: variable "time4" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff1" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff2" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff3" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff4" was declared but never referenced
cudaprog.cu(92): warning: variable "numElements" was declared but never referenced
cudaprog.cu(93): warning: variable "numVectors" was declared but never referenced
cudaprog.cu(100): warning: variable "sizeVectorArray" was declared but never referenced
cudaprog.cu(101): warning: variable "sizeMatrix" was declared but never referenced
cudaprog.cu(104): warning: variable "mem_SizeVector" was declared but never referenced
cudaprog.cu(89): warning: variable "time1" was set but never used
cudaprog.cu(89): warning: variable "time2" was set but never used
cudaprog.cu(89): warning: variable "time3" was declared but never referenced
cudaprog.cu(89): warning: variable "time4" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff1" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff2" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff3" was declared but never referenced
cudaprog.cu(90): warning: variable "tDiff4" was declared but never referenced
cudaprog.cu(92): warning: variable "numElements" was declared but never referenced
cudaprog.cu(93): warning: variable "numVectors" was declared but never referenced
cudaprog.cu(100): warning: variable "sizeVectorArray" was declared but never referenced
cudaprog.cu(101): warning: variable "sizeMatrix" was declared but never referenced
cudaprog.cu(104): warning: variable "mem_SizeVector" was declared but never referenced
g++ -I/home/faizan/workspace/common//inc -I/opt/cuda-6.5//include -I/usr/lib/jvm/jdk1.8.0_60//include -I/usr/lib/jvm/jdk1.8.0_60//include/linux -I. -shared -fPIC -m64 -o cEntry.o cEntry.c jclass.h cudaprog.h # -shared -fPIC -Xlinker -znoexecstack -Xlinker -shared -v -g
g++ -I/home/faizan/workspace/common//inc -I/opt/cuda-6.5//include -I/usr/lib/jvm/jdk1.8.0_60//include -I/usr/lib/jvm/jdk1.8.0_60//include/linux -I. -m64 -shared -fPIC -o libcujni1.so cEntry.o cudaprog.o -L/opt/cuda-6.5//lib64 -Wl,-rpath=/opt/cuda-6.5//lib64 -lcufft -lcublas -lcudart -lcuda -lrt -lm # -v
还添加了库文件夹,即
LIBRARIES := -L$(CUDA_PATH)/lib64 -Wl,-rpath=$(CUDA_PATH)/lib64 -L$(CUDA_PATH)/lib64/stubs -Wl,-rpath=$(CUDA_PATH)/lib64/stubs -lcufft -lcublas -lcudart -lcuda -lrt -lm
目前的错误是(在jclass.java main()中运行输出命令后
Exception in thread "main" 1:HelloJNI CUder
java.lang.UnsatisfiedLinkError: jclass.jniEntry()V
at jclass.jniEntry(Native Method)
at jclass.main(jclass.java:22)
【问题讨论】:
-
您是否尝试将
-Xcompiler -fPIC添加到您的 nvcc 选项列表中? -
成功!非常感谢贾尔斯
-
很高兴它成功了。如果不是这样,我会感到惊讶,因为几年前我在同样的情况下就是这样做的。顺便说一句,您还应该在链接命令行中添加
-lcuda,否则您可能会在代码终止时偶然发现非常奇怪、随机且难以重现的错误,并带有虚假的“纯虚函数调用”错误消息。 -
更具体地说,有什么问题?您是否首先在 Java 环境之外尝试了您的代码(使用 C 主程序调用函数只是为了检查)?
-
是的 cudaprogram.cu 通过 $(EXEC) $(NVCC) $(ALL_LDFLAGS) $(GENCODE_FLAGS) -o cudaprogram cudaprogram.o $(LIBRARIES) 正确编译为可执行文件
标签: cuda java-native-interface g++ nvcc