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]
Tento commit je obsažen v:
Ben Sander
2017-05-12 17:04:23 -05:00
rodič cfe81dfbf4
revize a55ce5bee4
11 změnil soubory, kde provedl 320 přidání a 96 odebrání
+128 -28
Zobrazit soubor
@@ -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();
}
+53 -7
Zobrazit soubor
@@ -184,6 +184,20 @@ addCountReverse( const T *A_d,
}
void setDefaultData(size_t numElements, T *A_h, T* B_h, T *C_h)
{
// Initialize the host data:
for (size_t i=0; i<numElements; i++) {
if (A_h)
(A_h)[i] = 3.146f + i; // Pi
if (B_h)
(B_h)[i] = 1.618f + i; // Phi
if (C_h)
(C_h)[i] = 0.0f + i;
}
}
template <typename T>
void initArraysForHost(T **A_h, T **B_h, T **C_h,
size_t N, bool usePinnedHost=false)
@@ -217,15 +231,10 @@ void initArraysForHost(T **A_h, T **B_h, T **C_h,
}
}
// Initialize the host data:
for (size_t i=0; i<N; i++) {
if (A_h)
(*A_h)[i] = 3.146f + i; // Pi
if (B_h)
(*B_h)[i] = 1.618f + i; // Phi
}
setDefaultData(N, A_h ? *A_h : nullptr, B_h ? *B_h : nullptr, C_h ? *C_h : nullptr);
}
template <typename T>
void initArrays(T **A_d, T **B_d, T **C_d,
T **A_h, T **B_h, T **C_h,
@@ -367,6 +376,43 @@ void checkVectorADD(T* A_h, T* B_h, T* result_H, size_t N, bool expectMatch=true
}
// Assumes C_h contains vector add of A_h + B_h
// Calls the test "failed" macro if a mismatch is detected.
template <typename T>
void checkTest(T* expected_H, T* result_H, size_t N, bool expectMatch=true)
{
size_t mismatchCount = 0;
size_t firstMismatch = 0;
size_t mismatchesToPrint = 10;
for (size_t i=0; i<N; i++) {
if (result_H[i] != expected_H[i]) {
if (mismatchCount == 0) {
firstMismatch = i;
}
mismatchCount++;
if ((mismatchCount <= mismatchesToPrint) && expectMatch) {
std::cout << std::fixed << std::setprecision(32);
std::cout << "At " << i << std::endl;
std::cout << " Computed:" << result_H[i] << std::endl;
std::cout << " Expected:" << expected_H[i] << std::endl;
}
}
}
if (expectMatch) {
if (mismatchCount) {
fprintf(stderr, "%zu mismatches ; first at index:%zu\n", mismatchCount, firstMismatch);
//failed("%zu mismatches ; first at index:%zu\n", mismatchCount, firstMismatch);
}
} else {
if (mismatchCount == 0) {
failed("expected mismatches but did not detect any!");
}
}
}
//---
struct Pinned {
static const bool isPinned = true;