blob: 6e3e18806eee748626edcbea35e3afeb6c3c31e5 [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.
#include "third_party/mlir_edge/iree/hal/host/host_local_allocator.h"
#include <cstdlib>
#include <string>
#include <utility>
#include "third_party/absl/types/source_location.h"
#include "third_party/mlir_edge/iree/base/status.h"
#include "third_party/mlir_edge/iree/base/tracing.h"
#include "third_party/mlir_edge/iree/hal/host/host_buffer.h"
namespace iree {
namespace hal {
HostLocalAllocator::HostLocalAllocator() = default;
HostLocalAllocator::~HostLocalAllocator() = default;
bool HostLocalAllocator::CanUseBufferLike(
Allocator* source_allocator, MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
BufferUsageBitfield intended_usage) const {
// Must always have visibility to the device, which ensures we can test
// against the host but have things work on devices with separate address
// spaces.
if (!AnyBitSet(memory_type & MemoryType::kDeviceVisible)) {
return false;
}
// kHostVisible is required for mapping.
if (AnyBitSet(intended_usage & BufferUsage::kMapping) &&
!AnyBitSet(memory_type & MemoryType::kHostVisible)) {
return false;
}
// Dispatch needs to be specified if we intend to dispatch.
if (AnyBitSet(intended_usage & BufferUsage::kDispatch) &&
!AnyBitSet(buffer_usage & BufferUsage::kDispatch)) {
return false;
}
return true;
}
bool HostLocalAllocator::CanAllocate(MemoryTypeBitfield memory_type,
BufferUsageBitfield buffer_usage,
size_t allocation_size) const {
// Host allows everything, pretty much, so long as it is device-visible (as
// the host is the device here).
return AnyBitSet(memory_type & MemoryType::kDeviceVisible);
}
Status HostLocalAllocator::MakeCompatible(
MemoryTypeBitfield* memory_type, BufferUsageBitfield* buffer_usage) const {
// Always ensure we are host-visible.
*memory_type |= MemoryType::kHostVisible;
// Host currently uses mapping to copy buffers, which is done a lot.
// We could probably remove this restriction somehow.
*buffer_usage |= BufferUsage::kMapping;
// TODO(b/111372612): tensorflow needs transfer too, but shouldn't.
*buffer_usage |= BufferUsage::kTransfer;
return OkStatus();
}
StatusOr<ref_ptr<Buffer>> HostLocalAllocator::Allocate(
MemoryTypeBitfield memory_type, BufferUsageBitfield buffer_usage,
size_t allocation_size) {
IREE_TRACE_SCOPE0("HostLocalAllocator::Allocate");
if (!CanAllocate(memory_type, buffer_usage, allocation_size)) {
return FailedPreconditionErrorBuilder(ABSL_LOC)
<< "Allocation not supported; memory_type="
<< MemoryTypeString(memory_type)
<< ", buffer_usage=" << BufferUsageString(buffer_usage)
<< ", allocation_size=" << allocation_size;
}
// Make compatible with our requirements.
RETURN_IF_ERROR(MakeCompatible(&memory_type, &buffer_usage));
void* malloced_data = std::calloc(1, allocation_size);
if (!malloced_data) {
return ResourceExhaustedErrorBuilder(ABSL_LOC)
<< "Failed to malloc " << allocation_size << " bytes";
}
auto buffer =
make_ref<HostBuffer>(this, memory_type, MemoryAccess::kAll, buffer_usage,
allocation_size, malloced_data, true);
return buffer;
}
} // namespace hal
} // namespace iree