Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 29 additions & 28 deletions src/gpgmm/common/BuddyMemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ namespace gpgmm {
return static_cast<uint64_t>(SafeDivide(offset, mMemorySize));
}

std::unique_ptr<MemoryAllocation> BuddyMemoryAllocator::TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> BuddyMemoryAllocator::TryAllocateMemory(
const MemoryAllocationRequest& request) {
TRACE_EVENT0(TraceEventCategory::kDefault, "BuddyMemoryAllocator.TryAllocateMemory");

Expand All @@ -57,33 +57,34 @@ namespace gpgmm {

// Attempt to sub-allocate a block of the requested size.
std::unique_ptr<MemoryAllocation> subAllocation;
GPGMM_TRY_ASSIGN(TrySubAllocateMemory(
&mBuddyBlockAllocator, allocationSize, request.Alignment,
request.NeverAllocate,
[&](const auto& block) -> MemoryBase* {
const uint64_t memoryIndex = GetMemoryIndex(block->Offset);
MemoryAllocation memoryAllocation =
mUsedPool.AcquireFromPool(memoryIndex);

// No existing, allocate new memory for the block.
if (memoryAllocation == GPGMM_INVALID_ALLOCATION) {
MemoryAllocationRequest newRequest = request;
newRequest.SizeInBytes = mMemorySize;
newRequest.Alignment = mMemoryAlignment;

std::unique_ptr<MemoryAllocation> memoryAllocationPtr;
GPGMM_TRY_ASSIGN(
GetNextInChain()->TryAllocateMemory(newRequest),
memoryAllocationPtr);
memoryAllocation = *memoryAllocationPtr;
}

MemoryBase* memory = memoryAllocation.GetMemory();
mUsedPool.ReturnToPool(memoryAllocation, memoryIndex);

return memory;
}),
subAllocation);
GPGMM_TRY_ASSIGN(
TrySubAllocateMemory(
&mBuddyBlockAllocator, allocationSize, request.Alignment, request.NeverAllocate,
[&](const auto& block) -> ResultOrError<MemoryBase*> {
const uint64_t memoryIndex = GetMemoryIndex(block->Offset);
MemoryAllocation memoryAllocation = mUsedPool.AcquireFromPool(memoryIndex);

// No existing, allocate new memory for the block.
if (memoryAllocation == GPGMM_INVALID_ALLOCATION) {
MemoryAllocationRequest newRequest = request;
newRequest.SizeInBytes = mMemorySize;
newRequest.Alignment = mMemoryAlignment;

ResultOrError<std::unique_ptr<MemoryAllocation>> memoryAllocationResult =
GetNextInChain()->TryAllocateMemory(newRequest);
if (!memoryAllocationResult.IsSuccess()) {
return memoryAllocationResult.GetErrorCode();
}

memoryAllocation = *memoryAllocationResult.AcquireResult();
}

MemoryBase* memory = memoryAllocation.GetMemory();
mUsedPool.ReturnToPool(memoryAllocation, memoryIndex);

return memory;
}),
subAllocation);

MemoryBlock* block = subAllocation->GetBlock();
mStats.UsedBlockCount++;
Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/BuddyMemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace gpgmm {
std::unique_ptr<MemoryAllocator> memoryAllocator);

// MemoryAllocator interface
std::unique_ptr<MemoryAllocation> TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> TryAllocateMemory(
const MemoryAllocationRequest& request) override;
void DeallocateMemory(std::unique_ptr<MemoryAllocation> subAllocation) override;

Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/ConditionalMemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace gpgmm {
mConditionalSize(conditionalSize) {
}

std::unique_ptr<MemoryAllocation> ConditionalMemoryAllocator::TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> ConditionalMemoryAllocator::TryAllocateMemory(
const MemoryAllocationRequest& request) {
TRACE_EVENT0(TraceEventCategory::kDefault, "ConditionalMemoryAllocator.TryAllocateMemory");
if (request.SizeInBytes <= mConditionalSize) {
Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/ConditionalMemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace gpgmm {
~ConditionalMemoryAllocator() override = default;

// MemoryAllocator interface
std::unique_ptr<MemoryAllocation> TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> TryAllocateMemory(
const MemoryAllocationRequest& request) override;
void DeallocateMemory(std::unique_ptr<MemoryAllocation> allocation) override;

Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/DedicatedMemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace gpgmm {
: MemoryAllocator(std::move(memoryAllocator)) {
}

std::unique_ptr<MemoryAllocation> DedicatedMemoryAllocator::TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> DedicatedMemoryAllocator::TryAllocateMemory(
const MemoryAllocationRequest& request) {
TRACE_EVENT0(TraceEventCategory::kDefault, "DedicatedMemoryAllocator.TryAllocateMemory");

Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/DedicatedMemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace gpgmm {
DedicatedMemoryAllocator(std::unique_ptr<MemoryAllocator> memoryAllocator);

// MemoryAllocator interface
std::unique_ptr<MemoryAllocation> TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> TryAllocateMemory(
const MemoryAllocationRequest& request) override;
void DeallocateMemory(std::unique_ptr<MemoryAllocation> subAllocation) override;
uint64_t GetMemoryAlignment() const override;
Expand Down
79 changes: 70 additions & 9 deletions src/gpgmm/common/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,82 @@

#include "gpgmm/utils/Assert.h"

#include <utility>

namespace gpgmm {

enum class ErrorCodeType : uint32_t;

constexpr ErrorCodeType kInternalFailureResult = static_cast<ErrorCodeType>(-1);
constexpr ErrorCodeType kInternalSuccessResult = static_cast<ErrorCodeType>(0u);

// Wraps a backend error code with a result object.
// Use Result::IsSuccess then Result::AcquireResult to use or else, use Result::GetErrorCode to
// return the error for backend-specific handling.
template <typename ErrorT, typename ResultT>
class Result {
public:
// Empty result
Result() : mErrorCode(kInternalFailureResult) {
}

// Error only result
Result(ErrorT&& error) : mErrorCode(std::move(error)) {
}

// Result but with no error
Result(ResultT&& result) : mErrorCode(kInternalSuccessResult), mResult(std::move(result)) {
}

// Result with error.
Result(ErrorT&& error, ResultT&& result)
: mErrorCode(std::move(error)), mResult(std::move(result)) {
}

Result(Result<ResultT, ErrorT>&& other)
: mErrorCode(std::move(other.mErrorCode), mResult(std::move(other.mResult))) {
}

Result<ResultT, ErrorT>& operator=(Result<ResultT, ErrorT>&& other) {
mResult = std::move(other.mResult);
mErrorCode = std::move(other.mErrorCode);
return *this;
}

ErrorCodeType GetErrorCode() const {
return mErrorCode;
}

ResultT&& AcquireResult() {
return std::move(mResult);
}

bool IsSuccess() const {
return mErrorCode == kInternalSuccessResult;
}

private:
ErrorT mErrorCode;
ResultT mResult;
};

// Alias of Result + error code to avoid having to always specify error type.
template <typename ResultT>
using ResultOrError = Result<ErrorCodeType, ResultT>;

#define GPGMM_INVALID_ALLOCATION \
MemoryAllocation { \
}

#define GPGMM_TRY_ASSIGN(expr, value) \
{ \
auto result = expr; \
if (GPGMM_UNLIKELY(result == nullptr)) { \
return {}; \
} \
value = std::move(result); \
} \
for (;;) \
#define GPGMM_TRY_ASSIGN(expr, value) \
{ \
auto result = expr; \
if (GPGMM_UNLIKELY(!result.IsSuccess())) { \
return result; \
} \
value = result.AcquireResult(); \
} \
for (;;) \
break

#define GPGMM_INVALID_IF(expr) \
Expand Down
14 changes: 10 additions & 4 deletions src/gpgmm/common/MemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace gpgmm {
mAllocation = mAllocator->TryAllocateMemory(mRequest);
}

std::unique_ptr<MemoryAllocation> AcquireAllocation() {
ResultOrError<std::unique_ptr<MemoryAllocation>> AcquireAllocation() {
std::lock_guard<std::mutex> lock(mAllocationMutex);
return std::move(mAllocation);
}
Expand All @@ -41,7 +41,7 @@ namespace gpgmm {
const MemoryAllocationRequest mRequest;

std::mutex mAllocationMutex;
std::unique_ptr<MemoryAllocation> mAllocation;
ResultOrError<std::unique_ptr<MemoryAllocation>> mAllocation;
};

// MemoryAllocatorStats
Expand Down Expand Up @@ -81,7 +81,8 @@ namespace gpgmm {
return mEvent->Signal();
}

std::unique_ptr<MemoryAllocation> MemoryAllocationEvent::AcquireAllocation() const {
ResultOrError<std::unique_ptr<MemoryAllocation>> MemoryAllocationEvent::AcquireAllocation()
const {
return mTask->AcquireAllocation();
}

Expand Down Expand Up @@ -115,12 +116,17 @@ namespace gpgmm {
}
}

std::unique_ptr<MemoryAllocation> MemoryAllocator::TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> MemoryAllocator::TryAllocateMemory(
const MemoryAllocationRequest& request) {
ASSERT(false);
return {};
}

std::unique_ptr<MemoryAllocation> MemoryAllocator::TryAllocateMemoryForTesting(
const MemoryAllocationRequest& request) {
return TryAllocateMemory(request).AcquireResult();
}

std::shared_ptr<MemoryAllocationEvent> MemoryAllocator::TryAllocateMemoryAsync(
const MemoryAllocationRequest& request) {
std::shared_ptr<AllocateMemoryTask> task =
Expand Down
25 changes: 17 additions & 8 deletions src/gpgmm/common/MemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace gpgmm {

\return Pointer to MemoryAllocation that was allocated.
*/
std::unique_ptr<MemoryAllocation> AcquireAllocation() const;
ResultOrError<std::unique_ptr<MemoryAllocation>> AcquireAllocation() const;

private:
void Signal() override;
Expand Down Expand Up @@ -152,7 +152,12 @@ namespace gpgmm {

\return A pointer to MemoryAllocation. If NULL, the request could not be full-filled.
*/
virtual std::unique_ptr<MemoryAllocation> TryAllocateMemory(
virtual ResultOrError<std::unique_ptr<MemoryAllocation>> TryAllocateMemory(
const MemoryAllocationRequest& request);

// Same as TryAllocateMemory above but leaves the result unwrapped for testing the result
// directly.
std::unique_ptr<MemoryAllocation> TryAllocateMemoryForTesting(
const MemoryAllocationRequest& request);

/** \brief Non-blocking version of TryAllocateMemory.
Expand Down Expand Up @@ -243,17 +248,19 @@ namespace gpgmm {
// or uninitalized memory allocation cannot be created. If memory cannot be allocated for
// the block, the block will be deallocated instead of allowing it to leak.
template <typename GetOrCreateMemoryFn>
static std::unique_ptr<MemoryAllocation> TrySubAllocateMemory(
static ResultOrError<std::unique_ptr<MemoryAllocation>> TrySubAllocateMemory(
BlockAllocator* allocator,
uint64_t requestSize,
uint64_t alignment,
bool neverAllocate,
GetOrCreateMemoryFn&& GetOrCreateMemory) {
MemoryBlock* block = nullptr;
GPGMM_TRY_ASSIGN(allocator->TryAllocateBlock(requestSize, alignment), block);
MemoryBlock* block = allocator->TryAllocateBlock(requestSize, alignment);
if (block == nullptr) {
return {};
}

MemoryBase* memory = GetOrCreateMemory(block);
if (memory == nullptr) {
ResultOrError<MemoryBase*> result = GetOrCreateMemory(block);
if (!result.IsSuccess()) {
// NeverAllocate always fails, so suppress it.
if (!neverAllocate) {
DebugLog() << std::string(allocator->GetTypename()) +
Expand All @@ -262,10 +269,12 @@ namespace gpgmm {
<< std::to_string(block->Offset + block->Size) << ").";
}
allocator->DeallocateBlock(block);
return nullptr;
return result.GetErrorCode();
}

MemoryBase* memory = result.AcquireResult();
ASSERT(memory != nullptr);

memory->AddSubAllocationRef();

// Caller is be responsible in fully initializing the memory allocation.
Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/PooledMemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace gpgmm {
mPool->ReleasePool(kInvalidSize);
}

std::unique_ptr<MemoryAllocation> PooledMemoryAllocator::TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> PooledMemoryAllocator::TryAllocateMemory(
const MemoryAllocationRequest& request) {
TRACE_EVENT0(TraceEventCategory::kDefault, "PooledMemoryAllocator.TryAllocateMemory");

Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/PooledMemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace gpgmm {
~PooledMemoryAllocator() override;

// MemoryAllocator interface
std::unique_ptr<MemoryAllocation> TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> TryAllocateMemory(
const MemoryAllocationRequest& request) override;
void DeallocateMemory(std::unique_ptr<MemoryAllocation> allocation) override;
uint64_t ReleaseMemory(uint64_t bytesToRelease = kInvalidSize) override;
Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/SegmentedMemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ namespace gpgmm {
return newFreeSegment;
}

std::unique_ptr<MemoryAllocation> SegmentedMemoryAllocator::TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> SegmentedMemoryAllocator::TryAllocateMemory(
const MemoryAllocationRequest& request) {
TRACE_EVENT0(TraceEventCategory::kDefault, "SegmentedMemoryAllocator.TryAllocateMemory");

Expand Down
2 changes: 1 addition & 1 deletion src/gpgmm/common/SegmentedMemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace gpgmm {
~SegmentedMemoryAllocator() override;

// MemoryAllocator interface
std::unique_ptr<MemoryAllocation> TryAllocateMemory(
ResultOrError<std::unique_ptr<MemoryAllocation>> TryAllocateMemory(
const MemoryAllocationRequest& request) override;
void DeallocateMemory(std::unique_ptr<MemoryAllocation> allocation) override;
uint64_t ReleaseMemory(uint64_t bytesToRelease = kInvalidSize) override;
Expand Down
Loading