Skip to content

Commit

Permalink
Merge pull request #1549 from igchor/event_fix
Browse files Browse the repository at this point in the history
Fix adding event to queue cache
  • Loading branch information
kbenzie committed May 3, 2024
1 parent e5e6d8a commit d4897d1
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 3 deletions.
4 changes: 4 additions & 0 deletions source/adapters/level_zero/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ bool setEnvVar(const char *name, const char *value) {
ZeUSMImportExtension ZeUSMImport;

// This will count the calls to Level-Zero
// TODO: remove the ifdef once
// https://github.com/oneapi-src/unified-runtime/issues/1454 is implemented
#ifndef UR_L0_CALL_COUNT_IN_TESTS
std::map<std::string, int> *ZeCallCount = nullptr;
#endif

inline void zeParseError(ze_result_t ZeError, const char *&ErrorString) {
switch (ZeError) {
Expand Down
3 changes: 1 addition & 2 deletions source/adapters/level_zero/queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1497,8 +1497,7 @@ ur_queue_handle_t_::resetDiscardedEvent(ur_command_list_ptr_t CommandList) {
}

ur_result_t ur_queue_handle_t_::addEventToQueueCache(ur_event_handle_t Event) {
if (!Event->IsMultiDevice && Event->UrQueue) {
auto Device = Event->UrQueue->Device;
if (!Event->IsMultiDevice) {
auto EventCachesMap = Event->isHostVisible() ? &EventCachesDeviceMap[0]
: &EventCachesDeviceMap[1];
if (EventCachesMap->find(Device) == EventCachesMap->end()) {
Expand Down
2 changes: 1 addition & 1 deletion test/adapters/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2023 Intel Corporation
# Copyright (C) 2023-2024 Intel Corporation
# Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
# See LICENSE.TXT
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Expand Down
163 changes: 163 additions & 0 deletions test/adapters/level_zero/event_cache_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright (C) 2024 Intel Corporation
// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE.TXT
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "ur_print.hpp"
#include "uur/fixtures.h"
#include "uur/raii.h"

#include <map>
#include <string>

template <typename... Args> auto combineFlags(std::tuple<Args...> tuple) {
return std::apply([](auto... args) { return (... |= args); }, tuple);
}

extern std::map<std::string, int> *ZeCallCount;

using FlagsTupleType = std::tuple<ur_queue_flags_t, ur_queue_flags_t,
ur_queue_flags_t, ur_queue_flags_t>;

struct urEventCacheTest : uur::urContextTestWithParam<FlagsTupleType> {
void SetUp() override {
UUR_RETURN_ON_FATAL_FAILURE(urContextTestWithParam::SetUp());

flags = combineFlags(getParam());

ur_queue_properties_t props;
props.flags = flags;
ASSERT_SUCCESS(urQueueCreate(context, device, &props, &queue));
ASSERT_NE(queue, nullptr);

ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_WRITE_ONLY, size,
nullptr, &buffer));

(*ZeCallCount)["zeEventCreate"] = 0;
(*ZeCallCount)["zeEventDestroy"] = 0;
}

void TearDown() override {
if (buffer) {
EXPECT_SUCCESS(urMemRelease(buffer));
}
if (queue) {
UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urQueueRelease(queue));
}
UUR_RETURN_ON_FATAL_FAILURE(urContextTestWithParam::TearDown());
}

auto enqueueWork(ur_event_handle_t *hEvent, int data) {
input.assign(count, data);
UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urEnqueueMemBufferWrite(
queue, buffer, false, 0, size, input.data(), 0, nullptr, hEvent));
}

void verifyData() {
std::vector<uint32_t> output(count, 1);
UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urEnqueueMemBufferRead(
queue, buffer, true, 0, size, output.data(), 0, nullptr, nullptr));

if (!(flags & UR_QUEUE_FLAG_OUT_OF_ORDER_EXEC_MODE_ENABLE)) {
ASSERT_EQ(input, output);
}
}

const size_t count = 1024;
const size_t size = sizeof(uint32_t) * count;
ur_mem_handle_t buffer = nullptr;
ur_queue_handle_t queue = nullptr;
std::vector<uint32_t> input;
ur_queue_flags_t flags;
};

TEST_P(urEventCacheTest, eventsReuseNoVisibleEvent) {
static constexpr int numIters = 16;
static constexpr int numEnqueues = 128;

for (int i = 0; i < numIters; i++) {
for (int j = 0; j < numEnqueues; j++) {
enqueueWork(nullptr, i * numEnqueues + j);
}
UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urQueueFinish(queue));
verifyData();
}

// TODO: why events are not reused for UR_QUEUE_FLAG_OUT_OF_ORDER_EXEC_MODE_ENABLE?
if ((flags & UR_QUEUE_FLAG_DISCARD_EVENTS) &&
!(flags & UR_QUEUE_FLAG_OUT_OF_ORDER_EXEC_MODE_ENABLE)) {
ASSERT_EQ((*ZeCallCount)["zeEventCreate"], 2);
} else {
ASSERT_GE((*ZeCallCount)["zeEventCreate"], numIters * numEnqueues);
}
}

TEST_P(urEventCacheTest, eventsReuseWithVisibleEvent) {
static constexpr int numIters = 16;
static constexpr int numEnqueues = 128;

for (int i = 0; i < numIters; i++) {
std::vector<uur::raii::Event> events(numEnqueues);
for (int j = 0; j < numEnqueues; j++) {
enqueueWork(events[j].ptr(), i * numEnqueues + j);
}
UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urQueueFinish(queue));
verifyData();
}

ASSERT_LT((*ZeCallCount)["zeEventCreate"], numIters * numEnqueues);
}

TEST_P(urEventCacheTest, eventsReuseWithVisibleEventAndWait) {
static constexpr int numIters = 16;
static constexpr int numEnqueues = 128;
static constexpr int waitEveryN = 16;

for (int i = 0; i < numIters; i++) {
std::vector<uur::raii::Event> events;
for (int j = 0; j < numEnqueues; j++) {
events.emplace_back();
enqueueWork(events.back().ptr(), i * numEnqueues + j);

if (j > 0 && j % waitEveryN == 0) {
ASSERT_SUCCESS(urEventWait(waitEveryN,
(ur_event_handle_t *)events.data()));
verifyData();
events.clear();
}
}
UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urQueueFinish(queue));
}

ASSERT_GE((*ZeCallCount)["zeEventCreate"], waitEveryN);
// TODO: why there are more events than this?
// ASSERT_LE((*ZeCallCount)["zeEventCreate"], waitEveryN * 2 + 2);
}

template <typename T>
inline std::string
printFlags(const testing::TestParamInfo<typename T::ParamType> &info) {
const auto device_handle = std::get<0>(info.param);
const auto platform_device_name =
uur::GetPlatformAndDeviceName(device_handle);
auto flags = combineFlags(std::get<1>(info.param));

std::stringstream ss;
ur::details::printFlag<ur_queue_flag_t>(ss, flags);

auto str = ss.str();
std::replace(str.begin(), str.end(), ' ', '_');
std::replace(str.begin(), str.end(), '|', '_');
return platform_device_name + "__" + str;
}

UUR_TEST_SUITE_P(
urEventCacheTest,
::testing::Combine(
testing::Values(0, UR_QUEUE_FLAG_DISCARD_EVENTS),
testing::Values(0, UR_QUEUE_FLAG_OUT_OF_ORDER_EXEC_MODE_ENABLE),
// TODO: why the test fails with UR_QUEUE_FLAG_SUBMISSION_BATCHED?
testing::Values(
UR_QUEUE_FLAG_SUBMISSION_IMMEDIATE /*, UR_QUEUE_FLAG_SUBMISSION_BATCHED */),
testing::Values(0, UR_QUEUE_FLAG_PROFILING_ENABLE)),
printFlags<urEventCacheTest>);
12 changes: 12 additions & 0 deletions test/adapters/level_zero/zeCallMap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (C) 2024 Intel Corporation
// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE.TXT
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <map>
#include <string>

// Map used by L0 adapter to count the number of calls to each L0 function
// Lifetime is managed by the adapter, this variable is defined here
// only so that we can read it from the tests.
std::map<std::string, int> *ZeCallCount = nullptr;
8 changes: 8 additions & 0 deletions test/conformance/testing/include/uur/fixtures.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
} \
(void)0

#define UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(ret) \
auto status = ret; \
if (status == UR_RESULT_ERROR_UNSUPPORTED_FEATURE) { \
GTEST_SKIP(); \
} else { \
ASSERT_EQ(status, UR_RESULT_SUCCESS); \
}

namespace uur {

struct urPlatformTest : ::testing::Test {
Expand Down

0 comments on commit d4897d1

Please sign in to comment.