Fix HIP_SYNC_NULL_STREAM=0 mode.

- Fix null-stream sync
- hipStreamDestroy of null stream returns hipErrorInvalidResourceHandle
- Update documentation.
- Add tests for null stream sync, hipEventElapsedTime.
- Rename internal enum hipEventStatusRecorded to hipEventStatusComplete
- refactor hipStreamWaitEvent to streamline control-flow
このコミットが含まれているのは:
Ben Sander
2017-06-05 00:41:18 -05:00
コミット 39c18e5e5f
7個のファイルの変更249行の追加144行の削除
+96 -45
ファイルの表示
@@ -28,8 +28,8 @@ THE SOFTWARE.
enum SyncMode {
syncNone,
syncNullStream,
syncOtherStream,
syncStream,
syncStopEvent,
};
@@ -37,19 +37,23 @@ const char *syncModeString(int syncMode) {
switch (syncMode) {
case syncNone:
return "syncNone";
case syncNullStream:
return "syncNullStream";
case syncOtherStream:
return "syncOtherStream";
case syncStream:
return "syncStream";
case syncStopEvent:
return "syncStopEvent";
default:
return "unknown";
};
};
void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode)
void test(unsigned testMask, int *C_d, int *C_h, int64_t numElements, hipStream_t stream, int waitStart, SyncMode syncMode)
{
printf ("\ntest: syncMode=%s\n", syncModeString(syncMode));
if (!(testMask & p_tests)) {
return;
}
printf ("\ntest 0x%3x: stream=%p waitStart=%d syncMode=%s\n",
testMask, stream, waitStart, syncModeString(syncMode));
size_t sizeBytes = numElements * sizeof(int);
@@ -60,55 +64,95 @@ void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode)
C_h[i] = -1; // initialize
}
hipStream_t stream = 0;
hipEvent_t neverCreated=0, neverRecorded, timingDisabled;
HIPCHECK(hipEventCreate(&neverRecorded));
HIPCHECK(hipEventCreateWithFlags(&timingDisabled, hipEventDisableTiming));
unsigned flags=0;
if (syncMode == syncOtherStream) {
HIPCHECK(hipStreamCreateWithFlags(&stream, flags));
}
hipEvent_t neverCreated=0;
hipEvent_t start, stop, neverRecorded;
hipEvent_t start, stop;
HIPCHECK(hipEventCreate(&start));
HIPCHECK(hipEventCreate(&stop));
HIPCHECK(hipEventCreate(&neverRecorded));
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, numElements);
HIPCHECK(hipEventRecord(timingDisabled, stream));
// sandwhich a kernel:
HIPCHECK(hipEventRecord(start, stream));
hipLaunchKernelGGL(HipTest::addCountReverse , dim3(blocks), dim3(threadsPerBlock), 0, stream, C_d, C_h, numElements, count);
HIPCHECK(hipEventRecord(stop, stream));
HIPCHECK(hipStreamSynchronize(stream)); // wait for recording to finish...
if (waitStart) {
HIPCHECK(hipEventSynchronize(start));
}
hipError_t expectedStopError = hipSuccess;
// How to wait for the events to finish:
switch (syncMode) {
case syncNone:
expectedStopError = hipErrorNotReady;
break;
case syncStream:
HIPCHECK(hipStreamSynchronize(stream)); // wait for recording to finish...
break;
case syncStopEvent:
HIPCHECK(hipEventSynchronize(stop));
break;
default:
assert(0);
};
float t;
HIPCHECK_API(hipEventElapsedTime(&t, neverCreated, stop), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, start, neverCreated), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, neverRecorded, stop), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, start, neverRecorded), hipErrorInvalidResourceHandle);
HIPCHECK(hipEventElapsedTime(&t, start, stop));
assert (t>0.0f);
printf ("time=%6.2f\n", t);
HIPCHECK(hipEventElapsedTime(&t, stop, start));
assert (t<0.0f);
printf ("negtime=%6.2f\n", t);
HIPCHECK(hipEventElapsedTime(&t, start, start));
assert (t==0.0f);
HIPCHECK(hipEventElapsedTime(&t, stop, stop));
assert (t==0.0f);
if (stream) {
HIPCHECK(hipStreamDestroy(stream));
hipError_t e = hipEventElapsedTime(&t, start, start);
if ((e != hipSuccess) && (e != hipErrorNotReady)) {
failed ("start event not in expected state, was %d=%s\n", e, hipGetErrorName(e));
}
if (e == hipSuccess)
assert (t==0.0f);
// stop usually ready unless we skipped the synchronization (syncNone)
HIPCHECK_API(hipEventElapsedTime(&t, stop, stop), expectedStopError);
if (e == hipSuccess)
assert (t==0.0f);
e = hipEventElapsedTime(&t, start, stop);
HIPCHECK_API(e, expectedStopError);
if (expectedStopError == hipSuccess)
assert (t>0.0f);
printf ("time=%6.2f error=%s\n", t, hipGetErrorName(e));
e = hipEventElapsedTime(&t, stop, start);
HIPCHECK_API(e, expectedStopError);
if (expectedStopError == hipSuccess)
assert (t<0.0f);
printf ("negtime=%6.2f error=%s\n", t, hipGetErrorName(e));
{
// Check some error conditions for incomplete events:
HIPCHECK_API(hipEventElapsedTime(&t, timingDisabled, stop), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, start, timingDisabled), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, neverCreated, stop), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, start, neverCreated), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, neverRecorded, stop), hipErrorInvalidResourceHandle);
HIPCHECK_API(hipEventElapsedTime(&t, start, neverRecorded), hipErrorInvalidResourceHandle);
}
HIPCHECK(hipEventDestroy(start));
HIPCHECK(hipEventDestroy(stop));
// Clear out everything:
HIPCHECK(hipDeviceSynchronize());
printf ("test: OK \n");
}
@@ -125,15 +169,22 @@ void runTests(int64_t numElements)
HIPCHECK(hipMalloc(&C_d, sizeBytes));
HIPCHECK(hipHostMalloc(&C_h, sizeBytes));
hipStream_t stream;
HIPCHECK(hipStreamCreateWithFlags(&stream, 0x0));
{
test (C_d, C_h, numElements, syncNone);
test (C_d, C_h, numElements, syncNullStream);
test (C_d, C_h, numElements, syncOtherStream);
//test (C_d, C_h, numElements, syncDevice);
//for (int waitStart=0; waitStart<2; waitStart++) {
for (int waitStart=1; waitStart>=0; waitStart--) {
unsigned W = waitStart ? 0x1000:0;
test (W | 0x01, C_d, C_h, numElements, 0 , waitStart, syncNone);
test (W | 0x02, C_d, C_h, numElements, stream, waitStart, syncNone);
test (W | 0x04, C_d, C_h, numElements, 0 , waitStart, syncStream);
test (W | 0x08, C_d, C_h, numElements, stream, waitStart, syncStream);
test (W | 0x10, C_d, C_h, numElements, 0, waitStart, syncStopEvent);
test (W | 0x20, C_d, C_h, numElements, stream, waitStart, syncStopEvent);
}
HIPCHECK(hipStreamDestroy(stream));
HIPCHECK(hipFree(C_d));
HIPCHECK(hipHostFree(C_h));
}
@@ -143,7 +194,7 @@ int main(int argc, char *argv[])
{
HipTest::parseStandardArguments(argc, argv, true /*failOnUndefinedArg*/);
runTests(4000000);
runTests(80000000);
passed();
}
+55 -17
ファイルの表示
@@ -56,9 +56,27 @@ const char *syncModeString(int syncMode) {
};
void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode, bool expectMismatch)
void test(unsigned testMask, int *C_d, int *C_h, int64_t numElements, SyncMode syncMode, bool expectMismatch)
{
printf ("\ntest: syncMode=%s expectMismatch=%d\n", syncModeString(syncMode), expectMismatch);
// This test sends a long-running kernel to the null stream, then tests to see if the
// specified synchronization technique is effective.
//
// Some syncMode are not expected to correctly sync (for example "syncNone"). in these
// cases the test sets expectMismatch and the check logic below will attempt to ensure that
// the undesired synchronization did not occur - ie ensure the kernel is still running and did
// not yet update the stop event. This can be tricky since if the kernel runs fast enough it
// may complete before the check. To prevent this, the addCountReverse has a count parameter
// which causes it to loop repeatedly, and the results are checked in reverse order.
//
// Tests with expectMismatch=true should ensure the kernel finishes correctly. This results
// are checked and we test to make sure stop event has completed.
if (!(testMask & p_tests)) {
return;
}
printf ("\ntest 0x%02x: syncMode=%s expectMismatch=%d\n",
testMask, syncModeString(syncMode), expectMismatch);
size_t sizeBytes = numElements * sizeof(int);
@@ -72,13 +90,15 @@ void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode, bool expec
hipStream_t otherStream = 0;
unsigned flags = (syncMode == syncMarkerThenOtherNonBlockingStream) ? hipStreamNonBlocking : hipStreamDefault;
HIPCHECK(hipStreamCreateWithFlags(&otherStream, flags));
hipEvent_t e;
HIPCHECK(hipEventCreate(&e));
hipEvent_t stop, otherStreamEvent;
HIPCHECK(hipEventCreate(&stop));
HIPCHECK(hipEventCreate(&otherStreamEvent));
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, numElements);
// Launch kernel into null stream, should result in C_h == count.
hipLaunchKernelGGL(HipTest::addCountReverse , dim3(blocks), dim3(threadsPerBlock), 0, 0 /*stream*/, C_d, C_h, numElements, count);
HIPCHECK(hipEventRecord(stop, 0/*default*/));
switch (syncMode) {
case syncNone:
@@ -92,7 +112,10 @@ void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode, bool expec
break;
case syncMarkerThenOtherStream:
case syncMarkerThenOtherNonBlockingStream:
HIPCHECK(hipEventRecord(e, otherStream)); // this may wait for NULL stream depending hipStreamNonBlocking flag above
// this may wait for NULL stream depending hipStreamNonBlocking flag above
HIPCHECK(hipEventRecord(otherStreamEvent, otherStream));
HIPCHECK(hipStreamSynchronize(otherStream));
break;
case syncDevice:
@@ -102,6 +125,14 @@ void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode, bool expec
assert(0);
};
hipError_t done = hipEventQuery(stop);
if (expectMismatch) {
assert (done == hipErrorNotReady);
} else {
assert (done == hipSuccess);
}
int mismatches = 0;
int expected = init0 + count;
for (int i=0; i<numElements; i++) {
@@ -121,17 +152,15 @@ void test(int *C_d, int *C_h, int64_t numElements, SyncMode syncMode, bool expec
HIPCHECK(hipStreamDestroy(otherStream));
HIPCHECK(hipEventDestroy(e));
HIPCHECK(hipEventDestroy(stop));
HIPCHECK(hipEventDestroy(otherStreamEvent));
HIPCHECK(hipDeviceSynchronize());
printf ("test: OK - %d mismatches (%6.2f%%)\n", mismatches, ((double)(mismatches)*100.0)/numElements);
}
void testEventRecord()
{
}
void runTests(int64_t numElements)
{
size_t sizeBytes = numElements * sizeof(int);
@@ -145,12 +174,18 @@ void runTests(int64_t numElements)
{
test (C_d, C_h, numElements, syncNone, true /*expectMismatch*/);
test (C_d, C_h, numElements, syncNullStream, false /*expectMismatch*/);
test (C_d, C_h, numElements, syncOtherStream, true /*expectMismatch*/);
test (C_d, C_h, numElements, syncDevice, false /*expectMismatch*/);
test (C_d, C_h, numElements, syncMarkerThenOtherStream, false /*expectMismatch*/);
test (C_d, C_h, numElements, syncMarkerThenOtherNonBlockingStream, true /*expectMismatch*/);
test (0x01, C_d, C_h, numElements, syncNone, true /*expectMismatch*/);
test (0x02, C_d, C_h, numElements, syncNullStream, false /*expectMismatch*/);
test (0x04, C_d, C_h, numElements, syncOtherStream, true /*expectMismatch*/);
test (0x08, C_d, C_h, numElements, syncDevice, false /*expectMismatch*/);
// Sending a marker to to null stream may synchronize the otherStream
// - other created with hipStreamNonBlocking=0 : synchronization, should match
// - other created with hipStreamNonBlocking=1 : no synchronization, may mismatch
test (0x10, C_d, C_h, numElements, syncMarkerThenOtherStream, false /*expectMismatch*/);
// TODO - review why this test seems flaky
//test (0x20, C_d, C_h, numElements, syncMarkerThenOtherNonBlockingStream, true /*expectMismatch*/);
}
@@ -161,6 +196,9 @@ void runTests(int64_t numElements)
int main(int argc, char *argv[])
{
// Can' destroy the default stream:// TODO - move to another test
HIPCHECK_API(hipStreamDestroy(0), hipErrorInvalidResourceHandle);
HipTest::parseStandardArguments(argc, argv, true /*failOnUndefinedArg*/);
runTests(40000000);