Path: blob/master/runtime/cuda/CudaCommon.cpp
12420 views
/*******************************************************************************1* Copyright (c) 2013, 2019 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "CudaCommon.hpp"23#include "java/com_ibm_cuda_Cuda.h"24#include "java/com_ibm_cuda_Cuda_Cleaner.h"2526/**27* Unless there is an outstanding exception, create and throw a CudaException.28*29* @param[in] env the JNI interface pointer30* @param[in] error the CUDA error code to be included in the exception31*/32void33throwCudaException(JNIEnv * env, int32_t error)34{35J9VMThread * thread = (J9VMThread *)env;3637Trc_cuda_throwCudaException_entry(thread, error);3839J9JavaVM * javaVM = thread->javaVM;40J9CudaGlobals * globals = javaVM->cudaGlobals;4142Assert_cuda_true(NULL != globals);43Assert_cuda_true(NULL != globals->exception_init);4445if (env->ExceptionCheck()) {46Trc_cuda_throwCudaException_suppressed(thread);47} else {48jobject exception = env->NewObject(globals->exceptionClass, globals->exception_init, error);4950if (NULL != exception) {51env->Throw((jthrowable)exception);52}53}5455Trc_cuda_throwCudaException_exit(thread);56}5758/**59* Allocate a block of pinned host memory. Transfers between pinned memory and60* devices avoids the intermediate copy via a pinned buffer local to the device61* driver.62*63* Class: com.ibm.cuda.Cuda64* Method: allocatePinnedBuffer65* Signature: (J)J66*67* @param[in] env the JNI interface pointer68* @param[in] (unused) the class pointer69* @param[in] byteCount the number of bytes requested70* @return a pointer to the pinned block of storage71*/72jlong JNICALL73Java_com_ibm_cuda_Cuda_allocatePinnedBuffer74(JNIEnv * env, jclass, jlong byteCount)75{76J9VMThread * thread = (J9VMThread *)env;7778Trc_cuda_allocatePinnedBuffer_entry(thread, byteCount);7980void * address = NULL;81int32_t error = J9CUDA_ERROR_NO_DEVICE;82#ifdef OMR_OPT_CUDA83PORT_ACCESS_FROM_ENV(env);84error = j9cuda_hostAlloc((size_t)byteCount, J9CUDA_HOST_ALLOC_DEFAULT, &address);85#endif /* OMR_OPT_CUDA */8687if (0 != error) {88throwCudaException(env, error);89}9091Trc_cuda_allocatePinnedBuffer_exit(thread, address);9293return (jlong)address;94}9596/**97* Return the number of devices visible to this process.98*99* Class: com.ibm.cuda.Cuda100* Method: getDeviceCount101* Signature: ()I102*103* @param[in] env the JNI interface pointer104* @param[in] (unused) the class pointer105* @return the number of devices visible to this process106*/107jint JNICALL108Java_com_ibm_cuda_Cuda_getDeviceCount109(JNIEnv * env, jclass)110{111J9VMThread * thread = (J9VMThread *)env;112113Trc_cuda_getDeviceCount_entry(thread);114115uint32_t count = 0;116#ifdef OMR_OPT_CUDA117PORT_ACCESS_FROM_ENV(env);118int32_t error = j9cuda_deviceGetCount(&count);119120if (0 != error) {121throwCudaException(env, error);122}123#endif /* OMR_OPT_CUDA */124125Trc_cuda_getDeviceCount_exit(thread, count);126127return (jint)count;128}129130/**131* Return the version number of the device driver.132*133* Class: com.ibm.cuda.Cuda134* Method: getDriverVersion135* Signature: ()I136*137* @param[in] env the JNI interface pointer138* @param[in] (unused) the class pointer139* @return the driver version number140*/141jint JNICALL142Java_com_ibm_cuda_Cuda_getDriverVersion143(JNIEnv * env, jclass)144{145J9VMThread * thread = (J9VMThread *)env;146147Trc_cuda_getDriverVersion_entry(thread);148149uint32_t version = 0;150int32_t error = J9CUDA_ERROR_NO_DEVICE;151#ifdef OMR_OPT_CUDA152PORT_ACCESS_FROM_ENV(env);153error = j9cuda_driverGetVersion(&version);154#endif /* OMR_OPT_CUDA */155156if (0 != error) {157throwCudaException(env, error);158}159160Trc_cuda_getDriverVersion_exit(thread, version);161162return (jint)version;163}164165/**166* Return a string describing the given error code.167*168* Class: com.ibm.cuda.Cuda169* Method: getErrorMessage170* Signature: (I)Ljava/lang/String;171*172* @param[in] env the JNI interface pointer173* @param[in] (unused) the class pointer174* @param[in] code the error code175* @return a string describing the error176*/177jstring JNICALL178Java_com_ibm_cuda_Cuda_getErrorMessage179(JNIEnv * env, jclass, jint code)180{181J9VMThread * thread = (J9VMThread *)env;182183Trc_cuda_getErrorMessage_entry(thread, code);184185const char * message = NULL;186#ifdef OMR_OPT_CUDA187PORT_ACCESS_FROM_ENV(env);188message = j9cuda_getErrorString(code);189#else /* OMR_OPT_CUDA */190/* Without CUDA support from OMR, these are the only error codes in use. */191switch (code) {192case J9CUDA_NO_ERROR:193message = "no error";194break;195case J9CUDA_ERROR_MEMORY_ALLOCATION:196message = "memory allocation failed";197break;198case J9CUDA_ERROR_NO_DEVICE:199message = "no CUDA-capable device is detected";200break;201default:202break;203}204#endif /* OMR_OPT_CUDA */205206Trc_cuda_getErrorMessage_exit(thread, (NULL == message) ? "(null)" : message);207208return (NULL == message) ? NULL : env->NewStringUTF(message);209}210211/**212* Return the version number of the CUDA runtime.213*214* Class: com.ibm.cuda.Cuda215* Method: getRuntimeVersion216* Signature: ()I217*218* @param[in] env the JNI interface pointer219* @param[in] (unused) the class pointer220* @return the runtime version number221*/222jint JNICALL223Java_com_ibm_cuda_Cuda_getRuntimeVersion224(JNIEnv * env, jclass)225{226J9VMThread * thread = (J9VMThread *)env;227228Trc_cuda_getRuntimeVersion_entry(thread);229230uint32_t version = 0;231int32_t error = J9CUDA_ERROR_NO_DEVICE;232#ifdef OMR_OPT_CUDA233PORT_ACCESS_FROM_ENV(env);234error = j9cuda_runtimeGetVersion(&version);235#endif /* OMR_OPT_CUDA */236237if (0 != error) {238throwCudaException(env, error);239}240241Trc_cuda_getRuntimeVersion_exit(thread, version);242243return (jint)version;244}245246/**247* Perform initialization required by native code.248*249* Class: com.ibm.cuda.Cuda250* Method: initialize251* Signature: (Ljava/lang/Class;Ljava/lang/reflect/Method;)I252*253* @param[in] env the JNI interface pointer254* @param[in] (unused) the class pointer255* @param[in] exceptionClass the class pointer for CudaException256* @param[in] runMethod the method handle for Runnable.run()257* @return a CUDA error code258*/259jint JNICALL260Java_com_ibm_cuda_Cuda_initialize261(JNIEnv * env, jclass, jclass exceptionClass, jobject runMethod)262{263jint result = 0;264J9CudaGlobals * globals = NULL;265J9VMThread * thread = (J9VMThread *)env;266J9JavaVM * javaVM = thread->javaVM;267268UT_MODULE_LOADED(J9_UTINTERFACE_FROM_VM(javaVM));269270Trc_cuda_initialize_entry(thread);271272Assert_cuda_true(NULL != exceptionClass);273Assert_cuda_true(NULL != runMethod);274275PORT_ACCESS_FROM_JAVAVM(javaVM);276277globals = (J9CudaGlobals *)J9CUDA_ALLOCATE_MEMORY(sizeof(J9CudaGlobals));278279if (NULL == globals) {280Trc_cuda_initialize_fail(thread, "allocate globals");281result = J9CUDA_ERROR_MEMORY_ALLOCATION;282goto done;283}284285memset(globals, 0, sizeof(J9CudaGlobals));286287// Cache handles for classes and methods we use.288289globals->exceptionClass = (jclass)env->NewGlobalRef(exceptionClass);290291if (NULL == globals->exceptionClass) {292Trc_cuda_initialize_fail(thread, "create NewGlobalRef for CudaException");293result = J9CUDA_ERROR_MEMORY_ALLOCATION;294goto error1;295}296297globals->exception_init = env->GetMethodID(globals->exceptionClass, "<init>", "(I)V");298299if (NULL == globals->exception_init) {300Trc_cuda_initialize_fail(thread, "find CudaException constructor");301result = J9CUDA_ERROR_INITIALIZATION_ERROR;302goto error2;303}304305globals->runnable_run = env->FromReflectedMethod(runMethod);306307if (NULL == globals->runnable_run) {308Trc_cuda_initialize_fail(thread, "get method handle");309result = J9CUDA_ERROR_INITIALIZATION_ERROR;310311error2:312env->DeleteGlobalRef(globals->exceptionClass);313314error1:315J9CUDA_FREE_MEMORY(globals);316globals = NULL;317}318319javaVM->cudaGlobals = globals;320321done:322Trc_cuda_initialize_exit(thread, result);323324return result;325}326327#ifdef OMR_OPT_CUDA328329/**330* Wrap the given native host buffer in a direct NIO byte buffer.331*332* Class: com.ibm.cuda.Cuda333* Method: wrapDirectBuffer334* Signature: (JJ)Ljava/nio/ByteBuffer;335*336* @param[in] env the JNI interface pointer337* @param[in] (unused) the class pointer338* @param[in] buffer the buffer pointer339* @param[in] capacity the buffer size in bytes340* @return a direct byte buffer341*/342jobject JNICALL343Java_com_ibm_cuda_Cuda_wrapDirectBuffer344(JNIEnv * env, jclass, jlong buffer, jlong capacity)345{346J9VMThread * thread = (J9VMThread *)env;347348Trc_cuda_wrapDirectBuffer_entry(thread, (uintptr_t)buffer, capacity);349350jobject wrapper = env->NewDirectByteBuffer((void *)(uintptr_t)buffer, capacity);351352Trc_cuda_wrapDirectBuffer_exit(thread, wrapper);353354return wrapper;355}356357/**358* Release a block of pinned host memory.359*360* Class: com.ibm.cuda.Cuda.Cleaner361* Method: releasePinnedBuffer362* Signature: (J)V363*364* @param[in] env the JNI interface pointer365* @param[in] (unused) the class pointer366* @param[in] address the buffer pointer367*/368void JNICALL369Java_com_ibm_cuda_Cuda_00024Cleaner_releasePinnedBuffer370(JNIEnv * env, jclass, jlong address)371{372J9VMThread * thread = (J9VMThread *)env;373374Trc_cuda_releasePinnedBuffer_entry(thread, (uintptr_t)address);375376PORT_ACCESS_FROM_ENV(env);377378int32_t error = j9cuda_hostFree((void *)(uintptr_t)address);379380if (0 != error) {381throwCudaException(env, error);382}383384Trc_cuda_releasePinnedBuffer_exit(thread);385}386387#endif /* OMR_OPT_CUDA */388389/**390* Called immediately before our shared library is unloaded: Release resources we allocated.391*/392void JNICALL393JNI_OnUnload(JavaVM * jvm, void *)394{395J9JavaVM * javaVM = (J9JavaVM *)jvm;396J9CudaGlobals * globals = javaVM->cudaGlobals;397398PORT_ACCESS_FROM_JAVAVM(javaVM);399400if (NULL != globals) {401if (NULL != globals->exceptionClass) {402JNIEnv * env = NULL;403404/*405* It's not serious if we can't get the JNIEnv - we're likely shutting down anyway.406*/407if (JNI_OK == jvm->GetEnv((void **)&env, JNI_VERSION_1_2)) {408env->DeleteGlobalRef(globals->exceptionClass);409}410}411412J9CUDA_FREE_MEMORY(globals);413javaVM->cudaGlobals = NULL;414}415416UT_MODULE_UNLOADED(J9_UTINTERFACE_FROM_VM(javaVM));417}418419420