From 83044ff7e7ecc9c7faa2404d07fe602c3fad5a4f Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Tue, 25 Jun 2024 20:40:46 +0000 Subject: [PATCH 01/12] Initial commit --- java/README.md | 20 ++ .../java/bindings/kvikio/cufile/CuFile.java | 29 +++ .../bindings/kvikio/cufile/CuFileDriver.java | 19 ++ .../bindings/kvikio/cufile/CuFileHandle.java | 23 ++ .../kvikio/cufile/CuFileReadHandle.java | 17 ++ .../kvikio/cufile/CuFileWriteHandle.java | 16 ++ .../java/bindings/kvikio/example/Main.java | 76 +++++++ java/src/main/native/src/CuFileJni.cpp | 208 ++++++++++++++++++ 8 files changed, 408 insertions(+) create mode 100644 java/README.md create mode 100644 java/src/main/java/bindings/kvikio/cufile/CuFile.java create mode 100644 java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java create mode 100644 java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java create mode 100644 java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java create mode 100644 java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java create mode 100644 java/src/main/java/bindings/kvikio/example/Main.java create mode 100644 java/src/main/native/src/CuFileJni.cpp diff --git a/java/README.md b/java/README.md new file mode 100644 index 0000000000..dd5c574bee --- /dev/null +++ b/java/README.md @@ -0,0 +1,20 @@ +Java Bindings + +Summary +These Java KvikIO bindings for GDS currently support only synchronous read and write IO operations using the underlying CuFile API. Support for batch IO and asynchronous operations are not yet supported. + +Dependencies +The Java KvikIO bindings have been developed to work on Linux based systems and require CUDA to be installed and for GDS to be properly enabled. Instructions for how to install and enable GDS can be found on NVIDIA's website. To compile the shared library it is also necessary to have a JDK installed. To run the included example, it is also necessary to install JCuda as it is used to handle memory allocations and the transfer of data between host and GPU memory. JCuda jar files supporting CUDA 12.x can be found here: +https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar +https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar + +Compilation +To recompile the .so file for your local system run the following command. Note: Update the command to reflect the directory where you have installed CUDA and your JDK. + +/usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile + +The resulting .so file must be in your JVM library path. If it is not already placed on your path in can be included when compiling and running your Java code by including an argument like the following: +-Djava.library.path={path/to/your/so/file/} + +Examples +An example for how to use the Java KvikIO bindings can be found in src/main/java/bindings/kvikio/example . Note: This example has a dependency on JCuda so ensure that when running the example the JCuda shared library files are on the JVM library path along with the libCuFileJNI.so file. diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFile.java b/java/src/main/java/bindings/kvikio/cufile/CuFile.java new file mode 100644 index 0000000000..1106477587 --- /dev/null +++ b/java/src/main/java/bindings/kvikio/cufile/CuFile.java @@ -0,0 +1,29 @@ +package bindings.kvikio.cufile; + +public class CuFile { + private static boolean initialized = false; + private static CuFileDriver driver; + + static { + initialize(); + } + + static synchronized void initialize() { + if (!initialized) { + try { + System.loadLibrary("CuFileJNI"); + driver = new CuFileDriver(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + driver.close(); + })); + initialized = true; + } catch (Throwable t) { + System.out.println("could not load cufile jni library"); + } + } + } + + public static boolean libraryLoaded() { + return initialized; + } +} diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java b/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java new file mode 100644 index 0000000000..893793d5a3 --- /dev/null +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java @@ -0,0 +1,19 @@ +package bindings.kvikio.cufile; + + +final class CuFileDriver implements AutoCloseable { + private final long pointer; + + CuFileDriver() { + pointer = create(); + } + + public void close() { + destroy(pointer); + } + + + private static native long create(); + + private static native void destroy(long pointer); +} diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java new file mode 100644 index 0000000000..f4bdd36882 --- /dev/null +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java @@ -0,0 +1,23 @@ +package bindings.kvikio.cufile; + +abstract class CuFileHandle implements AutoCloseable { + private final long pointer; + + static { + CuFile.initialize(); + } + + protected CuFileHandle(long pointer) { + this.pointer = pointer; + } + + public void close() { + destroy(pointer); + } + + protected long getPointer() { + return this.pointer; + } + + private static native void destroy(long pointer); + } \ No newline at end of file diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java new file mode 100644 index 0000000000..9c2ecc44d0 --- /dev/null +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java @@ -0,0 +1,17 @@ +package bindings.kvikio.cufile; + +public final class CuFileReadHandle extends CuFileHandle{ + + public CuFileReadHandle(String path) { + super(create(path)); + } + + public void read(long device_pointer, long size, long file_offset, long device_offset) { + readFile(getPointer(),device_pointer,size,file_offset,device_offset); + } + + private static native long create(String path); + + private static native void readFile(long file_pointer, long device_pointer, long size, long file_offset, long device_offset); + +} diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java new file mode 100644 index 0000000000..60bd6699e8 --- /dev/null +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java @@ -0,0 +1,16 @@ +package bindings.kvikio.cufile; + +public final class CuFileWriteHandle extends CuFileHandle { + + public CuFileWriteHandle(String path) { + super(create(path)); + } + + public void write(long device_pointer, long size, long file_offset, long buffer_offset) { + writeFile(getPointer(),device_pointer,size,file_offset,buffer_offset); + } + + private static native long create(String path); + + private static native void writeFile(long file_pointer, long device_pointer, long size, long file_offset, long buffer_offset); +} diff --git a/java/src/main/java/bindings/kvikio/example/Main.java b/java/src/main/java/bindings/kvikio/example/Main.java new file mode 100644 index 0000000000..a1fa159cbd --- /dev/null +++ b/java/src/main/java/bindings/kvikio/example/Main.java @@ -0,0 +1,76 @@ +package bindings.kvikio.example; + +import bindings.kvikio.cufile.CuFile; +import bindings.kvikio.cufile.CuFileReadHandle; +import bindings.kvikio.cufile.CuFileWriteHandle; + +import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyDeviceToHost; +import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyHostToDevice; + +import java.util.Arrays; + +import jcuda.NativePointerObject; +import jcuda.Pointer; +import jcuda.Sizeof; +import jcuda.driver.*; +import jcuda.runtime.JCuda; +import jcuda.runtime.cudaDeviceProp; + +class main { + public static void main(String []args) + { + // Allocate CUDA device memory + int numInts = 4; + Pointer pointer = new Pointer(); + JCuda.cudaMalloc(pointer, numInts*Sizeof.INT); + + // Build host arrays, print them out + int hostData[] = new int[numInts]; + int hostDataFilled[] = new int[numInts]; + for (int i = 0; i < numInts; ++i) { + hostDataFilled[i]=i; + } + System.out.println(Arrays.toString(hostData)); + System.out.println(Arrays.toString(hostDataFilled)); + + // Obtain pointer value for allocated CUDA device memory + long pointerAddress = getPointerAddress(pointer); + + // Copy filled data array to GPU and write to file + JCuda.cudaMemcpy(pointer,Pointer.to(hostDataFilled),numInts*Sizeof.INT,cudaMemcpyHostToDevice); + CuFileWriteHandle fw = new CuFileWriteHandle("/mnt/nvme/java_test"); + fw.write(pointerAddress, numInts*Sizeof.INT,0,0); + fw.close(); + + // Clear data stored in GPU + JCuda.cudaMemcpy(pointer,Pointer.to(hostData),numInts*Sizeof.INT,cudaMemcpyHostToDevice); + + // Read data back into GPU + CuFileReadHandle f = new CuFileReadHandle("/mnt/nvme/java_test"); + f.read(pointerAddress,numInts*Sizeof.INT,0,0); + f.close(); + + // Copy data back to host and confirm what was written was read + JCuda.cudaMemcpy(Pointer.to(hostData), pointer, numInts*Sizeof.INT, cudaMemcpyDeviceToHost); + System.out.println(Arrays.toString(hostDataFilled)); + System.out.println(Arrays.toString(hostData)); + JCuda.cudaFree(pointer); + } + + private static long getPointerAddress(Pointer p) + { + // WORKAROUND until a method like CUdeviceptr#getAddress exists + class PointerWithAddress extends Pointer + { + PointerWithAddress(Pointer other) + { + super(other); + } + long getAddress() + { + return getNativePointer() + getByteOffset(); + } + } + return new PointerWithAddress(p).getAddress(); + } +}; diff --git a/java/src/main/native/src/CuFileJni.cpp b/java/src/main/native/src/CuFileJni.cpp new file mode 100644 index 0000000000..69fc881cf9 --- /dev/null +++ b/java/src/main/native/src/CuFileJni.cpp @@ -0,0 +1,208 @@ +#include +#include +#include +#include + +#include + +#include + + +char const* GetCuErrorString(CUresult cu_result) +{ + char const* description; + if (cuGetErrorName(cu_result, &description) != CUDA_SUCCESS) description = "unknown cuda error"; + return description; +} + +std::string cuFileGetErrorString(int error_code) +{ + return IS_CUFILE_ERR(error_code) ? std::string(CUFILE_ERRSTR(error_code)) + : std::string(std::strerror(error_code)); +} + +std::string cuFileGetErrorString(CUfileError_t status) +{ + std::string error = cuFileGetErrorString(status.err); + if (IS_CUDA_ERR(status)) { error.append(".").append(GetCuErrorString(status.cu_err)); } + return error; +} + +/** @brief RAII wrapper for a file descriptor and the corresponding cuFile handle. */ +class cufile_file { + public: + /** + * @brief Construct a file wrapper. + * + * Should not be called directly; use the following factory methods instead. + * + * @param file_descriptor A valid file descriptor. + */ + explicit cufile_file(int file_descriptor) : file_descriptor_{file_descriptor} + { + CUfileDescr_t cufile_descriptor{CU_FILE_HANDLE_TYPE_OPAQUE_FD, file_descriptor_}; + auto const status = cuFileHandleRegister(&cufile_handle_, &cufile_descriptor); + if (status.err != CU_FILE_SUCCESS) { + close(file_descriptor_); + throw std::logic_error("Failed to register cuFile handle: " + cuFileGetErrorString(status)); + } + } + + /** + * @brief Factory method to create a file wrapper for reading. + * + * @param path Absolute path of the file to read from. + * @return std::unique_ptr for reading. + */ + static auto make_reader(char const* path) + { + auto const file_descriptor = open(path, O_RDONLY | O_DIRECT); + if (file_descriptor < 0) { + throw std::logic_error("Failed to open file to read: " + cuFileGetErrorString(errno)); + } + return std::make_unique(file_descriptor); + } + + + /** + * @brief Factory method to create a file wrapper for writing. + * + * @param path Absolute path of the file to write to. + * @return std::unique_ptr for writing. + */ + static auto make_writer(char const* path) + { + auto const file_descriptor = open(path, O_CREAT | O_WRONLY | O_DIRECT, S_IRUSR | S_IWUSR); + if (file_descriptor < 0) { + throw std::logic_error("Failed to open file to write: " + cuFileGetErrorString(errno)); + } + return std::make_unique(file_descriptor); + } + + + // Disable copy (and move) semantics. + cufile_file(cufile_file const&) = delete; + cufile_file& operator=(cufile_file const&) = delete; + + /** @brief Destroy the file wrapper by de-registering the cuFile handle and closing the file. */ + ~cufile_file() + { + cuFileHandleDeregister(cufile_handle_); + close(file_descriptor_); + } + + /** + * @brief Read the file into a device buffer. + * + * @param buffer Device buffer to read the file content into. + * @param file_offset Starting offset from which to read the file. + */ + void read(void* buffer, std::size_t size, std::size_t file_offset, std::size_t device_offset) const + { + auto const status = cuFileRead(cufile_handle_, buffer, size, file_offset, device_offset); + + if (status < 0) { + if (IS_CUFILE_ERR(status)) { + throw std::logic_error("Failed to read file into buffer: " + cuFileGetErrorString(status)); + } else { + throw std::logic_error("Failed to read file into buffer: " + cuFileGetErrorString(errno)); + + } + } + + //TODO check size of buffer vs bytes written? + } + + void write(void* buffer, std::size_t size, std::size_t file_offset, std::size_t buffer_offset) + { + auto const status = cuFileWrite(cufile_handle_,buffer,size,file_offset,buffer_offset); + if (status < 0) { + if (IS_CUFILE_ERR(status)) { + throw std::logic_error("Failed to write file from buffer: " + cuFileGetErrorString(status)); + } else { + throw std::logic_error("Failed to write file from buffer: " + cuFileGetErrorString(errno)); + + } + } + //TODO check size of buffer vs bytes written? + } + + private: + /// The underlying file descriptor. + int file_descriptor_; + /// The registered cuFile handle. + CUfileHandle_t cufile_handle_{}; +}; + +class cufile_driver { +public: + cufile_driver() + { + auto const status = cuFileDriverOpen(); + if (status.err != CU_FILE_SUCCESS) { + throw std::logic_error("Failed to initialize cuFile driver: " + cuFileGetErrorString(status)); + } + } + + cufile_driver(cufile_driver const&) = delete; + cufile_driver& operator=(cufile_driver const&) = delete; + + ~cufile_driver() { cuFileDriverClose(); } +}; + +extern "C" { +#include + +JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileDriver_create(JNIEnv* env, jclass) +{ + try { + return reinterpret_cast(new cufile_driver()); + } + catch(const std::exception& e) { + jlong default_ret_val = 0; + if (env->ExceptionOccurred()) { return default_ret_val; } + + jclass exceptionClass = env->FindClass("java/lang/Throwable"); + if (exceptionClass != NULL) { + env->ThrowNew(exceptionClass, e.what()); + } + return default_ret_val; + } +} + +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileDriver_destroy(JNIEnv* env, jclass, jlong pointer) +{ + delete reinterpret_cast(pointer); +} + +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileHandle_destroy(JNIEnv* env, jclass, jlong pointer) +{ + delete reinterpret_cast(pointer); +} + +JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileReadHandle_create(JNIEnv* env, jclass, jstring path) +{ + auto file = cufile_file::make_reader(env->GetStringUTFChars(path,nullptr)); + return reinterpret_cast(file.release()); +} + +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileReadHandle_readFile(JNIEnv* env, jclass, jlong file_pointer, jlong device_pointer, jlong size, jlong file_offset, jlong device_offset) +{ + auto* file_ptr = reinterpret_cast(file_pointer); + auto* dev_ptr = reinterpret_cast(device_pointer); + file_ptr->read(dev_ptr,size,file_offset,device_offset); +} + +JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_create(JNIEnv* env, jclass, jstring path) +{ + auto file = cufile_file::make_writer(env->GetStringUTFChars(path,nullptr)); + return reinterpret_cast(file.release()); +} + +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_writeFile(JNIEnv* env, jclass, jlong file_pointer, jlong device_pointer, jlong size, jlong file_offset, jlong buffer_offset) +{ + auto* file_ptr = reinterpret_cast(file_pointer); + auto* dev_ptr = reinterpret_cast(device_pointer); + file_ptr->write(dev_ptr,size,file_offset,buffer_offset); +} +} \ No newline at end of file From 62649e68689b3a87656326580965f2e9889c4048 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Tue, 25 Jun 2024 22:29:43 +0000 Subject: [PATCH 02/12] Update documentation to better flash out how to compile and run the example --- java/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/java/README.md b/java/README.md index dd5c574bee..d8b89682fe 100644 --- a/java/README.md +++ b/java/README.md @@ -18,3 +18,27 @@ The resulting .so file must be in your JVM library path. If it is not already pl Examples An example for how to use the Java KvikIO bindings can be found in src/main/java/bindings/kvikio/example . Note: This example has a dependency on JCuda so ensure that when running the example the JCuda shared library files are on the JVM library path along with the libCuFileJNI.so file. + +Specific instructions to run the example from a terminal: +Compile class files +cd kvikio/java/src/main/java/bindings/kvikio/cufile +javac \*.java + +Retrieve Jcuda jar files +cd kvikio/java/ +mkdir lib +cd lib +wget https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar +wget https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar + +Compile shared library +cd kvikio/java/lib +/usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux ../src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile + +Compile example file +cd kvikio/java/src/main/java +javac -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar bindings/kvikio/example/Main.java + +Run example +cd kvikio/java/src/main/java +java -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar -Djava.library.path=../../../lib/ bindings.kvikio.example.main From 161b260c606a88a9dceb438c65a7a8cd49e3c8ac Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Tue, 25 Jun 2024 22:51:42 +0000 Subject: [PATCH 03/12] code touchups and Readme update --- java/README.md | 4 ++++ java/src/main/java/bindings/kvikio/example/Main.java | 3 --- java/src/main/native/src/CuFileJni.cpp | 9 +++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/java/README.md b/java/README.md index d8b89682fe..e26e4691f6 100644 --- a/java/README.md +++ b/java/README.md @@ -35,6 +35,9 @@ Compile shared library cd kvikio/java/lib /usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux ../src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile +Setup a test file target NOTE: your mount directory may differ from /mnt/nvme, so update this command appropriately as well as example/Main.java to point to the correct file path. +touch /mnt/nvme/java\_test + Compile example file cd kvikio/java/src/main/java javac -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar bindings/kvikio/example/Main.java @@ -42,3 +45,4 @@ javac -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar Run example cd kvikio/java/src/main/java java -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar -Djava.library.path=../../../lib/ bindings.kvikio.example.main + diff --git a/java/src/main/java/bindings/kvikio/example/Main.java b/java/src/main/java/bindings/kvikio/example/Main.java index a1fa159cbd..1aac949532 100644 --- a/java/src/main/java/bindings/kvikio/example/Main.java +++ b/java/src/main/java/bindings/kvikio/example/Main.java @@ -1,6 +1,5 @@ package bindings.kvikio.example; -import bindings.kvikio.cufile.CuFile; import bindings.kvikio.cufile.CuFileReadHandle; import bindings.kvikio.cufile.CuFileWriteHandle; @@ -12,9 +11,7 @@ import jcuda.NativePointerObject; import jcuda.Pointer; import jcuda.Sizeof; -import jcuda.driver.*; import jcuda.runtime.JCuda; -import jcuda.runtime.cudaDeviceProp; class main { public static void main(String []args) diff --git a/java/src/main/native/src/CuFileJni.cpp b/java/src/main/native/src/CuFileJni.cpp index 69fc881cf9..c3a578f80c 100644 --- a/java/src/main/native/src/CuFileJni.cpp +++ b/java/src/main/native/src/CuFileJni.cpp @@ -51,7 +51,7 @@ class cufile_file { /** * @brief Factory method to create a file wrapper for reading. * - * @param path Absolute path of the file to read from. + * @param path Absolute path of the file to read from. This file must exist. * @return std::unique_ptr for reading. */ static auto make_reader(char const* path) @@ -67,7 +67,7 @@ class cufile_file { /** * @brief Factory method to create a file wrapper for writing. * - * @param path Absolute path of the file to write to. + * @param path Absolute path of the file to write to. This creates the file if it does not already exist.. * @return std::unique_ptr for writing. */ static auto make_writer(char const* path) @@ -109,8 +109,6 @@ class cufile_file { } } - - //TODO check size of buffer vs bytes written? } void write(void* buffer, std::size_t size, std::size_t file_offset, std::size_t buffer_offset) @@ -124,7 +122,6 @@ class cufile_file { } } - //TODO check size of buffer vs bytes written? } private: @@ -205,4 +202,4 @@ JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_writeFile(J auto* dev_ptr = reinterpret_cast(device_pointer); file_ptr->write(dev_ptr,size,file_offset,buffer_offset); } -} \ No newline at end of file +} From 30aa3dcf10e882ad03b1e417b570dbcc239bd508 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 26 Jun 2024 16:58:37 +0000 Subject: [PATCH 04/12] Update README with markdown formatting. Improve instructions and linkage --- java/README.md | 75 +++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/java/README.md b/java/README.md index e26e4691f6..c5acc7cd79 100644 --- a/java/README.md +++ b/java/README.md @@ -1,48 +1,59 @@ -Java Bindings +# Java KvikIO Bindings -Summary +## Summary These Java KvikIO bindings for GDS currently support only synchronous read and write IO operations using the underlying CuFile API. Support for batch IO and asynchronous operations are not yet supported. -Dependencies -The Java KvikIO bindings have been developed to work on Linux based systems and require CUDA to be installed and for GDS to be properly enabled. Instructions for how to install and enable GDS can be found on NVIDIA's website. To compile the shared library it is also necessary to have a JDK installed. To run the included example, it is also necessary to install JCuda as it is used to handle memory allocations and the transfer of data between host and GPU memory. JCuda jar files supporting CUDA 12.x can be found here: -https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar -https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar +## Dependencies +The Java KvikIO bindings have been developed to work on Linux based systems and require [CUDA](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html) to be installed and for [GDS](https://docs.nvidia.com/gpudirect-storage/troubleshooting-guide/index.html) to be properly enabled. To compile the shared library it is also necessary to have a JDK installed. To run the included example, it is also necessary to install JCuda as it is used to handle memory allocations and the transfer of data between host and GPU memory. JCuda jar files supporting CUDA 12.x can be found here: +[jcuda-12.0.0.jar](https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar), +[jcuda-natives-12.0.0.jar](https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar) -Compilation +For more information on JCuda and potentially more up to date installation instructions or jar files, see here: +[JCuda](http://javagl.de/jcuda.org/), [JCuda Usage](https://github.com/jcuda/jcuda-main/blob/master/USAGE.md), [JCuda Maven Repo](https://mvnrepository.com/artifact/org.jcuda) + +## Compilation To recompile the .so file for your local system run the following command. Note: Update the command to reflect the directory where you have installed CUDA and your JDK. -/usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile + /usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile -The resulting .so file must be in your JVM library path. If it is not already placed on your path in can be included when compiling and running your Java code by including an argument like the following: --Djava.library.path={path/to/your/so/file/} +The resulting .so file must be in your JVM library path when running upstream Java programs. If it is not already placed on your path in can be included by including an argument like the following: + + -Djava.library.path={path/to/your/so/file/} -Examples +## Examples An example for how to use the Java KvikIO bindings can be found in src/main/java/bindings/kvikio/example . Note: This example has a dependency on JCuda so ensure that when running the example the JCuda shared library files are on the JVM library path along with the libCuFileJNI.so file. -Specific instructions to run the example from a terminal: -Compile class files -cd kvikio/java/src/main/java/bindings/kvikio/cufile -javac \*.java +### Specific instructions to run the example from a terminal + +#### Compile class files + + cd kvikio/java/src/main/java/bindings/kvikio/cufile + javac *.java + +#### Retrieve Jcuda jar files + + cd kvikio/java/ + mkdir lib + cd lib + wget https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar + wget https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar + +#### Compile shared library + + cd kvikio/java/lib + /usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux ../src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile + +#### Setup a test file target NOTE: your mount directory may differ from /mnt/nvme, so update this command appropriately as well as example/Main.java to point to the correct file path. -Retrieve Jcuda jar files -cd kvikio/java/ -mkdir lib -cd lib -wget https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar -wget https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar + touch /mnt/nvme/java_test -Compile shared library -cd kvikio/java/lib -/usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux ../src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile +#### Compile example file -Setup a test file target NOTE: your mount directory may differ from /mnt/nvme, so update this command appropriately as well as example/Main.java to point to the correct file path. -touch /mnt/nvme/java\_test + cd kvikio/java/src/main/java + javac -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar bindings/kvikio/example/Main.java -Compile example file -cd kvikio/java/src/main/java -javac -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar bindings/kvikio/example/Main.java +#### Run example -Run example -cd kvikio/java/src/main/java -java -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar -Djava.library.path=../../../lib/ bindings.kvikio.example.main + cd kvikio/java/src/main/java + java -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar -Djava.library.path=../../../lib/ bindings.kvikio.example.main From 299bdb6dd2b6ae7ab4177c1290cb422cd27d2058 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Fri, 12 Jul 2024 20:33:45 +0000 Subject: [PATCH 05/12] Add initial maven setup, needs to be debugged --- java/pom.xml | 146 ++++++++++++++++++ .../java/bindings/kvikio/example/Main.java | 1 - 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 java/pom.xml diff --git a/java/pom.xml b/java/pom.xml new file mode 100644 index 0000000000..2a289445e5 --- /dev/null +++ b/java/pom.xml @@ -0,0 +1,146 @@ + + + + 4.0.0 + + bindings.kvikio + cufile + 24.08.0-SNAPSHOT + + cufile + + This project provides java bindings for the GPUDirect Storage cufile library, enabling the GPU to load and + save large amounts of data to and from persistent storage. This is still a work in progress so some APIs may change. + + http://ai.rapids + + + UTF-8 + 21 + 21 + + + + + org.jcuda + jcuda + 12.0.0 + + + org.jcuda + jcuda-natives + 12.0.0 + + + + + + + + maven-clean-plugin + 3.1.0 + + + maven-resources-plugin + 3.0.2 + + + maven-exec-plugin + 1.6.0 + + + maven-compiler-plugin + 3.8.0 + + 21 + 21 + + + + org.codehaus.mojo + native-maven-plugin + 0.7.11 + + + default-cli + + compile + link + + + + -I/usr/local/cuda/include/ + -I/usr/lib/jvm/java-21-openjdk-amd64/include/ + -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux + -lcufile + -fPIC + + + -shared + -o + libCuFileJNI.so + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.0.0 + + + compile-native-code + generate-sources + + run + + + + + + + + + + + + + + + + + + + + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/java/src/main/java/bindings/kvikio/example/Main.java b/java/src/main/java/bindings/kvikio/example/Main.java index 1aac949532..3e8db5f574 100644 --- a/java/src/main/java/bindings/kvikio/example/Main.java +++ b/java/src/main/java/bindings/kvikio/example/Main.java @@ -8,7 +8,6 @@ import java.util.Arrays; -import jcuda.NativePointerObject; import jcuda.Pointer; import jcuda.Sizeof; import jcuda.runtime.JCuda; From 1162efc4a51bb0e066827e11e241f6b6a091c755 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Fri, 12 Jul 2024 23:04:16 +0000 Subject: [PATCH 06/12] Update maven build to properly generate shared library --- java/README.md | 16 +++ java/pom.xml | 105 +++++++----------- .../java/bindings/kvikio/example/Main.java | 2 +- 3 files changed, 56 insertions(+), 67 deletions(-) diff --git a/java/README.md b/java/README.md index c5acc7cd79..a52bce2760 100644 --- a/java/README.md +++ b/java/README.md @@ -23,6 +23,22 @@ The resulting .so file must be in your JVM library path when running upstream Ja ## Examples An example for how to use the Java KvikIO bindings can be found in src/main/java/bindings/kvikio/example . Note: This example has a dependency on JCuda so ensure that when running the example the JCuda shared library files are on the JVM library path along with the libCuFileJNI.so file. +### Specific instructions to run the example using Maven + +#### Compile the shared library and Java files with Maven + + cd kvikio/java/ + mvn clean install + +#### Setup a test file target NOTE: your mount directory may differ from /mnt/nvme, so update this command appropriately as well as example/Main.java to point to the correct file path. + + touch /mnt/nvme/java_test + +#### Run example + + cd kvikio/java/ + java -cp target/cufile-24.08.0-SNAPSHOT.jar:$HOME/.m2/repository/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar:$HOME/.m2/repository/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar -Djava.library.path=./target bindings.kvikio.example.Main + ### Specific instructions to run the example from a terminal #### Compile class files diff --git a/java/pom.xml b/java/pom.xml index 2a289445e5..7ca7286f96 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -38,18 +38,17 @@ - - maven-clean-plugin - 3.1.0 - - - maven-resources-plugin - 3.0.2 - maven-exec-plugin 1.6.0 + + maven-clean-plugin + 3.1.0 + + true + + maven-compiler-plugin 3.8.0 @@ -58,64 +57,6 @@ 21 - - org.codehaus.mojo - native-maven-plugin - 0.7.11 - - - default-cli - - compile - link - - - - -I/usr/local/cuda/include/ - -I/usr/lib/jvm/java-21-openjdk-amd64/include/ - -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux - -lcufile - -fPIC - - - -shared - -o - libCuFileJNI.so - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 3.0.0 - - - compile-native-code - generate-sources - - run - - - - - - - - - - - - - - - - - - - - maven-surefire-plugin 2.22.1 @@ -142,5 +83,37 @@ + + + maven-antrun-plugin + 3.0.0 + + + compile-native-code + generate-sources + + run + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/src/main/java/bindings/kvikio/example/Main.java b/java/src/main/java/bindings/kvikio/example/Main.java index 3e8db5f574..a7d999730b 100644 --- a/java/src/main/java/bindings/kvikio/example/Main.java +++ b/java/src/main/java/bindings/kvikio/example/Main.java @@ -12,7 +12,7 @@ import jcuda.Sizeof; import jcuda.runtime.JCuda; -class main { +public class Main { public static void main(String []args) { // Allocate CUDA device memory From fe914270bae46d185356a3d8d6b09eb0fb7a8ec5 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 4 Sep 2024 17:53:47 +0000 Subject: [PATCH 07/12] Fix pre-commit issues --- java/README.md | 13 +- java/pom.xml | 4 +- .../java/bindings/kvikio/cufile/CuFile.java | 16 +++ .../bindings/kvikio/cufile/CuFileDriver.java | 18 ++- .../bindings/kvikio/cufile/CuFileHandle.java | 30 +++- .../kvikio/cufile/CuFileReadHandle.java | 22 ++- .../kvikio/cufile/CuFileWriteHandle.java | 20 ++- .../java/bindings/kvikio/example/Main.java | 20 ++- java/src/main/native/src/CuFileJni.cpp | 134 +++++++++++------- 9 files changed, 202 insertions(+), 75 deletions(-) diff --git a/java/README.md b/java/README.md index a52bce2760..f16873cbc1 100644 --- a/java/README.md +++ b/java/README.md @@ -5,7 +5,7 @@ These Java KvikIO bindings for GDS currently support only synchronous read and w ## Dependencies The Java KvikIO bindings have been developed to work on Linux based systems and require [CUDA](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html) to be installed and for [GDS](https://docs.nvidia.com/gpudirect-storage/troubleshooting-guide/index.html) to be properly enabled. To compile the shared library it is also necessary to have a JDK installed. To run the included example, it is also necessary to install JCuda as it is used to handle memory allocations and the transfer of data between host and GPU memory. JCuda jar files supporting CUDA 12.x can be found here: -[jcuda-12.0.0.jar](https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar), +[jcuda-12.0.0.jar](https://repo1.maven.org/maven2/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar), [jcuda-natives-12.0.0.jar](https://repo1.maven.org/maven2/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar) For more information on JCuda and potentially more up to date installation instructions or jar files, see here: @@ -17,7 +17,7 @@ To recompile the .so file for your local system run the following command. Note: /usr/local/cuda/bin/nvcc -shared -o libCuFileJNI.so -I/usr/local/cuda/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/ -I/usr/lib/jvm/java-21-openjdk-amd64/include/linux src/main/native/src/CuFileJni.cpp --compiler-options "-fPIC" -lcufile The resulting .so file must be in your JVM library path when running upstream Java programs. If it is not already placed on your path in can be included by including an argument like the following: - + -Djava.library.path={path/to/your/so/file/} ## Examples @@ -35,9 +35,9 @@ An example for how to use the Java KvikIO bindings can be found in src/main/java touch /mnt/nvme/java_test #### Run example - + cd kvikio/java/ - java -cp target/cufile-24.08.0-SNAPSHOT.jar:$HOME/.m2/repository/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar:$HOME/.m2/repository/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar -Djava.library.path=./target bindings.kvikio.example.Main + java -cp target/cufile-24.10.0-SNAPSHOT.jar:$HOME/.m2/repository/org/jcuda/jcuda/12.0.0/jcuda-12.0.0.jar:$HOME/.m2/repository/org/jcuda/jcuda-natives/12.0.0/jcuda-natives-12.0.0.jar -Djava.library.path=./target bindings.kvikio.example.Main ### Specific instructions to run the example from a terminal @@ -65,11 +65,10 @@ An example for how to use the Java KvikIO bindings can be found in src/main/java #### Compile example file - cd kvikio/java/src/main/java + cd kvikio/java/src/main/java javac -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar bindings/kvikio/example/Main.java #### Run example - cd kvikio/java/src/main/java + cd kvikio/java/src/main/java java -cp .:../../../lib/jcuda-12.0.0.jar:../../../lib/jcuda-natives-12.0.0.jar -Djava.library.path=../../../lib/ bindings.kvikio.example.main - diff --git a/java/pom.xml b/java/pom.xml index 7ca7286f96..75c070da43 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -1,13 +1,13 @@ - 4.0.0 bindings.kvikio cufile - 24.08.0-SNAPSHOT + 24.10.0-SNAPSHOT cufile diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFile.java b/java/src/main/java/bindings/kvikio/cufile/CuFile.java index 1106477587..5cfc44405b 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFile.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFile.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package bindings.kvikio.cufile; public class CuFile { diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java b/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java index 893793d5a3..f9879f09d7 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java @@ -1,4 +1,20 @@ -package bindings.kvikio.cufile; +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package bindings.kvikio.cufile; final class CuFileDriver implements AutoCloseable { diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java index f4bdd36882..7ec197ea93 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java @@ -1,23 +1,39 @@ -package bindings.kvikio.cufile; +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package bindings.kvikio.cufile; abstract class CuFileHandle implements AutoCloseable { private final long pointer; - + static { CuFile.initialize(); } - + protected CuFileHandle(long pointer) { this.pointer = pointer; } - + public void close() { destroy(pointer); } - + protected long getPointer() { return this.pointer; } - + private static native void destroy(long pointer); - } \ No newline at end of file + } diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java index 9c2ecc44d0..d64cbae62f 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java @@ -1,7 +1,23 @@ -package bindings.kvikio.cufile; +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package bindings.kvikio.cufile; public final class CuFileReadHandle extends CuFileHandle{ - + public CuFileReadHandle(String path) { super(create(path)); } @@ -13,5 +29,5 @@ public void read(long device_pointer, long size, long file_offset, long device_o private static native long create(String path); private static native void readFile(long file_pointer, long device_pointer, long size, long file_offset, long device_offset); - + } diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java index 60bd6699e8..057d1e32e0 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java @@ -1,7 +1,23 @@ -package bindings.kvikio.cufile; +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package bindings.kvikio.cufile; public final class CuFileWriteHandle extends CuFileHandle { - + public CuFileWriteHandle(String path) { super(create(path)); } diff --git a/java/src/main/java/bindings/kvikio/example/Main.java b/java/src/main/java/bindings/kvikio/example/Main.java index a7d999730b..eed4f38203 100644 --- a/java/src/main/java/bindings/kvikio/example/Main.java +++ b/java/src/main/java/bindings/kvikio/example/Main.java @@ -1,4 +1,20 @@ -package bindings.kvikio.example; +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package bindings.kvikio.example; import bindings.kvikio.cufile.CuFileReadHandle; import bindings.kvikio.cufile.CuFileWriteHandle; @@ -31,7 +47,7 @@ public static void main(String []args) // Obtain pointer value for allocated CUDA device memory long pointerAddress = getPointerAddress(pointer); - + // Copy filled data array to GPU and write to file JCuda.cudaMemcpy(pointer,Pointer.to(hostDataFilled),numInts*Sizeof.INT,cudaMemcpyHostToDevice); CuFileWriteHandle fw = new CuFileWriteHandle("/mnt/nvme/java_test"); diff --git a/java/src/main/native/src/CuFileJni.cpp b/java/src/main/native/src/CuFileJni.cpp index c3a578f80c..2aea5163b9 100644 --- a/java/src/main/native/src/CuFileJni.cpp +++ b/java/src/main/native/src/CuFileJni.cpp @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include #include @@ -7,7 +23,6 @@ #include - char const* GetCuErrorString(CUresult cu_result) { char const* description; @@ -58,28 +73,27 @@ class cufile_file { { auto const file_descriptor = open(path, O_RDONLY | O_DIRECT); if (file_descriptor < 0) { - throw std::logic_error("Failed to open file to read: " + cuFileGetErrorString(errno)); + throw std::logic_error("Failed to open file to read: " + cuFileGetErrorString(errno)); } return std::make_unique(file_descriptor); } - /** * @brief Factory method to create a file wrapper for writing. * - * @param path Absolute path of the file to write to. This creates the file if it does not already exist.. + * @param path Absolute path of the file to write to. This creates the file if it does not already + * exist.. * @return std::unique_ptr for writing. */ static auto make_writer(char const* path) { auto const file_descriptor = open(path, O_CREAT | O_WRONLY | O_DIRECT, S_IRUSR | S_IWUSR); if (file_descriptor < 0) { - throw std::logic_error("Failed to open file to write: " + cuFileGetErrorString(errno)); + throw std::logic_error("Failed to open file to write: " + cuFileGetErrorString(errno)); } return std::make_unique(file_descriptor); } - // Disable copy (and move) semantics. cufile_file(cufile_file const&) = delete; cufile_file& operator=(cufile_file const&) = delete; @@ -97,7 +111,10 @@ class cufile_file { * @param buffer Device buffer to read the file content into. * @param file_offset Starting offset from which to read the file. */ - void read(void* buffer, std::size_t size, std::size_t file_offset, std::size_t device_offset) const + void read(void* buffer, + std::size_t size, + std::size_t file_offset, + std::size_t device_offset) const { auto const status = cuFileRead(cufile_handle_, buffer, size, file_offset, device_offset); @@ -106,20 +123,18 @@ class cufile_file { throw std::logic_error("Failed to read file into buffer: " + cuFileGetErrorString(status)); } else { throw std::logic_error("Failed to read file into buffer: " + cuFileGetErrorString(errno)); - } } } void write(void* buffer, std::size_t size, std::size_t file_offset, std::size_t buffer_offset) { - auto const status = cuFileWrite(cufile_handle_,buffer,size,file_offset,buffer_offset); + auto const status = cuFileWrite(cufile_handle_, buffer, size, file_offset, buffer_offset); if (status < 0) { if (IS_CUFILE_ERR(status)) { throw std::logic_error("Failed to write file from buffer: " + cuFileGetErrorString(status)); } else { throw std::logic_error("Failed to write file from buffer: " + cuFileGetErrorString(errno)); - } } } @@ -132,19 +147,19 @@ class cufile_file { }; class cufile_driver { -public: - cufile_driver() - { - auto const status = cuFileDriverOpen(); - if (status.err != CU_FILE_SUCCESS) { - throw std::logic_error("Failed to initialize cuFile driver: " + cuFileGetErrorString(status)); - } + public: + cufile_driver() + { + auto const status = cuFileDriverOpen(); + if (status.err != CU_FILE_SUCCESS) { + throw std::logic_error("Failed to initialize cuFile driver: " + cuFileGetErrorString(status)); } + } - cufile_driver(cufile_driver const&) = delete; - cufile_driver& operator=(cufile_driver const&) = delete; + cufile_driver(cufile_driver const&) = delete; + cufile_driver& operator=(cufile_driver const&) = delete; - ~cufile_driver() { cuFileDriverClose(); } + ~cufile_driver() { cuFileDriverClose(); } }; extern "C" { @@ -152,54 +167,71 @@ extern "C" { JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileDriver_create(JNIEnv* env, jclass) { - try { - return reinterpret_cast(new cufile_driver()); - } - catch(const std::exception& e) { - jlong default_ret_val = 0; - if (env->ExceptionOccurred()) { return default_ret_val; } - - jclass exceptionClass = env->FindClass("java/lang/Throwable"); - if (exceptionClass != NULL) { - env->ThrowNew(exceptionClass, e.what()); - } - return default_ret_val; - } + try { + return reinterpret_cast(new cufile_driver()); + } catch (const std::exception& e) { + jlong default_ret_val = 0; + if (env->ExceptionOccurred()) { return default_ret_val; } + + jclass exceptionClass = env->FindClass("java/lang/Throwable"); + if (exceptionClass != NULL) { env->ThrowNew(exceptionClass, e.what()); } + return default_ret_val; + } } -JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileDriver_destroy(JNIEnv* env, jclass, jlong pointer) +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileDriver_destroy(JNIEnv* env, + jclass, + jlong pointer) { - delete reinterpret_cast(pointer); + delete reinterpret_cast(pointer); } -JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileHandle_destroy(JNIEnv* env, jclass, jlong pointer) +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileHandle_destroy(JNIEnv* env, + jclass, + jlong pointer) { - delete reinterpret_cast(pointer); + delete reinterpret_cast(pointer); } -JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileReadHandle_create(JNIEnv* env, jclass, jstring path) +JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileReadHandle_create(JNIEnv* env, + jclass, + jstring path) { - auto file = cufile_file::make_reader(env->GetStringUTFChars(path,nullptr)); - return reinterpret_cast(file.release()); + auto file = cufile_file::make_reader(env->GetStringUTFChars(path, nullptr)); + return reinterpret_cast(file.release()); } -JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileReadHandle_readFile(JNIEnv* env, jclass, jlong file_pointer, jlong device_pointer, jlong size, jlong file_offset, jlong device_offset) +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileReadHandle_readFile(JNIEnv* env, + jclass, + jlong file_pointer, + jlong device_pointer, + jlong size, + jlong file_offset, + jlong device_offset) { - auto* file_ptr = reinterpret_cast(file_pointer); - auto* dev_ptr = reinterpret_cast(device_pointer); - file_ptr->read(dev_ptr,size,file_offset,device_offset); + auto* file_ptr = reinterpret_cast(file_pointer); + auto* dev_ptr = reinterpret_cast(device_pointer); + file_ptr->read(dev_ptr, size, file_offset, device_offset); } -JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_create(JNIEnv* env, jclass, jstring path) +JNIEXPORT jlong JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_create(JNIEnv* env, + jclass, + jstring path) { - auto file = cufile_file::make_writer(env->GetStringUTFChars(path,nullptr)); - return reinterpret_cast(file.release()); + auto file = cufile_file::make_writer(env->GetStringUTFChars(path, nullptr)); + return reinterpret_cast(file.release()); } -JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_writeFile(JNIEnv* env, jclass, jlong file_pointer, jlong device_pointer, jlong size, jlong file_offset, jlong buffer_offset) +JNIEXPORT void JNICALL Java_bindings_kvikio_cufile_CuFileWriteHandle_writeFile(JNIEnv* env, + jclass, + jlong file_pointer, + jlong device_pointer, + jlong size, + jlong file_offset, + jlong buffer_offset) { - auto* file_ptr = reinterpret_cast(file_pointer); - auto* dev_ptr = reinterpret_cast(device_pointer); - file_ptr->write(dev_ptr,size,file_offset,buffer_offset); + auto* file_ptr = reinterpret_cast(file_pointer); + auto* dev_ptr = reinterpret_cast(device_pointer); + file_ptr->write(dev_ptr, size, file_offset, buffer_offset); } } From 4ad08c6af2726a59540a1d9d925e2b9738b0ed7a Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 4 Sep 2024 20:29:37 +0000 Subject: [PATCH 08/12] move example to be a test, update pom and dependencies to support CI runs --- ci/test_java.sh | 43 +++++++++++++++++++ dependencies.yaml | 11 +++++ java/pom.xml | 28 ++++++++++++ .../kvikio/cufile/BasicReadWriteTest.java} | 35 ++++++++------- 4 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 ci/test_java.sh rename java/src/{main/java/bindings/kvikio/example/Main.java => test/java/bindings/kvikio/cufile/BasicReadWriteTest.java} (81%) diff --git a/ci/test_java.sh b/ci/test_java.sh new file mode 100644 index 0000000000..74458e60b6 --- /dev/null +++ b/ci/test_java.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright (c) 2024, NVIDIA CORPORATION. + +set -euo pipefail + +. /opt/conda/etc/profile.d/conda.sh + +rapids-logger "Generate java testing dependencies" +rapids-dependency-file-generator \ + --output conda \ + --file-key test_java \ + --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch)" | tee env.yaml + +rapids-mamba-retry env create --yes -f env.yaml -n test + +# Temporarily allow unbound variables for conda activation. +set +u +conda activate test +set -u + +rapids-logger "Downloading artifacts from previous jobs" +CPP_CHANNEL=$(rapids-download-conda-from-s3 cpp) + +rapids-print-env + +rapids-mamba-retry install \ + --channel "${CPP_CHANNEL}" \ + libkvikio libkvikio-tests + +rapids-logger "Check GPU usage" +nvidia-smi + +EXITCODE=0 +trap "EXITCODE=1" ERR +set +e + +rapids-logger "Run Java tests" +pushd java +mvn test -B +popd + +rapids-logger "Test script exiting with value: $EXITCODE" +exit ${EXITCODE} \ No newline at end of file diff --git a/dependencies.yaml b/dependencies.yaml index c763161f8a..fa84f8c739 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -88,6 +88,11 @@ files: key: test includes: - test_python + test_java: + output: none + includes: + - cuda + - test_java channels: - rapidsai - rapidsai-nightly @@ -331,3 +336,9 @@ dependencies: packages: - *dask - distributed>=2022.05.2 + test_java: + common: + - output_types: conda + packages: + - maven + - openjdk=8.* diff --git a/java/pom.xml b/java/pom.xml index 75c070da43..6ff892eb81 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -20,6 +20,7 @@ UTF-8 21 21 + 5.4.2 @@ -33,6 +34,18 @@ jcuda-natives 12.0.0 + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-params + ${junit.version} + test + @@ -60,6 +73,21 @@ maven-surefire-plugin 2.22.1 + + -Djava.library.path=${project.build.directory}:${java.library.path} + + + + org.junit.platform + junit-platform-surefire-provider + 1.2.0 + + + org.junit.jupiter + junit-jupiter-engine + 5.4.2 + + maven-jar-plugin diff --git a/java/src/main/java/bindings/kvikio/example/Main.java b/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java similarity index 81% rename from java/src/main/java/bindings/kvikio/example/Main.java rename to java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java index eed4f38203..c3b44e2278 100644 --- a/java/src/main/java/bindings/kvikio/example/Main.java +++ b/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java @@ -14,13 +14,9 @@ * limitations under the License. */ - package bindings.kvikio.example; +package bindings.kvikio.cufile; -import bindings.kvikio.cufile.CuFileReadHandle; -import bindings.kvikio.cufile.CuFileWriteHandle; - -import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyDeviceToHost; -import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyHostToDevice; +import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -28,22 +24,30 @@ import jcuda.Sizeof; import jcuda.runtime.JCuda; -public class Main { - public static void main(String []args) +import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyDeviceToHost; +import static jcuda.runtime.cudaMemcpyKind.cudaMemcpyHostToDevice; + +import static org.junit.jupiter.api.Assertions.*; + +public class BasicReadWriteTest { + + @Test + public void testReadBackWrite() { + String libraryPath = System.getProperty("java.library.path"); + System.out.println("Java library path: " + libraryPath); + // Allocate CUDA device memory int numInts = 4; Pointer pointer = new Pointer(); JCuda.cudaMalloc(pointer, numInts*Sizeof.INT); - // Build host arrays, print them out - int hostData[] = new int[numInts]; - int hostDataFilled[] = new int[numInts]; + // Build host arrays + int[] hostData = new int[numInts]; + int[] hostDataFilled = new int[numInts]; for (int i = 0; i < numInts; ++i) { hostDataFilled[i]=i; } - System.out.println(Arrays.toString(hostData)); - System.out.println(Arrays.toString(hostDataFilled)); // Obtain pointer value for allocated CUDA device memory long pointerAddress = getPointerAddress(pointer); @@ -62,10 +66,9 @@ public static void main(String []args) f.read(pointerAddress,numInts*Sizeof.INT,0,0); f.close(); - // Copy data back to host and confirm what was written was read + // Copy data back to host and confirm what was written was read back JCuda.cudaMemcpy(Pointer.to(hostData), pointer, numInts*Sizeof.INT, cudaMemcpyDeviceToHost); - System.out.println(Arrays.toString(hostDataFilled)); - System.out.println(Arrays.toString(hostData)); + assertArrayEquals(hostData,hostDataFilled); JCuda.cudaFree(pointer); } From 83875b6d7214b35f359333ae0ea3c8838f4f09e2 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 4 Sep 2024 20:31:38 +0000 Subject: [PATCH 09/12] pre-commit fixes --- ci/test_java.sh | 2 +- .../test/java/bindings/kvikio/cufile/BasicReadWriteTest.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ci/test_java.sh b/ci/test_java.sh index 74458e60b6..3eecaf64f7 100644 --- a/ci/test_java.sh +++ b/ci/test_java.sh @@ -40,4 +40,4 @@ mvn test -B popd rapids-logger "Test script exiting with value: $EXITCODE" -exit ${EXITCODE} \ No newline at end of file +exit ${EXITCODE} diff --git a/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java b/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java index c3b44e2278..2ed5cc2ae1 100644 --- a/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java +++ b/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java @@ -34,9 +34,6 @@ public class BasicReadWriteTest { @Test public void testReadBackWrite() { - String libraryPath = System.getProperty("java.library.path"); - System.out.println("Java library path: " + libraryPath); - // Allocate CUDA device memory int numInts = 4; Pointer pointer = new Pointer(); From 4120e4c26b175326b2d5446d4dc7c23acf8b2932 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 4 Sep 2024 21:17:30 +0000 Subject: [PATCH 10/12] add github workflow items --- .github/workflows/build.yaml | 10 +++++++++- .github/workflows/pr.yaml | 14 ++++++++++++++ .github/workflows/test.yaml | 8 ++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1f8796e67f..a1105a5a77 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -34,6 +34,14 @@ jobs: branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} + java-build: + secrets: inherit + uses: rapidsai/shared-workflows/.github/workflows/conda-java-build.yaml@branch-24.10 + with: + build_type: ${{ inputs.build_type || 'branch' }} + branch: ${{ inputs.branch }} + date: ${{ inputs.date }} + sha: ${{ inputs.sha }} python-build: needs: [cpp-build] secrets: inherit @@ -44,7 +52,7 @@ jobs: date: ${{ inputs.date }} sha: ${{ inputs.sha }} upload-conda: - needs: [cpp-build, python-build] + needs: [cpp-build, python-build, java-build] secrets: inherit uses: rapidsai/shared-workflows/.github/workflows/conda-upload-packages.yaml@branch-24.10 with: diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 4499514060..28898af09d 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -15,6 +15,8 @@ jobs: - checks - conda-cpp-build - conda-cpp-tests + - conda-java-build + - conda-java-tests - conda-python-build - conda-python-tests - docs-build @@ -39,6 +41,18 @@ jobs: uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-tests.yaml@branch-24.10 with: build_type: pull-request + conda-java-build: + needs: checks + secrets: inherit + uses: rapidsai/shared-workflows/.github/workflows/conda-java-build.yaml@branch-24.10 + with: + build_type: pull-request + conda-java-tests: + needs: conda-java-build + secrets: inherit + uses: rapidsai/shared-workflows/.github/workflows/conda-java-tests.yaml@branch-24.10 + with: + build_type: pull-request conda-python-build: needs: conda-cpp-build secrets: inherit diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ef093ee79d..c462cb480b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,3 +30,11 @@ jobs: branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} + java-tests: + secrets: inherit + uses: rapidsai/shared-workflows/.github/workflows/conda-java-tests.yaml@branch-24.10 + with: + build_type: nightly + branch: ${{ inputs.branch }} + date: ${{ inputs.date }} + sha: ${{ inputs.sha }} From 888d6a7ab59264997854d0787b51b35b774a5e16 Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 18 Sep 2024 19:02:26 +0000 Subject: [PATCH 11/12] Updating workflows --- .github/workflows/build.yaml | 8 -------- .github/workflows/test.yaml | 8 ++++++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a1105a5a77..a9830b8e9d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -34,14 +34,6 @@ jobs: branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} - java-build: - secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-java-build.yaml@branch-24.10 - with: - build_type: ${{ inputs.build_type || 'branch' }} - branch: ${{ inputs.branch }} - date: ${{ inputs.date }} - sha: ${{ inputs.sha }} python-build: needs: [cpp-build] secrets: inherit diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c462cb480b..34f4b7c32e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,11 +30,15 @@ jobs: branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} - java-tests: + conda-java-tests: secrets: inherit - uses: rapidsai/shared-workflows/.github/workflows/conda-java-tests.yaml@branch-24.10 + uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@python-3.12 with: build_type: nightly branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} + node_type: "gpu-v100-latest-1" + arch: "amd64" + container_image: "rapidsai/ci-conda:latest" + run_script: "ci/test_java.sh" From 833ad32d604994c181fe54d9401111e25b76de4e Mon Sep 17 00:00:00 2001 From: Alex Sloboda Date: Wed, 18 Sep 2024 19:36:00 +0000 Subject: [PATCH 12/12] Formatting inconsistencies --- .../java/bindings/kvikio/cufile/CuFile.java | 2 +- .../bindings/kvikio/cufile/CuFileDriver.java | 4 +-- .../bindings/kvikio/cufile/CuFileHandle.java | 12 +++---- .../kvikio/cufile/CuFileReadHandle.java | 9 ++--- .../kvikio/cufile/CuFileWriteHandle.java | 7 ++-- .../kvikio/cufile/BasicReadWriteTest.java | 34 ++++++++----------- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFile.java b/java/src/main/java/bindings/kvikio/cufile/CuFile.java index 5cfc44405b..a4236a1c5b 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFile.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFile.java @@ -31,7 +31,7 @@ static synchronized void initialize() { driver = new CuFileDriver(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { driver.close(); - })); + })); initialized = true; } catch (Throwable t) { System.out.println("could not load cufile jni library"); diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java b/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java index f9879f09d7..37e75ad1db 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileDriver.java @@ -14,8 +14,7 @@ * limitations under the License. */ - package bindings.kvikio.cufile; - +package bindings.kvikio.cufile; final class CuFileDriver implements AutoCloseable { private final long pointer; @@ -28,7 +27,6 @@ public void close() { destroy(pointer); } - private static native long create(); private static native void destroy(long pointer); diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java index 7ec197ea93..f64e15401b 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileHandle.java @@ -14,26 +14,26 @@ * limitations under the License. */ - package bindings.kvikio.cufile; +package bindings.kvikio.cufile; abstract class CuFileHandle implements AutoCloseable { private final long pointer; static { - CuFile.initialize(); + CuFile.initialize(); } protected CuFileHandle(long pointer) { - this.pointer = pointer; + this.pointer = pointer; } public void close() { - destroy(pointer); + destroy(pointer); } protected long getPointer() { - return this.pointer; + return this.pointer; } private static native void destroy(long pointer); - } +} diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java index d64cbae62f..066b3e9214 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileReadHandle.java @@ -14,20 +14,21 @@ * limitations under the License. */ - package bindings.kvikio.cufile; +package bindings.kvikio.cufile; -public final class CuFileReadHandle extends CuFileHandle{ +public final class CuFileReadHandle extends CuFileHandle { public CuFileReadHandle(String path) { super(create(path)); } public void read(long device_pointer, long size, long file_offset, long device_offset) { - readFile(getPointer(),device_pointer,size,file_offset,device_offset); + readFile(getPointer(), device_pointer, size, file_offset, device_offset); } private static native long create(String path); - private static native void readFile(long file_pointer, long device_pointer, long size, long file_offset, long device_offset); + private static native void readFile(long file_pointer, long device_pointer, long size, long file_offset, + long device_offset); } diff --git a/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java b/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java index 057d1e32e0..e1bf8804f3 100644 --- a/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java +++ b/java/src/main/java/bindings/kvikio/cufile/CuFileWriteHandle.java @@ -14,7 +14,7 @@ * limitations under the License. */ - package bindings.kvikio.cufile; +package bindings.kvikio.cufile; public final class CuFileWriteHandle extends CuFileHandle { @@ -23,10 +23,11 @@ public CuFileWriteHandle(String path) { } public void write(long device_pointer, long size, long file_offset, long buffer_offset) { - writeFile(getPointer(),device_pointer,size,file_offset,buffer_offset); + writeFile(getPointer(), device_pointer, size, file_offset, buffer_offset); } private static native long create(String path); - private static native void writeFile(long file_pointer, long device_pointer, long size, long file_offset, long buffer_offset); + private static native void writeFile(long file_pointer, long device_pointer, long size, long file_offset, + long buffer_offset); } diff --git a/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java b/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java index 2ed5cc2ae1..78f9fa0af7 100644 --- a/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java +++ b/java/src/test/java/bindings/kvikio/cufile/BasicReadWriteTest.java @@ -32,57 +32,53 @@ public class BasicReadWriteTest { @Test - public void testReadBackWrite() - { + public void testReadBackWrite() { // Allocate CUDA device memory int numInts = 4; Pointer pointer = new Pointer(); - JCuda.cudaMalloc(pointer, numInts*Sizeof.INT); + JCuda.cudaMalloc(pointer, numInts * Sizeof.INT); // Build host arrays int[] hostData = new int[numInts]; int[] hostDataFilled = new int[numInts]; for (int i = 0; i < numInts; ++i) { - hostDataFilled[i]=i; + hostDataFilled[i] = i; } // Obtain pointer value for allocated CUDA device memory long pointerAddress = getPointerAddress(pointer); // Copy filled data array to GPU and write to file - JCuda.cudaMemcpy(pointer,Pointer.to(hostDataFilled),numInts*Sizeof.INT,cudaMemcpyHostToDevice); + JCuda.cudaMemcpy(pointer, Pointer.to(hostDataFilled), numInts * Sizeof.INT, cudaMemcpyHostToDevice); CuFileWriteHandle fw = new CuFileWriteHandle("/mnt/nvme/java_test"); - fw.write(pointerAddress, numInts*Sizeof.INT,0,0); + fw.write(pointerAddress, numInts * Sizeof.INT, 0, 0); fw.close(); // Clear data stored in GPU - JCuda.cudaMemcpy(pointer,Pointer.to(hostData),numInts*Sizeof.INT,cudaMemcpyHostToDevice); + JCuda.cudaMemcpy(pointer, Pointer.to(hostData), numInts * Sizeof.INT, cudaMemcpyHostToDevice); // Read data back into GPU CuFileReadHandle f = new CuFileReadHandle("/mnt/nvme/java_test"); - f.read(pointerAddress,numInts*Sizeof.INT,0,0); + f.read(pointerAddress, numInts * Sizeof.INT, 0, 0); f.close(); // Copy data back to host and confirm what was written was read back - JCuda.cudaMemcpy(Pointer.to(hostData), pointer, numInts*Sizeof.INT, cudaMemcpyDeviceToHost); - assertArrayEquals(hostData,hostDataFilled); + JCuda.cudaMemcpy(Pointer.to(hostData), pointer, numInts * Sizeof.INT, cudaMemcpyDeviceToHost); + assertArrayEquals(hostData, hostDataFilled); JCuda.cudaFree(pointer); } - private static long getPointerAddress(Pointer p) - { + private static long getPointerAddress(Pointer p) { // WORKAROUND until a method like CUdeviceptr#getAddress exists - class PointerWithAddress extends Pointer - { - PointerWithAddress(Pointer other) - { + class PointerWithAddress extends Pointer { + PointerWithAddress(Pointer other) { super(other); } - long getAddress() - { + + long getAddress() { return getNativePointer() + getByteOffset(); } } return new PointerWithAddress(p).getAddress(); } -}; +}