blob: 2e0c5e6e3d4f09f022e2ba06e2e92d556f7c7849 [file]
// Copyright 2026 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "iree/hal/pool.h"
#include <stddef.h>
#include <string.h>
#include "iree/async/notification.h"
#include "iree/hal/detail.h"
#include "iree/hal/resource.h"
#define _VTABLE_DISPATCH(pool, method_name) \
IREE_HAL_VTABLE_DISPATCH(pool, iree_hal_pool, method_name)
IREE_HAL_API_RETAIN_RELEASE(pool);
IREE_API_EXPORT iree_status_t iree_hal_pool_acquire_reservation(
iree_hal_pool_t* pool, iree_device_size_t size,
iree_device_size_t alignment,
const iree_async_frontier_t* requester_frontier,
iree_hal_pool_reserve_flags_t flags,
iree_hal_pool_reservation_t* out_reservation,
iree_hal_pool_acquire_info_t* out_info,
iree_hal_pool_acquire_result_t* out_result) {
IREE_ASSERT_ARGUMENT(pool);
IREE_ASSERT_ARGUMENT(out_reservation);
IREE_ASSERT_ARGUMENT(out_info);
IREE_ASSERT_ARGUMENT(out_result);
memset(out_info, 0, sizeof(*out_info));
IREE_TRACE_ZONE_BEGIN(z0);
iree_status_t status = _VTABLE_DISPATCH(pool, acquire_reservation)(
pool, size, alignment, requester_frontier, flags, out_reservation,
out_info, out_result);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT void iree_hal_pool_release_reservation(
iree_hal_pool_t* pool, const iree_hal_pool_reservation_t* reservation,
const iree_async_frontier_t* death_frontier) {
IREE_ASSERT_ARGUMENT(pool);
IREE_ASSERT_ARGUMENT(reservation);
IREE_TRACE_ZONE_BEGIN(z0);
_VTABLE_DISPATCH(pool, release_reservation)(pool, reservation,
death_frontier);
IREE_TRACE_ZONE_END(z0);
}
IREE_API_EXPORT iree_status_t iree_hal_pool_materialize_reservation(
iree_hal_pool_t* pool, iree_hal_buffer_params_t params,
const iree_hal_pool_reservation_t* reservation,
iree_hal_pool_materialize_flags_t flags, iree_hal_buffer_t** out_buffer) {
IREE_ASSERT_ARGUMENT(pool);
IREE_ASSERT_ARGUMENT(reservation);
IREE_ASSERT_ARGUMENT(out_buffer);
*out_buffer = NULL;
IREE_TRACE_ZONE_BEGIN(z0);
iree_status_t status = _VTABLE_DISPATCH(pool, materialize_reservation)(
pool, params, reservation, flags, out_buffer);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT void iree_hal_pool_query_capabilities(
const iree_hal_pool_t* pool,
iree_hal_pool_capabilities_t* out_capabilities) {
IREE_ASSERT_ARGUMENT(pool);
IREE_ASSERT_ARGUMENT(out_capabilities);
memset(out_capabilities, 0, sizeof(*out_capabilities));
_VTABLE_DISPATCH(pool, query_capabilities)(pool, out_capabilities);
}
IREE_API_EXPORT void iree_hal_pool_query_stats(
const iree_hal_pool_t* pool, iree_hal_pool_stats_t* out_stats) {
IREE_ASSERT_ARGUMENT(pool);
IREE_ASSERT_ARGUMENT(out_stats);
memset(out_stats, 0, sizeof(*out_stats));
_VTABLE_DISPATCH(pool, query_stats)(pool, out_stats);
}
IREE_API_EXPORT iree_status_t iree_hal_pool_trim(iree_hal_pool_t* pool) {
IREE_ASSERT_ARGUMENT(pool);
IREE_TRACE_ZONE_BEGIN(z0);
iree_status_t status = _VTABLE_DISPATCH(pool, trim)(pool);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_async_notification_t* iree_hal_pool_notification(
iree_hal_pool_t* pool) {
IREE_ASSERT_ARGUMENT(pool);
return _VTABLE_DISPATCH(pool, notification)(pool);
}
IREE_API_EXPORT iree_status_t iree_hal_pool_allocate_buffer(
iree_hal_pool_t* pool, iree_hal_buffer_params_t params,
iree_device_size_t allocation_size,
const iree_async_frontier_t* requester_frontier, iree_timeout_t timeout,
iree_hal_buffer_t** out_buffer) {
IREE_ASSERT_ARGUMENT(pool);
IREE_ASSERT_ARGUMENT(out_buffer);
*out_buffer = NULL;
IREE_TRACE_ZONE_BEGIN(z0);
// Convert to absolute so retries after spurious wakes use a consistent
// cutoff.
iree_convert_timeout_to_absolute(&timeout);
iree_async_notification_t* notification = iree_hal_pool_notification(pool);
iree_status_t status = iree_ok_status();
bool retry = true;
while (retry) {
const uint32_t wait_token =
iree_async_notification_begin_observe(notification);
iree_hal_pool_reservation_t reservation;
iree_hal_pool_acquire_info_t acquire_info;
iree_hal_pool_acquire_result_t result;
status = iree_hal_pool_acquire_reservation(
pool, allocation_size, params.min_alignment ? params.min_alignment : 1,
requester_frontier, IREE_HAL_POOL_RESERVE_FLAG_NONE, &reservation,
&acquire_info, &result);
if (iree_status_is_ok(status)) {
switch (result) {
case IREE_HAL_POOL_ACQUIRE_OK:
case IREE_HAL_POOL_ACQUIRE_OK_FRESH:
// Reservation succeeded; transfer ownership to the returned buffer.
status = iree_hal_pool_materialize_reservation(
pool, params, &reservation,
IREE_HAL_POOL_MATERIALIZE_FLAG_TRANSFER_RESERVATION_OWNERSHIP,
out_buffer);
if (!iree_status_is_ok(status)) {
// Wrapping failed; release the reservation to avoid leaking the
// offset back to the pool.
iree_hal_pool_release_reservation(pool, &reservation, NULL);
}
retry = false;
break;
case IREE_HAL_POOL_ACQUIRE_OK_NEEDS_WAIT:
// Synchronous allocation cannot model a hidden queue wait edge. A
// pool used through this helper must skip non-dominated blocks and
// return EXHAUSTED/OVER_BUDGET until an immediately-usable
// reservation exists. Preserve the block's original frontier and
// report a pool implementation bug, not a caller precondition
// failure.
iree_hal_pool_release_reservation(pool, &reservation,
acquire_info.wait_frontier);
status = iree_make_status(
IREE_STATUS_INTERNAL,
"iree_hal_pool_allocate_buffer received an "
"IREE_HAL_POOL_ACQUIRE_OK_NEEDS_WAIT reservation from a pool "
"that must only return immediately-usable reservations in the "
"synchronous helper path");
retry = false;
break;
case IREE_HAL_POOL_ACQUIRE_EXHAUSTED:
case IREE_HAL_POOL_ACQUIRE_OVER_BUDGET:
// Wait for a release to advance the notification, then retry.
if (!iree_async_notification_wait_for_token(notification, wait_token,
timeout)) {
status = iree_make_status(
IREE_STATUS_DEADLINE_EXCEEDED,
"pool allocate_buffer timed out waiting for a free block (%s)",
result == IREE_HAL_POOL_ACQUIRE_EXHAUSTED ? "exhausted"
: "over budget");
retry = false;
}
break;
}
}
iree_async_notification_end_observe(notification);
if (!iree_status_is_ok(status)) {
retry = false;
}
}
IREE_TRACE_ZONE_END(z0);
return status;
}