mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Support: Stop using iplist in Recycler
Recycler just needs a singly-linked list, and it takes less (and simpler) code to hand-roll one of those than to build up the equivalent `iplist_traits`. In theory, this should speed things up a bit too, but this is really just a drive-by cleanup so I haven't measured. llvm-svn: 249615
This commit is contained in:
parent
cb545e4c47
commit
b5929cfe1f
@ -28,53 +28,36 @@ namespace llvm {
|
||||
///
|
||||
void PrintRecyclerStats(size_t Size, size_t Align, size_t FreeListSize);
|
||||
|
||||
/// RecyclerStruct - Implementation detail for Recycler. This is a
|
||||
/// class that the recycler imposes on free'd memory to carve out
|
||||
/// next/prev pointers.
|
||||
struct RecyclerStruct {
|
||||
RecyclerStruct *Prev, *Next;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ilist_traits<RecyclerStruct> :
|
||||
public ilist_default_traits<RecyclerStruct> {
|
||||
static RecyclerStruct *getPrev(const RecyclerStruct *t) { return t->Prev; }
|
||||
static RecyclerStruct *getNext(const RecyclerStruct *t) { return t->Next; }
|
||||
static void setPrev(RecyclerStruct *t, RecyclerStruct *p) { t->Prev = p; }
|
||||
static void setNext(RecyclerStruct *t, RecyclerStruct *n) { t->Next = n; }
|
||||
|
||||
mutable RecyclerStruct Sentinel;
|
||||
RecyclerStruct *createSentinel() const {
|
||||
return &Sentinel;
|
||||
}
|
||||
static void destroySentinel(RecyclerStruct *) {}
|
||||
|
||||
RecyclerStruct *provideInitialHead() const { return createSentinel(); }
|
||||
RecyclerStruct *ensureHead(RecyclerStruct*) const { return createSentinel(); }
|
||||
static void noteHead(RecyclerStruct*, RecyclerStruct*) {}
|
||||
|
||||
static void deleteNode(RecyclerStruct *) {
|
||||
llvm_unreachable("Recycler's ilist_traits shouldn't see a deleteNode call!");
|
||||
}
|
||||
};
|
||||
|
||||
/// Recycler - This class manages a linked-list of deallocated nodes
|
||||
/// and facilitates reusing deallocated memory in place of allocating
|
||||
/// new memory.
|
||||
///
|
||||
template<class T, size_t Size = sizeof(T), size_t Align = AlignOf<T>::Alignment>
|
||||
class Recycler {
|
||||
/// FreeList - Doubly-linked list of nodes that have deleted contents and
|
||||
/// are not in active use.
|
||||
///
|
||||
iplist<RecyclerStruct> FreeList;
|
||||
struct FreeNode {
|
||||
FreeNode *Next;
|
||||
};
|
||||
|
||||
/// List of nodes that have deleted contents and are not in active use.
|
||||
FreeNode *FreeList = nullptr;
|
||||
|
||||
FreeNode *pop_val() {
|
||||
auto *Val = FreeList;
|
||||
FreeList = FreeList->Next;
|
||||
return Val;
|
||||
}
|
||||
|
||||
void push(FreeNode *N) {
|
||||
N->Next = FreeList;
|
||||
FreeList = N;
|
||||
}
|
||||
|
||||
public:
|
||||
~Recycler() {
|
||||
// If this fails, either the callee has lost track of some allocation,
|
||||
// or the callee isn't tracking allocations and should just call
|
||||
// clear() before deleting the Recycler.
|
||||
assert(FreeList.empty() && "Non-empty recycler deleted!");
|
||||
assert(!FreeList && "Non-empty recycler deleted!");
|
||||
}
|
||||
|
||||
/// clear - Release all the tracked allocations to the allocator. The
|
||||
@ -82,8 +65,8 @@ public:
|
||||
/// deleted; calling clear is one way to ensure this.
|
||||
template<class AllocatorType>
|
||||
void clear(AllocatorType &Allocator) {
|
||||
while (!FreeList.empty()) {
|
||||
T *t = reinterpret_cast<T *>(FreeList.remove(FreeList.begin()));
|
||||
while (FreeList) {
|
||||
T *t = reinterpret_cast<T *>(pop_val());
|
||||
Allocator.Deallocate(t);
|
||||
}
|
||||
}
|
||||
@ -93,9 +76,7 @@ public:
|
||||
///
|
||||
/// There is no need to traverse the free list, pulling all the objects into
|
||||
/// cache.
|
||||
void clear(BumpPtrAllocator&) {
|
||||
FreeList.clearAndLeakNodesUnsafely();
|
||||
}
|
||||
void clear(BumpPtrAllocator &) { FreeList = nullptr; }
|
||||
|
||||
template<class SubClass, class AllocatorType>
|
||||
SubClass *Allocate(AllocatorType &Allocator) {
|
||||
@ -103,9 +84,8 @@ public:
|
||||
"Recycler allocation alignment is less than object align!");
|
||||
static_assert(sizeof(SubClass) <= Size,
|
||||
"Recycler allocation size is less than object size!");
|
||||
return !FreeList.empty() ?
|
||||
reinterpret_cast<SubClass *>(FreeList.remove(FreeList.begin())) :
|
||||
static_cast<SubClass *>(Allocator.Allocate(Size, Align));
|
||||
return FreeList ? reinterpret_cast<SubClass *>(pop_val())
|
||||
: static_cast<SubClass *>(Allocator.Allocate(Size, Align));
|
||||
}
|
||||
|
||||
template<class AllocatorType>
|
||||
@ -115,14 +95,20 @@ public:
|
||||
|
||||
template<class SubClass, class AllocatorType>
|
||||
void Deallocate(AllocatorType & /*Allocator*/, SubClass* Element) {
|
||||
FreeList.push_front(reinterpret_cast<RecyclerStruct *>(Element));
|
||||
push(reinterpret_cast<FreeNode *>(Element));
|
||||
}
|
||||
|
||||
void PrintStats() {
|
||||
PrintRecyclerStats(Size, Align, FreeList.size());
|
||||
}
|
||||
void PrintStats();
|
||||
};
|
||||
|
||||
template <class T, size_t Size, size_t Align>
|
||||
void Recycler<T, Size, Align>::PrintStats() {
|
||||
size_t S = 0;
|
||||
for (auto *I = FreeList; I; I = I->Next)
|
||||
++S;
|
||||
PrintRecyclerStats(Size, Align, S);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user