-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ec2fd28
commit 9031451
Showing
3 changed files
with
329 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright (c) 2018-Present Advanced Micro Devices, Inc. See LICENSE.TXT for terms. | ||
|
||
#ifndef INCLUDE_CPPUTILS_ALLOCATOR_H_ | ||
#define INCLUDE_CPPUTILS_ALLOCATOR_H_ | ||
|
||
#include <cassert> | ||
#include <cstdlib> | ||
|
||
#include <memory> | ||
#include <vector> | ||
|
||
namespace cpputils { | ||
|
||
template <typename T> | ||
class AlignedAllocator : public std::allocator<T> { | ||
using Base = std::allocator<T>; | ||
|
||
protected: | ||
size_t mAlign; | ||
|
||
public: | ||
explicit AlignedAllocator(size_t alignment) noexcept : Base(), mAlign(alignment) { | ||
assert(mAlign & 3 == 0 && "lowest alignment must be at least 4 bytes"); | ||
} | ||
|
||
T* allocate(size_t n) const noexcept { return aligned_alloc(mAlign, n); } | ||
|
||
T* allocate(size_t n) override { return const_cast<const AlignedAllocator*>(this)->allocate(n); } | ||
|
||
void deallocate(T* ptr, size_t n) const noexcept { free(ptr); } | ||
|
||
void deallocate(T* ptr, size_t n) override { | ||
const_cast<const AlignedAllocator*>(this)->deallocate(ptr, n); | ||
} | ||
|
||
size_t alignment(void) const noexcept { return mAlign; } | ||
}; | ||
|
||
|
||
/** | ||
* generic resource pool that holds some number of objects of type T | ||
* Objects are created via a static factory class that exposes create and | ||
* destroy methods that work on one object of type T. | ||
*/ | ||
|
||
template <typename T, typename FactoryT, size_t BATCH_SIZE_T> | ||
struct ResourcePool { | ||
constexpr static const size_t BATCH_SIZE = BATCH_SIZE_T; | ||
using value_type = T; | ||
|
||
private: | ||
|
||
using Pool = std::vector<T>; | ||
|
||
Pool mResPool; | ||
FactoryT mFactory; | ||
|
||
|
||
void replenish() noexcept { | ||
assert(mResPool.empty()); | ||
|
||
for (size_t i = 0; i < BATCH_SIZE; ++i) { | ||
mResPool.emplace_back(mFactory.create()); | ||
} | ||
} | ||
|
||
void init() noexcept { | ||
// TODO: add policy on whether to replenish at creation/init or not | ||
replenish(); | ||
} | ||
|
||
void destroy() noexcept { | ||
for (const auto& r: mResPool) { | ||
mFactory.destroy(r); | ||
} | ||
mResPool.clear(); | ||
} | ||
|
||
public: | ||
|
||
explicit ResourcePool(FactoryT&& factory = FactoryT()) noexcept: | ||
mResPool(), | ||
mFactory(std::forward<T>(factory)) | ||
{ | ||
init(); | ||
} | ||
|
||
~ResourcePool() noexcept { | ||
destroy(); | ||
} | ||
|
||
T allocate() noexcept { | ||
if (mResPool.empty()) { | ||
replenish(); | ||
} | ||
|
||
assert(!mResPool.empty()); | ||
|
||
auto obj = mResPool.back(); | ||
mResPool.pop_back(); | ||
return obj; | ||
} | ||
|
||
void deallocate(const T& obj) { | ||
mResPool.push_back(obj); | ||
} | ||
}; | ||
|
||
namespace impl { | ||
template <typename T, typename StaticFactoryT> | ||
struct StaticFactoryWrapper { | ||
|
||
T create() const noexcept { | ||
return StaticFactoryT::create(); | ||
} | ||
|
||
void destroy(const T& obj) const noexcept { | ||
StaticFactoryT::destroy(obj); | ||
} | ||
}; | ||
} | ||
|
||
template <typename T, typename StaticFactoryT, size_t BATCH_SIZE_T> | ||
using ResourcePoolStaticFactory = | ||
ResourcePool<T, impl::StaticFactoryWrapper<T, StaticFactoryT>, BATCH_SIZE_T>; | ||
|
||
|
||
} // end namespace cpputils | ||
|
||
#endif // INCLUDE_CPPUTILS_ALLOCATOR_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright (c) 2018-Present Advanced Micro Devices, Inc. See LICENSE.TXT for terms. | ||
#ifndef INCLUDE_CPPUTILS_HEAP_H_ | ||
#define INCLUDE_CPPUTILS_HEAP_H_ | ||
|
||
#include <cassert> | ||
#include <cstdio> | ||
#include <cstddef> | ||
|
||
#include <vector> | ||
|
||
namespace cpputils { | ||
|
||
template <typename PtrT=char*> | ||
struct MemBlockImpl { | ||
|
||
using pointer = PtrT; | ||
PtrT mBeg = nullptr; | ||
PtrT mEnd = nullptr; | ||
|
||
MemBlockImpl(const PtrT& b, const PtrT& e) : mBeg(b), mEnd(e) {} | ||
|
||
const PtrT& begin(void) const noexcept { return mBeg; } | ||
const PtrT& end(void) const noexcept { return mEnd; } | ||
|
||
size_t size(void) const noexcept { | ||
assert(mEnd >= mBeg); | ||
return static_cast<size_t>(mEnd - mBeg); | ||
} | ||
|
||
ptrdiff_t distance(void) const noexcept { return (mEnd - mBeg); } | ||
|
||
bool empty(void) const noexcept { return mBeg == mEnd; } | ||
}; | ||
|
||
using MemBlock = MemBlockImpl<>; | ||
|
||
/** | ||
* FixedSizeHeap allocates blocks of a fixed size (mAllocSz). It requests a larger block | ||
* from the BackingHeapT and chops it up into smaller blocks of mAllocSz | ||
*/ | ||
template <typename BackingHeapT> | ||
class FixedSizeHeapImpl { | ||
// FIXME(amber): Fixed size heap currently requests huge pages from the | ||
// mBackingHeap but never frees them back until it's destroyed. Freed chunks go in the mFreeBlocks below. | ||
// If we track what chunks belong to which page of BackingHeapT, we can free a | ||
// huge page when all its chunks have been freed by FixedSizeHeap | ||
|
||
using BlockList = std::vector<MemBlock>; | ||
using pointer = char*; | ||
|
||
size_t mAllocSz; | ||
BackingHeapT& mBackingHeap; | ||
BlockList mFreeBlocks; | ||
BlockList mBigBlocks; | ||
|
||
void replenish(void) { | ||
assert(mFreeBlocks.empty()); | ||
|
||
MemBlock bigBlk = mBackingHeap.allocate(); | ||
assert(bigBlk.size() >= mAllocSz && "must allocate at least 1 block of mAllocSz"); | ||
|
||
if (bigBlk.empty()) { | ||
std::fprintf(stderr, "FixedSizeHeapImpl::replenish() : mBackingHeap.allocate() failed\n"); | ||
std::abort(); | ||
} | ||
|
||
mBigBlocks.emplace_back(bigBlk); | ||
|
||
auto* beg = bigBlk.begin(); | ||
auto* end = bigBlk.end(); | ||
for (auto* i = begin; (i+mAllocSz) <= end; i += mAllocSz) { | ||
mFreeBlocks.emplace_back(i, i + mAllocSz); | ||
} | ||
} | ||
|
||
public: | ||
FixedSizeHeapImpl(BackingHeapT& backHeap, const size_t allocSz) | ||
: mAllocSz(allocSz), mBackingHeap(backHeap) { | ||
// TODO(amber) FIXME other fields are default constructed? | ||
// TODO(amber) FIXME: change assert because ALLOCATION_SIZE is undefined? | ||
// assert(BackingHeapT::ALLOCATION_SIZE % mAllocSz == 0 && | ||
// "allocation size must be a factor of CoreHeap::ALLOCATION_SIZE"); | ||
} | ||
|
||
~FixedSizeHeapImpl(void) noexcept { | ||
for (const auto& bigBlk : mBigBlocks) { | ||
mBackingHeap.deallocate(bigBlk); | ||
} | ||
mBigBlocks.clear(); | ||
mFreeBlocks.clear(); | ||
} | ||
|
||
size_t allocationSize(void) const noexcept { return mAllocSz; } | ||
|
||
/** | ||
* allocate without alignment constraints | ||
*/ | ||
MemBlock allocate() noexcept { | ||
if (mFreeBlocks.empty()) { | ||
replenish(); | ||
} | ||
|
||
if (mFreeBlocks.empty()) { | ||
assert(false && "allocation failed due to out of memory"); | ||
return MemBlock{nullptr, nullptr}; | ||
} | ||
|
||
MemBlock ret = mFreeBlocks.back(); | ||
mFreeBlocks.pop_back(); | ||
assert(ret.size() == mAllocSz && "allocation size mismatch. Bad blk"); | ||
return ret; | ||
} | ||
|
||
void deallocate(const MemBlock& blk) { | ||
assert(blk.size() == mAllocSz && "attempting to free a bad blk"); | ||
mFreeBlocks.push_back(blk); | ||
} | ||
}; | ||
|
||
|
||
|
||
|
||
}// end namespace cpputils | ||
|
||
#endif// INCLUDE_CPPUTILS_HEAP_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#ifndef INCLUDE_CPPUTILS_STAT_H_ | ||
#define INCLUDE_CPPUTILS_STAT_H_ | ||
|
||
#include <cassert> | ||
|
||
#include <algorithm> | ||
#include <vector> | ||
|
||
namespace cpputils { | ||
|
||
template <typename T, typename Cont_tp=std::vector<T> > | ||
struct StatSeries { | ||
|
||
using container = Cont_tp; | ||
|
||
Cont_tp mSeries; | ||
|
||
void push_back(const T& val) { | ||
mSeries.emplace_back(val); | ||
} | ||
|
||
void clear() noexcept { | ||
mSeries.clear(); | ||
} | ||
|
||
size_t size(void) const { | ||
return mSeries.size(); | ||
} | ||
|
||
bool empty(void) const { | ||
return mSeries.empty(); | ||
} | ||
|
||
T min(void) const { | ||
assert(!mSeries.empty()); | ||
return *(std::min_element(mSeries.cbegin(), mSeries.cend())); | ||
} | ||
|
||
T max(void) const { | ||
assert(!mSeries.empty()); | ||
return *(std::max_element(mSeries.cbegin(), mSeries.cend())); | ||
} | ||
|
||
std::pair<T,T> range(void) const { | ||
assert(!mSeries.empty()); | ||
auto p = std::minmax_element(mSeries.cbegin(), mSeries.cend()); | ||
return std::make_pair(*p.first, *p.second); | ||
} | ||
|
||
T sum(void) const { | ||
return std::accumulate(mSeries.cbegin(), mSeries.cend(), T()); | ||
} | ||
|
||
template <typename U> | ||
U avg(void) const { | ||
return static_cast<U>(sum()) / static_cast<U>(size()); | ||
} | ||
|
||
template <typename U> | ||
U stdDev(void) const { | ||
U a = avg(); | ||
U sumSqDev = U(); | ||
for (const auto& i: mSeries) { | ||
sumSqDev += (i - a) * (i - a); | ||
} | ||
return std::sqrt(sumSqDev); | ||
} | ||
|
||
}; | ||
|
||
|
||
}// end namespace cpputils | ||
|
||
#endif// INCLUDE_CPPUTILS_STAT_H_ |