Skip to content

Commit

Permalink
Add size validation for USM device/shared allocs
Browse files Browse the repository at this point in the history
The spec states that an allocation size higher than
`DEVICE_INFO_MAX_MEM_ALLOC_SIZE` should report an error. This has been
added to the Cuda, Hip and Native CPU backends now.

The tests have also been updated, which sadly introduces a new
regression for level zero.
  • Loading branch information
RossBrunton committed Jan 14, 2025
1 parent ad88f0a commit 90776d2
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 32 deletions.
8 changes: 8 additions & 0 deletions source/adapters/cuda/usm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ urUSMDeviceAlloc(ur_context_handle_t hContext, ur_device_handle_t hDevice,
(alignment == 0 || ((alignment & (alignment - 1)) == 0)),
UR_RESULT_ERROR_INVALID_VALUE);

if (size > hDevice->getMaxAllocSize()) {
return UR_RESULT_ERROR_INVALID_USM_SIZE;
}

if (!hPool) {
return USMDeviceAllocImpl(ppMem, hContext, hDevice, /* flags */ 0, size,
alignment);
Expand All @@ -88,6 +92,10 @@ urUSMSharedAlloc(ur_context_handle_t hContext, ur_device_handle_t hDevice,
(alignment == 0 || ((alignment & (alignment - 1)) == 0)),
UR_RESULT_ERROR_INVALID_VALUE);

if (size > hDevice->getMaxAllocSize()) {
return UR_RESULT_ERROR_INVALID_USM_SIZE;
}

if (!hPool) {
return USMSharedAllocImpl(ppMem, hContext, hDevice, /*host flags*/ 0,
/*device flags*/ 0, size, alignment);
Expand Down
18 changes: 2 additions & 16 deletions source/adapters/hip/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "context.hpp"
#include "event.hpp"
#include "logger/ur_logger.hpp"
#include "usm.hpp"

#include <sstream>

Expand Down Expand Up @@ -206,22 +207,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urDeviceGetInfo(ur_device_handle_t hDevice,
return ReturnValue(Bits);
}
case UR_DEVICE_INFO_MAX_MEM_ALLOC_SIZE: {
// Max size of memory object allocation in bytes.
// The minimum value is max(min(1024 × 1024 ×
// 1024, 1/4th of CL_DEVICE_GLOBAL_MEM_SIZE),
// 32 × 1024 × 1024) for devices that are not of type
// CL_DEVICE_TYPE_CUSTOM.

size_t Global = 0;
detail::ur::assertion(hipDeviceTotalMem(&Global, hDevice->get()) ==
hipSuccess);

auto QuarterGlobal = static_cast<uint32_t>(Global / 4u);

auto MaxAlloc = std::max(std::min(1024u * 1024u * 1024u, QuarterGlobal),
32u * 1024u * 1024u);

return ReturnValue(uint64_t{MaxAlloc});
return ReturnValue(uint64_t{maxUSMAllocationSize(hDevice)});
}
case UR_DEVICE_INFO_IMAGE_SUPPORTED: {
bool Enabled = false;
Expand Down
26 changes: 26 additions & 0 deletions source/adapters/hip/usm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ urUSMDeviceAlloc(ur_context_handle_t hContext, ur_device_handle_t hDevice,
UR_ASSERT(checkUSMAlignment(alignment, pUSMDesc),
UR_RESULT_ERROR_INVALID_VALUE);

if (size > maxUSMAllocationSize(hDevice)) {
return UR_RESULT_ERROR_INVALID_USM_SIZE;
}

if (!hPool) {
return USMDeviceAllocImpl(ppMem, hContext, hDevice, /* flags */ 0, size,
alignment);
Expand All @@ -66,6 +70,10 @@ urUSMSharedAlloc(ur_context_handle_t hContext, ur_device_handle_t hDevice,
UR_ASSERT(checkUSMAlignment(alignment, pUSMDesc),
UR_RESULT_ERROR_INVALID_VALUE);

if (size > maxUSMAllocationSize(hDevice)) {
return UR_RESULT_ERROR_INVALID_USM_SIZE;
}

if (!hPool) {
return USMSharedAllocImpl(ppMem, hContext, hDevice, /*host flags*/ 0,
/*device flags*/ 0, size, alignment);
Expand Down Expand Up @@ -454,6 +462,24 @@ UR_APIEXPORT ur_result_t UR_APICALL urUSMPoolGetInfo(
}
}

uint64_t maxUSMAllocationSize(const ur_device_handle_t &Device) {
// Max size of memory object allocation in bytes.
// The minimum value is max(min(1024 × 1024 ×
// 1024, 1/4th of CL_DEVICE_GLOBAL_MEM_SIZE),
// 32 × 1024 × 1024) for devices that are not of type
// CL_DEVICE_TYPE_CUSTOM.
size_t Global = 0;
detail::ur::assertion(hipDeviceTotalMem(&Global, Device->get()) ==
hipSuccess);

auto QuarterGlobal = static_cast<uint32_t>(Global / 4u);

auto MaxAlloc = std::max(std::min(1024u * 1024u * 1024u, QuarterGlobal),
32u * 1024u * 1024u);

return MaxAlloc;
}

bool checkUSMAlignment(uint32_t &alignment, const ur_usm_desc_t *pUSMDesc) {
alignment = pUSMDesc ? pUSMDesc->align : 0u;
return (!pUSMDesc ||
Expand Down
2 changes: 2 additions & 0 deletions source/adapters/hip/usm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ ur_result_t USMHostAllocImpl(void **ResultPtr, ur_context_handle_t Context,
ur_usm_host_mem_flags_t Flags, size_t Size,
uint32_t Alignment);

uint64_t maxUSMAllocationSize(const ur_device_handle_t &Device);

bool checkUSMAlignment(uint32_t &alignment, const ur_usm_desc_t *pUSMDesc);

bool checkUSMImplAlignment(uint32_t Alignment, void **ResultPtr);
Expand Down
10 changes: 2 additions & 8 deletions source/adapters/native_cpu/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "common.hpp"
#include "platform.hpp"
#include "usm.hpp"

#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
#ifndef NOMINMAX
Expand Down Expand Up @@ -321,14 +322,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urDeviceGetInfo(ur_device_handle_t hDevice,
case UR_DEVICE_INFO_PARTITION_AFFINITY_DOMAIN:
return ReturnValue(ur_device_affinity_domain_flags_t{0});
case UR_DEVICE_INFO_MAX_MEM_ALLOC_SIZE: {
size_t Global = hDevice->mem_size;

auto QuarterGlobal = static_cast<uint32_t>(Global / 4u);

auto MaxAlloc = std::max(std::min(1024u * 1024u * 1024u, QuarterGlobal),
32u * 1024u * 1024u);

return ReturnValue(uint64_t{MaxAlloc});
return ReturnValue(uint64_t{native_cpu::detail::maxUSMAllocationSize(hDevice)});
}
case UR_DEVICE_INFO_EXECUTION_CAPABILITIES:
// TODO : CHECK
Expand Down
19 changes: 16 additions & 3 deletions source/adapters/native_cpu/usm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "common.hpp"
#include "context.hpp"
#include "usm.hpp"
#include <cstdlib>

namespace umf {
Expand All @@ -27,7 +28,8 @@ static ur_result_t alloc_helper(ur_context_handle_t hContext,
auto alignment = (pUSMDesc && pUSMDesc->align) ? pUSMDesc->align : 1u;
UR_ASSERT(isPowerOf2(alignment), UR_RESULT_ERROR_UNSUPPORTED_ALIGNMENT);
UR_ASSERT(ppMem, UR_RESULT_ERROR_INVALID_NULL_POINTER);
// TODO: Check Max size when UR_DEVICE_INFO_MAX_MEM_ALLOC_SIZE is implemented
// TODO: Check Max size for host allocations when
// UR_DEVICE_INFO_MAX_MEM_ALLOC_SIZE is implemented
UR_ASSERT(size > 0, UR_RESULT_ERROR_INVALID_USM_SIZE);

auto *ptr = hContext->add_alloc(alignment, type, size, nullptr);
Expand All @@ -49,8 +51,9 @@ UR_APIEXPORT ur_result_t UR_APICALL
urUSMDeviceAlloc(ur_context_handle_t hContext, ur_device_handle_t hDevice,
const ur_usm_desc_t *pUSMDesc, ur_usm_pool_handle_t pool,
size_t size, void **ppMem) {
std::ignore = hDevice;
std::ignore = pool;
UR_ASSERT(size < native_cpu::detail::maxUSMAllocationSize(hDevice),
UR_RESULT_ERROR_INVALID_USM_SIZE);

return alloc_helper(hContext, pUSMDesc, size, ppMem, UR_USM_TYPE_DEVICE);
}
Expand All @@ -59,8 +62,9 @@ UR_APIEXPORT ur_result_t UR_APICALL
urUSMSharedAlloc(ur_context_handle_t hContext, ur_device_handle_t hDevice,
const ur_usm_desc_t *pUSMDesc, ur_usm_pool_handle_t pool,
size_t size, void **ppMem) {
std::ignore = hDevice;
std::ignore = pool;
UR_ASSERT(size < native_cpu::detail::maxUSMAllocationSize(hDevice),
UR_RESULT_ERROR_INVALID_USM_SIZE);

return alloc_helper(hContext, pUSMDesc, size, ppMem, UR_USM_TYPE_SHARED);
}
Expand Down Expand Up @@ -155,3 +159,12 @@ UR_APIEXPORT ur_result_t UR_APICALL urUSMReleaseExp(ur_context_handle_t Context,
std::ignore = HostPtr;
DIE_NO_IMPLEMENTATION;
}

uint64_t maxUSMAllocationSize(const ur_device_handle_t &Device) {
size_t Global = Device->mem_size;

auto QuarterGlobal = static_cast<uint32_t>(Global / 4u);

return std::max(std::min(1024u * 1024u * 1024u, QuarterGlobal),
32u * 1024u * 1024u);
}
17 changes: 17 additions & 0 deletions source/adapters/native_cpu/usm.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//===--------- usm.hpp - Native CPU Adapter --------------------------===//
//
// Copyright (C) 2025 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 "common.hpp"

namespace native_cpu {
namespace detail {
uint64_t maxUSMAllocationSize(const ur_device_handle_t &Device);
} // namespace detail
} // namespace native_cpu
12 changes: 9 additions & 3 deletions test/conformance/usm/urUSMDeviceAlloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,19 @@ TEST_P(urUSMDeviceAllocTest, InvalidNullPtrResult) {
}

TEST_P(urUSMDeviceAllocTest, InvalidUSMSize) {
UUR_KNOWN_FAILURE_ON(uur::CUDA{}, uur::HIP{}, uur::LevelZero{},
uur::NativeCPU{});
UUR_KNOWN_FAILURE_ON(uur::LevelZero{}, uur::LevelZeroV2{});

size_t max_size;
ASSERT_SUCCESS(urDeviceGetInfo(device, UR_DEVICE_INFO_MAX_MEM_ALLOC_SIZE,
sizeof(max_size), &max_size, nullptr));
if (max_size == std::numeric_limits<size_t>::max()) {
GTEST_SKIP() << "Device has no max allocation size";
}

void *ptr = nullptr;
ASSERT_EQ_RESULT(
UR_RESULT_ERROR_INVALID_USM_SIZE,
urUSMDeviceAlloc(context, device, nullptr, pool, -1, &ptr));
urUSMDeviceAlloc(context, device, nullptr, pool, max_size + 1, &ptr));
}

TEST_P(urUSMDeviceAllocTest, InvalidValueAlignPowerOfTwo) {
Expand Down
11 changes: 9 additions & 2 deletions test/conformance/usm/urUSMSharedAlloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,18 @@ TEST_P(urUSMSharedAllocTest, InvalidNullPtrMem) {
}

TEST_P(urUSMSharedAllocTest, InvalidUSMSize) {
UUR_KNOWN_FAILURE_ON(uur::CUDA{}, uur::HIP{}, uur::NativeCPU{});
UUR_KNOWN_FAILURE_ON(uur::LevelZero{}, uur::LevelZeroV2{});

size_t max_size;
ASSERT_SUCCESS(urDeviceGetInfo(device, UR_DEVICE_INFO_MAX_MEM_ALLOC_SIZE,
sizeof(max_size), &max_size, nullptr));
if (max_size == std::numeric_limits<size_t>::max()) {
GTEST_SKIP() << "Device has no max allocation size";
}

ASSERT_EQ_RESULT(
UR_RESULT_ERROR_INVALID_USM_SIZE,
urUSMSharedAlloc(context, device, nullptr, pool, -1, &ptr));
urUSMSharedAlloc(context, device, nullptr, pool, max_size + 1, &ptr));
}

TEST_P(urUSMSharedAllocTest, InvalidValueAlignPowerOfTwo) {
Expand Down

0 comments on commit 90776d2

Please sign in to comment.