Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions sycl/source/detail/graph_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,16 @@ class graph_impl {
if (PropList.has_property<property::graph::no_cycle_check>()) {
MSkipCycleChecks = true;
}
if (SyclDevice.get_info<
ext::oneapi::experimental::info::device::graph_support>() ==
info::graph_support_level::unsupported) {
std::stringstream Stream;
Stream << SyclDevice.get_backend();
std::string BackendString = Stream.str();
throw sycl::exception(
sycl::make_error_code(errc::invalid),
BackendString + " backend is not supported by SYCL Graph extension.");
}
}

/// Insert node into list of root nodes.
Expand Down
35 changes: 35 additions & 0 deletions sycl/test-e2e/Graph/exception_unsupported_backend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %{build} -o %t.out
// RUN: %{run} %t.out

// Tests the ability to finalize a empty command graph
// The test checks that invalid exception is thrown
// when trying to create a graph with an unsupported backend.

#include "graph_common.hpp"

int GetUnsupportedBackend(const sycl::device &Dev) {
// Return 1 if the device backend is unsupported or 0 else.
// 0 does not prevent another device to be picked as a second choice
return Dev.get_info<
ext::oneapi::experimental::info::device::graph_support>() ==
ext::oneapi::experimental::info::graph_support_level::unsupported;
}

int main() {
sycl::device Dev{GetUnsupportedBackend};
queue Queue{Dev};

if (Dev.get_info<ext::oneapi::experimental::info::device::graph_support>() !=
ext::oneapi::experimental::info::graph_support_level::unsupported)
return 0;

std::error_code ExceptionCode = make_error_code(sycl::errc::success);
try {
exp_ext::command_graph Graph{Queue.get_context(), Dev};
} catch (exception &Exception) {
ExceptionCode = Exception.code();
}
assert(ExceptionCode == sycl::errc::invalid);

return 0;
}
53 changes: 27 additions & 26 deletions sycl/unittests/Extensions/CommandGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <detail/config.hpp>
#include <helpers/PiMock.hpp>
#include <helpers/ScopedEnvVar.hpp>
#include <helpers/TestKernel.hpp>

#include <gtest/gtest.h>

Expand Down Expand Up @@ -43,7 +44,7 @@ TEST_F(CommandGraphTest, AddNode) {
ASSERT_TRUE(GraphImpl->MRoots.empty());

auto Node1 = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
ASSERT_NE(sycl::detail::getSyclObjImpl(Node1), nullptr);
ASSERT_FALSE(sycl::detail::getSyclObjImpl(Node1)->isEmpty());
ASSERT_EQ(GraphImpl->MRoots.size(), 1lu);
Expand Down Expand Up @@ -98,17 +99,17 @@ TEST_F(CommandGraphTest, Finalize) {
sycl::buffer<int> Buf(1);
auto Node1 = Graph.add([&](sycl::handler &cgh) {
sycl::accessor A(Buf, cgh, sycl::write_only, sycl::no_init);
cgh.single_task<class TestKernel1>([=]() { A[0] = 1; });
cgh.single_task<TestKernel<>>([]() {});
});

// Add independent node
auto Node2 = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

// Add a node that depends on Node1 due to the accessor
auto Node3 = Graph.add([&](sycl::handler &cgh) {
sycl::accessor A(Buf, cgh, sycl::write_only, sycl::no_init);
cgh.single_task<class TestKernel2>([=]() { A[0] = 3; });
cgh.single_task<TestKernel<>>([]() {});
});

// Guarantee order of independent nodes 1 and 2
Expand All @@ -134,7 +135,7 @@ TEST_F(CommandGraphTest, MakeEdge) {

// Add two independent nodes
auto Node1 = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
auto Node2 = Graph.add([&](sycl::handler &cgh) {});
ASSERT_EQ(GraphImpl->MRoots.size(), 2ul);
ASSERT_TRUE(sycl::detail::getSyclObjImpl(Node1)->MSuccessors.empty());
Expand Down Expand Up @@ -228,7 +229,7 @@ TEST_F(CommandGraphTest, BeginEndRecording) {
TEST_F(CommandGraphTest, GetCGCopy) {
auto Node1 = Graph.add([&](sycl::handler &cgh) {});
auto Node2 = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); },
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); },
{experimental::property::node::depends_on(Node1)});

// Get copy of CG of Node2 and check equality
Expand All @@ -250,21 +251,21 @@ TEST_F(CommandGraphTest, GetCGCopy) {
TEST_F(CommandGraphTest, SubGraph) {
// Add sub-graph with two nodes
auto Node1Graph = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
auto Node2Graph = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); },
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); },
{experimental::property::node::depends_on(Node1Graph)});
auto GraphExec = Graph.finalize();

// Add node to main graph followed by sub-graph and another node
experimental::command_graph MainGraph(Queue.get_context(), Dev);
auto Node1MainGraph = MainGraph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
auto Node2MainGraph =
MainGraph.add([&](handler &CGH) { CGH.ext_oneapi_graph(GraphExec); },
{experimental::property::node::depends_on(Node1MainGraph)});
auto Node3MainGraph = MainGraph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); },
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); },
{experimental::property::node::depends_on(Node2MainGraph)});

// Assert order of the added sub-graph
Expand Down Expand Up @@ -302,10 +303,10 @@ TEST_F(CommandGraphTest, RecordSubGraph) {
// Record sub-graph with two nodes
Graph.begin_recording(Queue);
auto Node1Graph = Queue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
auto Node2Graph = Queue.submit([&](sycl::handler &cgh) {
cgh.depends_on(Node1Graph);
cgh.single_task<class TestKernel>([]() {});
cgh.single_task<TestKernel<>>([]() {});
});
Graph.end_recording(Queue);
auto GraphExec = Graph.finalize();
Expand All @@ -314,14 +315,14 @@ TEST_F(CommandGraphTest, RecordSubGraph) {
experimental::command_graph MainGraph(Queue.get_context(), Dev);
MainGraph.begin_recording(Queue);
auto Node1MainGraph = Queue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
auto Node2MainGraph = Queue.submit([&](handler &cgh) {
cgh.depends_on(Node1MainGraph);
cgh.ext_oneapi_graph(GraphExec);
});
auto Node3MainGraph = Queue.submit([&](sycl::handler &cgh) {
cgh.depends_on(Node2MainGraph);
cgh.single_task<class TestKernel>([]() {});
cgh.single_task<TestKernel<>>([]() {});
});
MainGraph.end_recording(Queue);

Expand Down Expand Up @@ -371,7 +372,7 @@ TEST_F(CommandGraphTest, InOrderQueue) {
// Record in-order queue with three nodes
InOrderGraph.begin_recording(InOrderQueue);
auto Node1Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode1 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand All @@ -380,7 +381,7 @@ TEST_F(CommandGraphTest, InOrderQueue) {
ASSERT_TRUE(PtrNode1->MPredecessors.empty());

auto Node2Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode2 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand All @@ -393,7 +394,7 @@ TEST_F(CommandGraphTest, InOrderQueue) {
ASSERT_EQ(PtrNode2->MPredecessors.front().lock(), PtrNode1);

auto Node3Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode3 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand Down Expand Up @@ -431,7 +432,7 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmpty) {
// node
InOrderGraph.begin_recording(InOrderQueue);
auto Node1Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode1 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand All @@ -452,7 +453,7 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmpty) {
ASSERT_EQ(PtrNode2->MPredecessors.front().lock(), PtrNode1);

auto Node3Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode3 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand Down Expand Up @@ -496,7 +497,7 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmptyFirst) {
ASSERT_TRUE(PtrNode1->MPredecessors.empty());

auto Node2Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode2 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand All @@ -509,7 +510,7 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmptyFirst) {
ASSERT_EQ(PtrNode2->MPredecessors.front().lock(), PtrNode1);

auto Node3Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode3 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand Down Expand Up @@ -545,7 +546,7 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmptyLast) {
// Record in-order queue with two regular nodes then an empty node
InOrderGraph.begin_recording(InOrderQueue);
auto Node1Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode1 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand All @@ -554,7 +555,7 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmptyLast) {
ASSERT_TRUE(PtrNode1->MPredecessors.empty());

auto Node2Graph = InOrderQueue.submit(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

auto PtrNode2 =
sycl::detail::getSyclObjImpl(InOrderGraph)
Expand Down Expand Up @@ -596,9 +597,9 @@ TEST_F(CommandGraphTest, InOrderQueueWithEmptyLast) {
TEST_F(CommandGraphTest, MakeEdgeErrors) {
// Set up some nodes in the graph
auto NodeA = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });
auto NodeB = Graph.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

// Test error on calling make_edge when a queue is recording to the graph
Graph.begin_recording(Queue);
Expand Down Expand Up @@ -631,7 +632,7 @@ TEST_F(CommandGraphTest, MakeEdgeErrors) {
experimental::command_graph<experimental::graph_state::modifiable> GraphOther{
Queue.get_context(), Queue.get_device()};
auto NodeOther = GraphOther.add(
[&](sycl::handler &cgh) { cgh.single_task<class TestKernel>([]() {}); });
[&](sycl::handler &cgh) { cgh.single_task<TestKernel<>>([]() {}); });

ASSERT_THROW(
{
Expand Down
2 changes: 1 addition & 1 deletion sycl/unittests/helpers/PiMockPlugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ inline pi_result mock_piDeviceGetInfo(pi_device device,
size_t *param_value_size_ret) {
constexpr char MockDeviceName[] = "Mock device";
constexpr char MockSupportedExtensions[] =
"cl_khr_fp64 cl_khr_fp16 cl_khr_il_program";
"cl_khr_fp64 cl_khr_fp16 cl_khr_il_program ur_exp_command_buffer";
switch (param_name) {
case PI_DEVICE_INFO_TYPE: {
// Act like any device is a GPU.
Expand Down