Skip to content
Open
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
41 changes: 41 additions & 0 deletions source/common/unified_malloc_framework/include/umf/memory_pool.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <umf/base.h>
#include <umf/memory_pool.h>
#include <umf/memory_provider.hpp>

namespace umf
{
namespace polymorphic
{

struct memory_pool {
virtual void *malloc(size_t size) = 0;
virtual void *calloc(size_t, size_t) = 0;
virtual void *realloc(void *, size_t) = 0;
virtual void *aligned_malloc(size_t size, size_t alignment) = 0;
virtual size_t malloc_usable_size(void *) = 0;
virtual void free(void *ptr) = 0;
};

// wraps c handle in c++ type
struct memory_pool_c : public memory_pool {
memory_pool_c(umf_memory_pool_handle_t hPool): hPool(hPool) {}
void *malloc(size_t size) {return umfPoolMalloc(hPool, size);} // TODO: check last_allocation_error and throw?
void *calloc(size_t num, size_t size) {return umfPoolCalloc(hPool, num, size);} // TODO: check last_allocation_error and throw?
void *realloc(void *ptr, size_t size) {return umfPoolRealloc(hPool, ptr, size);} // TODO: check last_allocation_error and throw?
void *aligned_malloc(size_t size, size_t alignment) {return umfPoolAlignedMalloc(hPool, size, alignment);} // TODO: check last_allocation_error and throw?
size_t malloc_usable_size(void *ptr) {return umfPoolMallocUsableSize(hPool, ptr);}
void free(void *ptr) {return umfPoolFree(hPool, ptr);}
private:
umf_memory_pool_handle_t hPool;
};

}

// creates c handle from a c++ type, fills ops struct, call pool_create, etc.
template <typename Pool, typename... Args> // could be constrained by concept
umf_memory_pool_handle_t memoryPoolHandleCreate(Args&&...) {
// implementation as in umf_helpers.hpp or similar
return nullptr;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <umf/base.h>
#include <umf/memory_provider.h>

namespace umf
{
namespace polymorphic
{

struct memory_provider {
virtual enum umf_result_t alloc(size_t, size_t, void **) = 0;
virtual enum umf_result_t free(void *ptr, size_t size) = 0;
virtual enum umf_result_t get_recommended_page_size(size_t size,
size_t *pageSize)= 0;
virtual enum umf_result_t get_min_page_size(void *ptr, size_t *pageSize) = 0;
virtual enum umf_result_t purge_lazy(void *ptr, size_t size) = 0;
virtual enum umf_result_t purge_force(void *ptr, size_t size) = 0;
virtual const char *get_name() = 0;
};

// wraps c handle in c++ type
struct memory_provider_c : public memory_provider {
memory_provider_c(umf_memory_provider_handle_t hProvider): hProvider(hProvider) {}
enum umf_result_t alloc(size_t size, size_t align, void **ptr) {return umfMemoryProviderAlloc(hProvider, size, align, ptr);}
enum umf_result_t free(void *ptr, size_t size) {return umfMemoryProviderFree(hProvider, ptr, size);}
enum umf_result_t get_recommended_page_size(size_t size,
size_t *pageSize) {return umfMemoryProviderGetRecommendedPageSize(hProvider, size, pageSize);}
enum umf_result_t get_min_page_size(void *ptr, size_t *pageSize) {return umfMemoryProviderGetMinPageSize(hProvider, ptr, pageSize);}
enum umf_result_t purge_lazy(void *ptr, size_t size) {return umfMemoryProviderPurgeLazy(hProvider, ptr, size);}
enum umf_result_t purge_force(void *ptr, size_t size) {return umfMemoryProviderPurgeForce(hProvider, ptr, size);}
const char *get_name() {return umfMemoryProviderGetName(hProvider);}
private:
umf_memory_provider_handle_t hProvider;
};

}

// creates c handle from a c++ type, fills ops struct, call provider_create, etc.
template <typename Provider, typename... Args> // could be constrained by concept
umf_memory_provider_handle_t memoryProviderHandleCreate(Args&&...) {
// implementation as in umf_helpers.hpp or similar
return nullptr;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <umf/base.h>
#include <umf/memory_provider.h>
#include <umf/memory_pool.h>

struct UmfDisjointPoolConfig {
// Minimum allocation size that will be requested from the system.
// By default this is the minimum allocation size of each memory type.
size_t SlabMinSize = 0;

// Allocations up to this limit will be subject to chunking/pooling
size_t MaxPoolableSize = 0;

// When pooling, each bucket will hold a max of 4 unfreed slabs
size_t Capacity = 0;

// Holds the minimum bucket size valid for allocation of a memory type.
size_t MinBucketSize = 0;

// Holds size of the pool managed by the allocator.
size_t CurPoolSize = 0;

// Whether to print pool usage statistics
int PoolTrace = 0;
};

umf_memory_pool_handle_t umfCreateDisjointPool(umf_memory_provider_handle_t upstream, umf_memory_provider_handle_t metadata, struct UmfDisjointPoolConfig *config);
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//===---------- disjoint_pool.hpp - Allocator for USM memory --------------===//
//
// Part of the Unified-Runtime Project, 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
//
//===----------------------------------------------------------------------===//

#ifndef DISJOINT_POOL
#define DISJOINT_POOL

#include <atomic>
#include <memory>
#include <string>

#include <umf/base.h>
#include <umf/memory_provider.hpp>

namespace umf {

// Configuration for specific USM allocator instance
class DisjointPoolConfig {
public:
DisjointPoolConfig();

std::string name = "";

struct SharedLimits {
SharedLimits() : TotalSize(0) {}

// Maximum memory left unfreed
size_t MaxSize = 16 * 1024 * 1024;

// Total size of pooled memory
std::atomic<size_t> TotalSize;
};

// Minimum allocation size that will be requested from the system.
// By default this is the minimum allocation size of each memory type.
size_t SlabMinSize = 0;

// Allocations up to this limit will be subject to chunking/pooling
size_t MaxPoolableSize = 0;

// When pooling, each bucket will hold a max of 4 unfreed slabs
size_t Capacity = 0;

// Holds the minimum bucket size valid for allocation of a memory type.
size_t MinBucketSize = 0;

// Holds size of the pool managed by the allocator.
size_t CurPoolSize = 0;

// Whether to print pool usage statistics
int PoolTrace = 0;

std::shared_ptr<SharedLimits> limits;
};

class DisjointPool {
public:
class AllocImpl;
using Config = DisjointPoolConfig;

// DisjointPool accepts providers as pointers to polymorphic types but other implementations could
// just accept a template arguments that match 'memory_provider' concept (or pass some other checks pre-c++20)
DisjointPool(std::unique_ptr<polymorphic::memory_provider> upstream, std::unique_ptr<polymorphic::memory_provider> metadata, DisjointPoolConfig parameters);
void *malloc(size_t size);
void *calloc(size_t, size_t);
void *realloc(void *, size_t);
void *aligned_malloc(size_t size, size_t alignment);
size_t malloc_usable_size(void *);
void free(void *ptr);

DisjointPool();
~DisjointPool();

private:
std::unique_ptr<AllocImpl> impl;
};

} // namespace umf

#endif
18 changes: 18 additions & 0 deletions source/common/unified_malloc_framework/src/disjoint_pool.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "disjoint_pool.h"
#include "disjoint_pool.hpp"

#include "memory_pool.hpp"
#include "memory_provider.hpp"

extern "C" umf_memory_pool_handle_t
umfCreateDisjointPool(umf_memory_provider_handle_t upstream, umf_memory_provider_handle_t metadata, struct UmfDisjointPoolConfig *config) {
umf::DisjointPoolConfig cpp_config;
// translate config to cpp_config
cpp_config.Capacity = config->Capacity;
// ...

return umf::memoryPoolHandleCreate<umf::DisjointPool>(
std::unique_ptr<umf::polymorphic::memory_provider>(new umf::polymorphic::memory_provider_c(upstream)),
std::unique_ptr<umf::polymorphic::memory_provider>(new umf::polymorphic::memory_provider_c(metadata)),
cpp_config);
}