Add initial HIP_SYNC_NULL_STREAM=0 mode.

This eliminates host-synchronization for null stream.  Instead, the
null-stream uses GPU-side events to wait for other streams.
Default is OFF pending additional testing.

Add enhanced null-stream test.

Also refine HIP_TRACE_API.


[ROCm/hip commit: 27877f8854]
This commit is contained in:
Ben Sander
2017-05-12 17:04:23 -05:00
والد cfe81dfbf4
کامیت a55ce5bee4
11فایلهای تغییر یافته به همراه320 افزوده شده و 96 حذف شده
@@ -27,8 +27,9 @@ THE SOFTWARE.
#include "hip/hip_runtime.h"
#include "test_common.h"
#include <vector>
unsigned p_streams = 6;
unsigned p_streams =16;
int p_repeat = 10;
int p_db = 0;
template <typename T>
@@ -45,7 +46,7 @@ vectorADDRepeat(hipLaunchParm lp,
for (int j=1; j<=repeat;j++) {
for (size_t i=offset; i<NELEM; i+=stride) {
C_d[i] = A_d[i]*j + B_d[i]*j;
C_d[i] = A_d[i]*j + B_d[i]*j;
}
};
}
@@ -63,6 +64,10 @@ public:
void enqueAsync();
void queryUntilComplete();
void reset();
void H2D();
void D2H();
public:
T *_A_h;
@@ -91,8 +96,33 @@ Streamer<T>::Streamer(size_t numElements, bool useNullStream) :
HIPCHECK(hipStreamCreate(&_stream));
}
HIPCHECK(hipEventCreate(&_event));
H2D();
};
template <typename T>
void Streamer<T>::H2D()
{
HIPCHECK(hipMemcpy(_A_d, _A_h, _numElements*sizeof(T), hipMemcpyHostToDevice));
HIPCHECK(hipMemcpy(_B_d, _B_h, _numElements*sizeof(T), hipMemcpyHostToDevice));
}
template <typename T>
void Streamer<T>::D2H()
{
HIPCHECK(hipMemcpy(_C_h, _C_d, _numElements*sizeof(T), hipMemcpyDeviceToHost));
}
template <typename T>
void Streamer<T>::reset()
{
HipTest::setDefaultData(_numElements, _A_h, _B_h, _C_h);
H2D();
}
template <typename T>
void Streamer<T>::enqueAsync()
{
@@ -131,6 +161,10 @@ void parseMyArguments(int argc, char *argv[])
if (++i >= argc || !HipTest::parseUInt(argv[i], &p_streams)) {
failed("Bad streams argument");
}
} else if (!strcmp(arg, "--repeat") || (!strcmp(arg, "-r"))) {
if (++i >= argc || !HipTest::parseInt(argv[i], &p_repeat)) {
failed("Bad repeat argument");
}
} else {
failed("Bad argument '%s'", arg);
}
@@ -138,6 +172,15 @@ void parseMyArguments(int argc, char *argv[])
};
void
printBuffer(std::string name, int *f, size_t numElements)
{
std::cout << name << "\n";
for (size_t i=0; i<numElements; i++) {
printf ("%5zu: %d\n", i, f[i]);
}
}
@@ -147,54 +190,111 @@ int main(int argc, char *argv[])
HipTest::parseStandardArguments(argc, argv, false);
parseMyArguments(argc, argv);
typedef Streamer<float> FloatStreamer;
typedef Streamer<int> IntStreamer;
std::vector<FloatStreamer *> streamers;
std::vector<IntStreamer *> streamers;
size_t numElements = N;
float *expected_H = (float*)malloc(numElements*sizeof(float));
int *expected_H = (int*)malloc(numElements*sizeof(int));
auto nullStreamer = new FloatStreamer(numElements, true);
auto nullStreamer = new IntStreamer(numElements, true);
// Expected resultr - last streamer runs vectorADDRepeat, then nullstreamer adds lastStreamer->_C_d + lastStreamer->_C_d
for (size_t i=0; i<numElements; i++) {
expected_H[i] = nullStreamer->_A_h[i]*p_repeat + nullStreamer->_B_h[i] * p_repeat;
expected_H[i] = ((nullStreamer->_A_h[i])*p_repeat + (nullStreamer->_B_h[i]) * p_repeat) *2;
}
for (int i=0; i<p_streams; i++) {
FloatStreamer * s = new FloatStreamer(numElements);
IntStreamer * s = new IntStreamer(numElements);
streamers.push_back(s);
}
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, numElements);
if (p_tests & 0x1) {
printf ("==> Test 0x1 runAsnc\n");
for (int i=0; i<p_streams; i++) {
streamers[i]->enqueAsync();
for (int s=1; s<p_streams; s++) {
if (p_tests & (1<<s)) {
printf ("==> Test %x runAsnc, #streams=%d\n", (1<<s), s);
nullStreamer->reset();
for (int i=0; i<s; i++) {
streamers[i]->enqueAsync();
}
auto lastStreamer = streamers[s - 1];
// Dispatch to NULL stream, should wait for prior async activity to complete before beginning:
hipLaunchKernel(vectorADDRepeat, dim3(blocks), dim3(threadsPerBlock), 0, 0/*nullstream*/, lastStreamer->_C_d, lastStreamer->_C_d, nullStreamer->_C_d, numElements, 1/*repeat*/);
if (p_db) {
HIPCHECK(hipDeviceSynchronize());
lastStreamer->D2H();
printBuffer("lastStream _A_h", lastStreamer->_A_h, min(numElements, size_t(20)));
printBuffer("lastStream _B_h", lastStreamer->_B_h, min(numElements, size_t(20)));
printBuffer("lastStream _C_h", lastStreamer->_C_h, min(numElements, size_t(20)));
}
nullStreamer->D2H();
HIPCHECK(hipDeviceSynchronize());
HipTest::checkTest(expected_H, nullStreamer->_C_h, numElements);
}
auto lastStreamer = streamers[p_streams - 1];
// Dispatch to NULL stream, should wait for prior async activity to complete.
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, numElements);
hipLaunchKernel(vectorADDRepeat, dim3(blocks), dim3(threadsPerBlock), 0, 0/*nullstream*/, lastStreamer->_C_d, lastStreamer->_C_d, nullStreamer->_C_d, numElements, 1/*repeat*/);
HIPCHECK(hipMemcpy(nullStreamer->_C_h, nullStreamer->_C_d, numElements*sizeof(float), hipMemcpyDeviceToHost));
HIPCHECK(hipStreamSynchronize(0));
HipTest::checkTest(expected_H, nullStreamer->_C_h, numElements);
}
if (p_tests & 0x2) {
printf ("==> Test 0x2 runAsnc-odd-only\n");
for (int i=0; i<p_streams; i++) {
if (i & 0x1) {
streamers[i]->enqueAsync();
for (int s=1; s<p_streams; s+=2) {
unsigned tmask = (0x10000 | (1<<s));
if (p_tests & tmask) {
nullStreamer->reset();
printf ("==> Test %x runAsnc-odd-only, #streams=%d\n", tmask, s);
for (int i=0; i<s; i++) {
// RUn just odd streams so we have some empty ones to examine/optimize:
if (i & 0x1) {
streamers[i]->enqueAsync();
}
}
auto lastStreamer = streamers[s - 1];
// Dispatch to NULL stream, should wait for prior async activity to complete before beginning:
hipLaunchKernel(vectorADDRepeat, dim3(blocks), dim3(threadsPerBlock), 0, 0/*nullstream*/, lastStreamer->_C_d, lastStreamer->_C_d, nullStreamer->_C_d, numElements, 1/*repeat*/);
nullStreamer->D2H();
HIPCHECK(hipDeviceSynchronize());
HipTest::checkTest(expected_H, nullStreamer->_C_h, numElements);
}
}
// Expected resultr - last streamer runs vectorADDRepeat
for (size_t i=0; i<numElements; i++) {
expected_H[i] = ((nullStreamer->_A_h[i])*p_repeat + (nullStreamer->_B_h[i]) * p_repeat);
}
if (p_tests & 0x20000) {
assert (p_streams >=2); // need a couple streams in order to run this test.
nullStreamer->reset();
printf ("\n==> Test hipStreamSynchronize with defaultStream \n");
// Enqueue a long-running job to stream1
streamers[0]->enqueAsync();
// Check to see if synchronizing on a null stream synchronizes all other streams or just the null stream.
// This function follows null stream semantics and will wait for all other blocking streams before returning.
// This will wait on the host
HIPCHECK(hipStreamSynchronize(0));
// Copy with stream1, this could go async if the streamSync doesn't synchronize ALL the streams.
HIPCHECK(hipMemcpyAsync(streamers[0]->_C_h, streamers[0]->_C_d, streamers[0]->_numElements*sizeof(int), hipMemcpyDeviceToHost, streamers[1]->_stream));
HIPCHECK(hipDeviceSynchronize());
HipTest::checkTest(expected_H, streamers[0]->_C_h, numElements);
}
passed();
}