Skip to content

Commit 3e1a0ea

Browse files
committed
[L0] Fix binary sizes and binaries returned by urProgramGetInfo
Currently urProgramGetInfo will return UR_RESULT_ERROR_INVALID_PROGRAM if program is built only for a subset of associated devices, i.e. not all devices have level zero module and binaries. This PR fixes this behaviour. Such urProgramGetInfo will return UR_RESULT_SUCCESS and 0 will be returned as binary size for devices which don't have a binary and binary data will not be copied for them.
1 parent 9a209aa commit 3e1a0ea

File tree

5 files changed

+84
-31
lines changed

5 files changed

+84
-31
lines changed

source/adapters/level_zero/program.cpp

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -668,17 +668,16 @@ ur_result_t urProgramGetInfo(
668668
binarySizes.push_back(Program->getCodeSize(Device->ZeDevice));
669669
continue;
670670
}
671-
auto ZeModule = Program->getZeModuleHandle(Device->ZeDevice);
672-
if (!ZeModule)
673-
return UR_RESULT_ERROR_INVALID_PROGRAM;
674-
675671
if (State == ur_program_handle_t_::IL ||
676672
State == ur_program_handle_t_::Object) {
677-
// We don't have a binary for this device, so return size of the spirv
678-
// code. This is an array of 1 element, initialized as if it were
679-
// scalar.
680-
return ReturnValue(size_t{Program->getCodeSize()});
673+
// We don't have a binary for this device, so return 0.
674+
binarySizes.push_back(0);
675+
continue;
681676
} else if (State == ur_program_handle_t_::Exe) {
677+
auto ZeModule = Program->getZeModuleHandle(Device->ZeDevice);
678+
if (!ZeModule)
679+
return UR_RESULT_ERROR_INVALID_PROGRAM;
680+
682681
size_t binarySize = 0;
683682
ZE2UR_CALL(zeModuleGetNativeBinary, (ZeModule, &binarySize, nullptr));
684683
binarySizes.push_back(binarySize);
@@ -718,27 +717,17 @@ ur_result_t urProgramGetInfo(
718717
SzBinary += Program->getCodeSize(ZeDevice);
719718
continue;
720719
}
721-
auto ZeModule = Program->getZeModuleHandle(ZeDevice);
722-
if (!ZeModule) {
723-
return UR_RESULT_ERROR_INVALID_PROGRAM;
724-
}
725-
// If the caller is using a Program which is IL or an object, then
726-
// the program has not been built for multiple devices so a single IL is
727-
// returned.
728-
// TODO: currently if program is not compiled for any of the associated
729-
// devices, we just return spirv code, assuming that we either have the
730-
// program built for all associated devices or for none. It is possible
731-
// that program is compiled for subset of associated devices, so that case
732-
// probably should be explicitely specified and handled better.
733720
if (State == ur_program_handle_t_::IL ||
734721
State == ur_program_handle_t_::Object) {
722+
// We don't have a binary for this device, so don't update the output
723+
// pointer to the binary, only set return size to 0.
735724
if (PropSizeRet)
736-
*PropSizeRet = Program->getCodeSize();
737-
if (PBinary) {
738-
std::memcpy(PBinary[0], Program->getCode(), Program->getCodeSize());
739-
}
740-
break;
725+
*PropSizeRet = 0;
741726
} else if (State == ur_program_handle_t_::Exe) {
727+
auto ZeModule = Program->getZeModuleHandle(ZeDevice);
728+
if (!ZeModule) {
729+
return UR_RESULT_ERROR_INVALID_PROGRAM;
730+
}
742731
size_t binarySize = 0;
743732
if (PBinary) {
744733
NativeBinaryPtr = PBinary[deviceIndex];

test/conformance/program/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_conformance_test_with_kernels_environment(program
88
urProgramCompile.cpp
99
urProgramCreateWithBinary.cpp
1010
urMultiDeviceProgramCreateWithBinary.cpp
11+
urMultiDeviceProgramCreateWithIL.cpp
1112
urProgramCreateWithIL.cpp
1213
urProgramCreateWithNativeHandle.cpp
1314
urProgramGetBuildInfo.cpp

test/conformance/program/urMultiDeviceProgramCreateWithBinary.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ struct urMultiDeviceProgramCreateWithBinaryTest
1212
void SetUp() override {
1313
UUR_RETURN_ON_FATAL_FAILURE(urMultiDeviceProgramTest::SetUp());
1414

15-
// First obtain binaries for all devices from the compiler SPIRV program.
16-
devices = uur::DevicesEnvironment::instance->devices;
17-
if (devices.size() < 2) {
18-
GTEST_SKIP();
19-
}
15+
// First obtain binaries for all devices from the compiled SPIRV program.
2016
ASSERT_SUCCESS(urProgramBuild(context, program, nullptr));
2117
size_t binary_sizes_len = 0;
2218
ASSERT_SUCCESS(urProgramGetInfo(program, UR_PROGRAM_INFO_BINARY_SIZES,
@@ -51,7 +47,6 @@ struct urMultiDeviceProgramCreateWithBinaryTest
5147
}
5248

5349
std::vector<std::vector<uint8_t>> binaries;
54-
std::vector<ur_device_handle_t> devices;
5550
std::vector<const uint8_t *> pointers;
5651
std::vector<size_t> binary_sizes;
5752
ur_program_handle_t binary_program = nullptr;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
// Copyright (C) 2024 Intel Corporation
3+
// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See LICENSE.TXT
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
7+
#include <uur/fixtures.h>
8+
#include <uur/raii.h>
9+
10+
using urMultiDeviceProgramTest = uur::urMultiDeviceProgramTest;
11+
12+
// Test binary sizes and binaries obtained from urProgramGetInfo when program is built for a subset of devices in the context.
13+
TEST_F(urMultiDeviceProgramTest, urMultiDeviceProgramGetInfo) {
14+
// Run test only for level zero backend which supports urProgramBuildExp.
15+
ur_platform_backend_t backend;
16+
ASSERT_SUCCESS(urPlatformGetInfo(platform, UR_PLATFORM_INFO_BACKEND,
17+
sizeof(backend), &backend, nullptr));
18+
if (backend != UR_PLATFORM_BACKEND_LEVEL_ZERO) {
19+
GTEST_SKIP();
20+
}
21+
22+
std::vector<ur_device_handle_t> associated_devices(devices.size());
23+
ASSERT_SUCCESS(
24+
urProgramGetInfo(program, UR_PROGRAM_INFO_DEVICES,
25+
associated_devices.size() * sizeof(ur_device_handle_t),
26+
associated_devices.data(), nullptr));
27+
28+
// Build program for the first half of devices.
29+
auto subset = std::vector<ur_device_handle_t>(
30+
associated_devices.begin(),
31+
associated_devices.begin() + associated_devices.size() / 2);
32+
ASSERT_SUCCESS(
33+
urProgramBuildExp(program, subset.size(), subset.data(), nullptr));
34+
35+
std::vector<size_t> binary_sizes(associated_devices.size());
36+
ASSERT_SUCCESS(urProgramGetInfo(program, UR_PROGRAM_INFO_BINARY_SIZES,
37+
binary_sizes.size() * sizeof(size_t),
38+
binary_sizes.data(), nullptr));
39+
40+
std::vector<std::vector<char>> binaries(associated_devices.size());
41+
std::vector<char *> pointers(associated_devices.size());
42+
for (size_t i = 0; i < associated_devices.size() / 2; i++) {
43+
ASSERT_NE(binary_sizes[i], 0);
44+
binaries[i].resize(binary_sizes[i]);
45+
pointers[i] = binaries[i].data();
46+
}
47+
for (size_t i = associated_devices.size() / 2;
48+
i < associated_devices.size(); i++) {
49+
ASSERT_EQ(binary_sizes[i], 0);
50+
pointers[i] = binaries[i].data();
51+
}
52+
53+
ASSERT_SUCCESS(urProgramGetInfo(program, UR_PROGRAM_INFO_BINARIES,
54+
sizeof(uint8_t *) * pointers.size(),
55+
pointers.data(), nullptr));
56+
for (size_t i = 0; i < associated_devices.size() / 2; i++) {
57+
ASSERT_NE(binaries[i].size(), 0);
58+
}
59+
for (size_t i = associated_devices.size() / 2;
60+
i < associated_devices.size(); i++) {
61+
ASSERT_EQ(binaries[i].size(), 0);
62+
}
63+
}

test/conformance/testing/include/uur/fixtures.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,10 @@ struct urMultiDeviceProgramTest : urMultiDeviceQueueTest {
15861586
backend == UR_PLATFORM_BACKEND_CUDA) {
15871587
GTEST_SKIP();
15881588
}
1589+
devices = uur::DevicesEnvironment::instance->devices;
1590+
if (devices.size() < 2) {
1591+
GTEST_SKIP();
1592+
}
15891593
UUR_RETURN_ON_FATAL_FAILURE(
15901594
uur::KernelsEnvironment::instance->LoadSource(program_name,
15911595
il_binary));
@@ -1611,6 +1615,7 @@ struct urMultiDeviceProgramTest : urMultiDeviceQueueTest {
16111615
std::string program_name = "foo";
16121616
ur_program_handle_t program = nullptr;
16131617
std::vector<ur_program_metadata_t> metadatas{};
1618+
std::vector<ur_device_handle_t> devices;
16141619
};
16151620

16161621
} // namespace uur

0 commit comments

Comments
 (0)