blob: b3dba2325b4feeb6587701cf21e315262ee10cb9 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef IREE_HAL_ALLOCATOR_H_
#define IREE_HAL_ALLOCATOR_H_
#include <cstddef>
#include <memory>
#include "absl/types/span.h"
#include "base/status.h"
#include "hal/buffer.h"
namespace iree {
namespace hal {
// Allocates buffers for a particular device memory space.
//
// Buffers allocated are only guaranteed to work with the driver that the
// allocator services. Any attempt to use buffers on drivers they were not
// allocated from must first be checked with CanUseBuffer.
//
// Thread-safe.
class Allocator {
public:
virtual ~Allocator() = default;
// Returns true if the device can use the given buffer for the provided usage.
// For buffers allocated from this allocator it's expected that the result
// will always be true. For buffers that originate from another allocator
// there may be limited support for cross-device usage.
//
// Returning false indicates that the buffer must be transferred externally
// into a buffer compatible with the device this allocator services.
bool CanUseBuffer(Buffer* buffer, BufferUsageBitfield intended_usage) const;
virtual bool CanUseBufferLike(Allocator* source_allocator,
MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
BufferUsageBitfield intended_usage) const = 0;
// Returns true if the allocator can allocate a buffer with the given
// attributes.
virtual bool CanAllocate(MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
size_t allocation_size) const = 0;
// Adjusts allocation parameters to be compatible with the allocator.
// Certain allocators may require particular memory types to function. By
// adjusting the parameters prior to allocation callers can be sure they are
// able to successfully Allocate a buffer later on with the same parameters.
virtual Status MakeCompatible(MemoryTypeBitfield* memory_type,
BufferUsageBitfield* buffer_usage) const {
return OkStatus();
}
// Allocates a buffer from the allocator.
// Fails if the memory type requested for the given usage cannot be serviced.
// Callers can use CanAllocate to decide their memory use strategy.
//
// The memory type of the buffer returned may differ from the requested value
// if the device can provide more functionality; for example, if requesting
// MemoryType::kHostVisible but the memory is really host cached you may get
// a buffer back with MemoryType::kHostVisible | MemoryType::kHostCached. The
// only requirement is that the buffer satisfy the required bits.
virtual StatusOr<ref_ptr<Buffer>> Allocate(MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
size_t allocation_size) = 0;
// Allocates a buffer from the allocator for use as a constant value.
// The provided |source_buffer| may be returned if the device can use it
// directly and otherwise will be copied.
virtual StatusOr<ref_ptr<Buffer>> AllocateConstant(
BufferUsageBitfield buffer_usage, ref_ptr<Buffer> source_buffer);
// Wraps an existing host heap allocation in a buffer.
// Ownership of the host allocation remains with the caller and the memory
// must remain valid for so long as the Buffer may be in use.
// Will have MemoryType::kHostLocal in most cases and may not be usable
// by the device.
//
// The inference optimizer makes assumptions about buffer aliasing based on
// Buffer instances and because of this wrapping the same host buffer in
// multiple Buffers will create potential memory aliasing issues that can be
// difficult to track down. There's no checking as to whether a host buffer
// has already been wrapped so it's best for callers to ensure this is never
// possible (the simplest way being to never use Wrap and always just allocate
// new Buffers).
//
// Fails if the allocator cannot access host memory in this way.
StatusOr<ref_ptr<Buffer>> Wrap(MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
const void* data, size_t data_length);
virtual StatusOr<ref_ptr<Buffer>> WrapMutable(
MemoryTypeBitfield memory_type, MemoryAccessBitfield allowed_access,
BufferUsageBitfield buffer_usage, void* data, size_t data_length);
template <typename T>
StatusOr<ref_ptr<Buffer>> Wrap(MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
absl::Span<const T> data);
template <typename T>
StatusOr<ref_ptr<Buffer>> WrapMutable(MemoryTypeBitfield memory_type,
MemoryAccessBitfield allowed_access,
BufferUsageBitfield buffer_usage,
absl::Span<T> data);
};
// Inline functions and template definitions follow:
template <typename T>
StatusOr<ref_ptr<Buffer>> Allocator::Wrap(MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
absl::Span<const T> data) {
return Wrap(memory_type, buffer_usage, data.data(), data.size() * sizeof(T));
}
template <typename T>
StatusOr<ref_ptr<Buffer>> Allocator::WrapMutable(
MemoryTypeBitfield memory_type, MemoryAccessBitfield allowed_access,
BufferUsageBitfield buffer_usage, absl::Span<T> data) {
return WrapMutable(memory_type, allowed_access, buffer_usage, data.data(),
data.size() * sizeof(T));
}
} // namespace hal
} // namespace iree
#endif // IREE_HAL_ALLOCATOR_H_