# HG changeset patch # User Doug Simon # Date 1391122354 -3600 # Node ID ab370d74a8ebdc446dd60cd808d888f54291da7c # Parent d6823d127f76c8732f70caec62ee3fb31342df21 implemented GC locking for duration of a PTX kernel call diff -r d6823d127f76 -r ab370d74a8eb graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java Thu Jan 30 23:51:55 2014 +0100 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java Thu Jan 30 23:52:34 2014 +0100 @@ -40,7 +40,6 @@ double d; } - @Ignore("Object parameters not yet GC safe") @Test public void test0() { for (long l : new long[]{Long.MIN_VALUE, -10, 0, 1, 2, 10, Long.MAX_VALUE}) { @@ -54,7 +53,6 @@ return a.l + l; } - @Ignore("Object parameters not yet GC safe") @Test public void test1() { for (int i : new int[]{Integer.MIN_VALUE, -10, 0, 1, 2, 10, Integer.MAX_VALUE}) { @@ -68,7 +66,6 @@ return a.i + i; } - @Ignore("Object parameters not yet GC safe") @Test public void test2() { A a = new A(); @@ -82,7 +79,6 @@ return a.z; } - @Ignore("Object parameters not yet GC safe") @Test public void test3() { for (byte b : new byte[]{Byte.MIN_VALUE, -10, 0, 1, 2, 10, Byte.MAX_VALUE}) { @@ -96,7 +92,6 @@ return a.b + b; } - @Ignore("Object parameters not yet GC safe") @Test public void test4() { for (short s : new short[]{Short.MIN_VALUE, -10, 0, 1, 2, 10, Short.MAX_VALUE}) { @@ -110,7 +105,7 @@ return a.s + s; } - @Ignore("Object parameters not yet GC safe") + @Ignore("java.lang.AssertionError: expected:<65531> but was:<809107451>") @Test public void test5() { for (char c : new char[]{Character.MIN_VALUE, 1, 2, 10, Character.MAX_VALUE}) { @@ -124,7 +119,6 @@ return a.c + c; } - @Ignore("Object parameters not yet GC safe") @Test public void test6() { for (float f : new float[]{Float.MIN_VALUE, Float.MIN_NORMAL, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN, -11.45F, -0.0F, 0.0F, 2, 10, Float.MAX_VALUE}) { @@ -138,7 +132,6 @@ return a.f + f; } - @Ignore("Object parameters not yet GC safe") @Test public void test7() { for (double d : new double[]{Double.MIN_VALUE, Double.MIN_NORMAL, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY - 11.45D, -0.0D, 0.0D, 2, 10, Double.MAX_VALUE}) { diff -r d6823d127f76 -r ab370d74a8eb graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java Thu Jan 30 23:51:55 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java Thu Jan 30 23:52:34 2014 +0100 @@ -105,12 +105,12 @@ *

* The generated graph includes a reference to the {@link HotSpotNmethod} for the kernel. There must * be another reference to the same {@link HotSpotNmethod} object to ensure that the nmethod is not - * unloaded by the next full GC. + * unloaded by the next full GC. Currently, these extra "keep-alive" references are maintained by + * {@link PTXHotSpotBackend}. *

- * TODO: Only the memory for objects passed as parameters is pinned. Surely the memory for other - * objects accessed in the kernel reachable from the parameter objects needs to be pinned as well? - *

- * TODO: Objects references within kernels are currently completely hidden from GC. + * The PTX runtime code called by the wrapper blocks GC while the kernel is executing (cf + * GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical JNI functions). This ensures objects can + * be safely passed to kernels but should be replaced with a lighter weight mechanism at some point. */ public class PTXWrapperBuilder extends GraphKit { diff -r d6823d127f76 -r ab370d74a8eb src/gpu/ptx/vm/gpu_ptx.cpp --- a/src/gpu/ptx/vm/gpu_ptx.cpp Thu Jan 30 23:51:55 2014 +0100 +++ b/src/gpu/ptx/vm/gpu_ptx.cpp Thu Jan 30 23:52:34 2014 +0100 @@ -29,6 +29,7 @@ #include "utilities/ostream.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "memory/gcLocker.inline.hpp" #include "runtime/interfaceSupport.hpp" #include "graal/graalEnv.hpp" #include "graal/graalCompiler.hpp" @@ -404,6 +405,7 @@ gpu::Ptx::CUdeviceptr _ret_value; // pointer to slot in GPU memory holding the return value int _ret_type_size; // size of the return type value bool _ret_is_object; // specifies if the return type is Object + bool _gc_locked; bool check(int status, const char *action) { if (status != GRAAL_CUDA_SUCCESS) { @@ -425,7 +427,7 @@ } public: - PtxCall(JavaThread* thread, address buffer, int buffer_size, oop* pinned, int encodedReturnTypeSize) : _thread(thread), + PtxCall(JavaThread* thread, address buffer, int buffer_size, oop* pinned, int encodedReturnTypeSize) : _thread(thread), _gc_locked(false), _buffer(buffer), _buffer_size(buffer_size), _pinned(pinned), _pinned_length(0), _ret_value(0), _ret_is_object(encodedReturnTypeSize < 0) { _ret_type_size = _ret_is_object ? -encodedReturnTypeSize : encodedReturnTypeSize; } @@ -445,6 +447,16 @@ if (count == 0) { return; } + // Once we start pinning objects, no GC must occur + // until the kernel has completed. This is a big + // hammer for ensuring we can safely pass objects + // to the GPU. + GC_locker::lock_critical(_thread); + _gc_locked = true; + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Locked GC"); + } + for (int i = 0; i < count; i++) { int offset = objectOffsets[i]; oop* argPtr = (oop*) (_buffer + offset); @@ -531,6 +543,12 @@ unpin_objects(); free_return_value(); destroy_context(); + if (_gc_locked) { + GC_locker::unlock_critical(_thread); + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Unlocked GC"); + } + } } }; @@ -550,10 +568,6 @@ return 0L; } -#if 0 - Universe::heap()->collect(GCCause::_jvmti_force_gc); -#endif - PtxCall call(thread, (address) buffer, bufferSize, (oop*) (address) pinnedObjects, encodedReturnTypeSize); #define TRY(action) do { \