EXSWHTEC-173 - Implement tests for Graph Node dependencies APIs (#50)

Recreation of github PR https://github.com/ROCm-Developer-Tools/hip-tests/pull/50

Change-Id: I65707d9d0bfa12c08d82779c1402215f22d7815b
Этот коммит содержится в:
Nives Vukovic
2023-11-16 13:04:32 +00:00
коммит произвёл Rakesh Roy
родитель 7cfc4a3664
Коммит 91ee1399df
16 изменённых файлов: 3829 добавлений и 1471 удалений
+136 -182
Просмотреть файл
@@ -17,113 +17,99 @@ OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios
------------------
Functional ::
1) Add nodes to graph and get nodes. Verify the added nodes are present in returned list.
2) Pass nodes as nullptr and verify numNodes returns actual number of nodes added to graph.
3) If numNodes passed is greater than the actual number of nodes, the remaining entries in nodes
will be set to NULL, and the number of nodes actually obtained will be returned in numNodes.
4) Begin stream capture and push operations to stream. Verify nodes of created graph are matching the
operations pushed.
Argument Validation ::
1) Pass graph as nullptr and verify api returns error code.
2) Pass numNodes as nullptr and other params as valid values. Expect api to return error code.
3) When there are no nodes in graph, expect numNodes to be set to zero.
4) Pass numNodes less than actual number of nodes. Expect api to populate requested number of node entries
and does update numNodes.
*/
#include <functional>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
#include <hip_test_defgroups.hh>
#include "graph_dependency_common.hh"
/**
* Functional Test for hipGraphGetNodes API fetching node list
* @addtogroup hipGraphGetNodes hipGraphGetNodes
* @{
* @ingroup GraphTest
* `hipGraphGetNodes(hipGraph_t graph, hipGraphNode_t *nodes, size_t *numNodes)` -
* returns graph nodes
*/
TEST_CASE("Unit_hipGraphGetNodes_Functional") {
namespace {
inline constexpr size_t kNumOfNodes = 7;
} // anonymous namespace
/**
* Test Description
* ------------------------
* - Functional test to validate API for different number of nodes:
* -# Validate number of nodes
* -# Validate node list when numNodes = num of nodes
* -# Validate node list when numNodes < num of nodes
* -# Validate node list when numNodes > num of nodes
* -# Validate numNodes is 0 when no nodes in graph
* Test source
* ------------------------
* - catch\unit\graph\hipGraphGetNodes.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 5.2
*/
TEST_CASE("Unit_hipGraphGetNodes_Positive_Functional") {
using namespace std::placeholders;
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
constexpr auto addlEntries = 4;
hipGraph_t graph;
hipGraphNode_t memcpyNode, kernelNode;
hipKernelNodeParams kernelNodeParams{};
hipStream_t streamForGraph;
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
std::vector<hipGraphNode_t> dependencies, nodelist;
hipGraphExec_t graphExec;
size_t NElem{N};
HIP_CHECK(hipStreamCreate(&streamForGraph));
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyNode);
nodelist.push_back(memcpyNode);
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyNode);
nodelist.push_back(memcpyNode);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
void* kernelArgs[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernelNode, graph, dependencies.data(),
dependencies.size(), &kernelNodeParams));
dependencies.clear();
dependencies.push_back(kernelNode);
nodelist.push_back(kernelNode);
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, dependencies.data(),
dependencies.size(), C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
nodelist.push_back(memcpyNode);
std::vector<hipGraphNode_t> from_nodes;
std::vector<hipGraphNode_t> to_nodes;
std::vector<hipGraphNode_t> nodelist;
graphNodesCommon(graph, A_h, A_d, B_h, B_d, C_h, C_d, N, from_nodes, to_nodes, nodelist);
// Create dependencies
HIP_CHECK(hipGraphAddDependencies(graph, &from_nodes[0], &to_nodes[0], 6));
// Get numNodes by passing nodes as nullptr.
// verify : numNodes is set to actual number of nodes added
size_t numNodes{};
HIP_CHECK(hipGraphGetNodes(graph, nullptr, &numNodes));
INFO("Num of nodes returned by GetNodes : " << numNodes);
REQUIRE(numNodes == nodelist.size());
// Request for extra/additional nodes.
// verify : totNodes is reset to actual number of nodes
// verify : additional entries in nodes are set to nullptr
size_t totNodes = numNodes + addlEntries;
int numBytes = sizeof(hipGraphNode_t) * totNodes;
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
REQUIRE(nodes != nullptr);
HIP_CHECK(hipGraphGetNodes(graph, nodes, &totNodes));
REQUIRE(totNodes == nodelist.size());
for (auto i = numNodes; i < numNodes + addlEntries; i++) {
REQUIRE(nodes[i] == nullptr);
// Get numNodes by passing nodes as nullptr.
// Verify numNodes is set to actual number of nodes added
// Scenario 1
SECTION("Validate number of nodes") {
HIP_CHECK(hipGraphGetNodes(graph, nullptr, &numNodes));
INFO("Num of nodes returned by GetNodes : " << numNodes);
REQUIRE(numNodes == nodelist.size());
}
// Verify added nodes are present in the node entries returned
for (auto Node : nodelist) {
bool found = false;
for (size_t i = 0; i < numNodes; i++) {
if (Node == nodes[i]) {
found = true;
break;
}
}
// Scenario 2
SECTION("Validate node list when numNodes = num of nodes") {
validateGraphNodesCommon(std::bind(hipGraphGetNodes, graph, _1, _2), nodelist, kNumOfNodes,
GraphGetNodesTest::equalNumNodes);
}
if (!found) {
INFO("Added node " << Node << " not present in returned list");
REQUIRE(false);
}
// Scenario 3
SECTION("Validate node list when numNodes < num of nodes") {
validateGraphNodesCommon(std::bind(hipGraphGetNodes, graph, _1, _2), nodelist, kNumOfNodes - 1,
GraphGetNodesTest::lesserNumNodes);
}
// Scenario 4
SECTION("Validate node list when numNodes > num of nodes") {
validateGraphNodesCommon(std::bind(hipGraphGetNodes, graph, _1, _2), nodelist, kNumOfNodes + 1,
GraphGetNodesTest::greaterNumNodes);
}
// Scenario 5
SECTION("Validate numNodes is 0 when no nodes in graph") {
hipGraph_t emptyGraph{};
HIP_CHECK(hipGraphCreate(&emptyGraph, 0));
HIP_CHECK(hipGraphGetNodes(emptyGraph, nullptr, &numNodes));
REQUIRE(numNodes == 0);
HIP_CHECK(hipGraphDestroy(emptyGraph));
}
// Instantiate and launch the graph
@@ -138,50 +124,46 @@ TEST_CASE("Unit_hipGraphGetNodes_Functional") {
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
free(nodes);
}
/**
* Begin stream capture and push operations to stream.
* Verify nodes of created graph are matching the operations pushed.
* Test Description
* ------------------------
* - Test to verify nodes of created graph are matching the captured operations
* Test source
* ------------------------
* - catch\unit\graph\hipGraphGetNodes.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 5.2
*/
TEST_CASE("Unit_hipGraphGetNodes_CapturedStream") {
TEST_CASE("Unit_hipGraphGetNodes_Positive_CapturedStream") {
hipGraph_t graph{nullptr};
hipGraphExec_t graphExec{nullptr};
constexpr unsigned blocks = 512;
constexpr unsigned threadsPerBlock = 256;
constexpr size_t N = 1000000;
size_t Nbytes = N * sizeof(float);
constexpr int numMemcpy{2}, numKernel{1}, numMemset{1};
constexpr int numMemcpy{3}, numKernel{2}, numMemset{2};
int cntMemcpy{}, cntKernel{}, cntMemset{};
hipStream_t stream, streamForGraph;
hipStream_t streamForGraph;
hipGraphNodeType nodeType;
float *A_d, *C_d;
float *A_h, *C_h;
A_h = reinterpret_cast<float*>(malloc(Nbytes));
C_h = reinterpret_cast<float*>(malloc(Nbytes));
REQUIRE(A_h != nullptr);
REQUIRE(C_h != nullptr);
HIP_CHECK(hipMalloc(&A_d, Nbytes));
HIP_CHECK(hipMalloc(&C_d, Nbytes));
REQUIRE(A_d != nullptr);
REQUIRE(C_d != nullptr);
float *A_d, *B_d, *C_d;
float *A_h, *B_h, *C_h;
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
HIP_CHECK(hipStreamCreate(&streamForGraph));
// Initialize input buffer
for (size_t i = 0; i < N; ++i) {
A_h[i] = 3.146f + i; // Pi
A_h[i] = 3.146f + i; // Pi
B_h[i] = 3.146f + i; // Pi
}
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamEndCapture(stream, &graph));
// Create streams and events
StreamsGuard streams(3);
EventsGuard events(3);
// Capture stream
captureNodesCommon(graph, A_h, A_d, B_h, B_d, C_h, C_d, N, streams.stream_list(),
events.event_list());
REQUIRE(graph != nullptr);
size_t numNodes{};
@@ -190,7 +172,7 @@ TEST_CASE("Unit_hipGraphGetNodes_CapturedStream") {
REQUIRE(numNodes == numMemcpy + numKernel + numMemset);
int numBytes = sizeof(hipGraphNode_t) * numNodes;
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t*>(malloc(numBytes));
REQUIRE(nodes != nullptr);
HIP_CHECK(hipGraphGetNodes(graph, nodes, &numNodes));
@@ -227,99 +209,71 @@ TEST_CASE("Unit_hipGraphGetNodes_CapturedStream") {
// Validate the computation
for (size_t i = 0; i < N; i++) {
if (C_h[i] != A_h[i] * A_h[i]) {
INFO("A and C not matching at " << i << " C_h[i] " << C_h[i]
<< " A_h[i] " << A_h[i]);
if (C_h[i] != A_h[i] + B_h[i]) {
INFO("C not matching at " << i << " C_h[i] " << C_h[i] << " A_h[i] + B_h[i] "
<< A_h[i] + B_h[i]);
REQUIRE(false);
}
}
HIP_CHECK(hipStreamDestroy(streamForGraph));
HIP_CHECK(hipStreamDestroy(stream));
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
free(A_h);
free(C_h);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
free(nodes);
HIP_CHECK(hipFree(A_d));
HIP_CHECK(hipFree(C_d));
}
/**
* Test performs api parameter validation by passing various values
* as input and output parameters and validates the behavior.
* Test will include both negative and positive scenarios.
* Test Description
* ------------------------
* - Test to verify API behavior with invalid arguments:
* -# Null Graph
* -# Graph is uninitialized
* -# numNodes as nullptr
* Test source
* ------------------------
* - catch\unit\graph\hipGraphGetNodes.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 5.2
*/
TEST_CASE("Unit_hipGraphGetNodes_ParamValidation") {
hipStream_t stream{nullptr};
TEST_CASE("Unit_hipGraphGetNodes_Negative_Parameters") {
hipGraph_t graph{nullptr};
constexpr unsigned blocks = 512;
constexpr unsigned threadsPerBlock = 256;
constexpr size_t N = 1000000;
size_t Nbytes = N * sizeof(float), numNodes{};
float *A_d, *C_d;
float *A_h, *C_h;
A_h = reinterpret_cast<float*>(malloc(Nbytes));
C_h = reinterpret_cast<float*>(malloc(Nbytes));
REQUIRE(A_h != nullptr);
REQUIRE(C_h != nullptr);
HIP_CHECK(hipMalloc(&A_d, Nbytes));
HIP_CHECK(hipMalloc(&C_d, Nbytes));
REQUIRE(A_d != nullptr);
REQUIRE(C_d != nullptr);
size_t numNodes{0};
HIP_CHECK(hipGraphCreate(&graph, 0));
hipEvent_t event_start, event_end;
HIP_CHECK(hipEventCreateWithFlags(&event_start, hipEventDisableTiming));
HIP_CHECK(hipEventCreateWithFlags(&event_end, hipEventDisableTiming));
// create event record nodes
hipGraphNode_t event_node_start, event_node_end;
HIP_CHECK(hipGraphAddEventRecordNode(&event_node_start, graph, nullptr, 0, event_start));
HIP_CHECK(hipGraphAddEventRecordNode(&event_node_end, graph, nullptr, 0, event_end));
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamEndCapture(stream, &graph));
HIP_CHECK(hipGraphGetNodes(graph, nullptr, &numNodes));
INFO("Num of nodes returned by GetNodes : " << numNodes);
int numBytes = sizeof(hipGraphNode_t) * numNodes;
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t*>(malloc(numBytes));
REQUIRE(nodes != nullptr);
SECTION("graph as nullptr") {
hipError_t ret = hipGraphGetNodes(nullptr, nodes, &numNodes);
REQUIRE(ret == hipErrorInvalidValue);
HIP_CHECK_ERROR(hipGraphGetNodes(nullptr, nodes, &numNodes), hipErrorInvalidValue);
}
SECTION("graph is uninitialized") {
hipGraph_t graph_uninit{};
HIP_CHECK_ERROR(hipGraphGetNodes(graph_uninit, nodes, &numNodes), hipErrorInvalidValue);
}
SECTION("numNodes as nullptr") {
hipError_t ret = hipGraphGetNodes(graph, nodes, nullptr);
REQUIRE(ret == hipErrorInvalidValue);
}
SECTION("no nodes in graph") {
hipGraph_t emptyGraph{};
HIP_CHECK(hipGraphCreate(&emptyGraph, 0));
HIP_CHECK(hipGraphGetNodes(emptyGraph, nullptr, &numNodes));
REQUIRE(numNodes == 0);
}
SECTION("numNodes less than actual number of nodes") {
size_t numPartNodes = numNodes - 1;
hipGraphNodeType nodeType;
HIP_CHECK(hipGraphGetNodes(graph, nodes, &numPartNodes));
// verify numPartNodes is unchanged
REQUIRE(numPartNodes == numNodes - 1);
// verify partial node list returned has valid nodes
for (size_t i = 0; i < numPartNodes; i++) {
HIP_CHECK(hipGraphNodeGetType(nodes[i], &nodeType));
REQUIRE(nodeType >= 0);
REQUIRE(nodeType < hipGraphNodeTypeCount);
}
HIP_CHECK_ERROR(hipGraphGetNodes(graph, nodes, nullptr), hipErrorInvalidValue);
}
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(stream));
free(A_h);
free(C_h);
HIP_CHECK(hipEventDestroy(event_end));
HIP_CHECK(hipEventDestroy(event_start));
free(nodes);
HIP_CHECK(hipFree(A_d));
HIP_CHECK(hipFree(C_d));
}