12357e899Savl-llvm //===- ArrayList.h ----------------------------------------------*- C++ -*-===// 22357e899Savl-llvm // 32357e899Savl-llvm // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42357e899Savl-llvm // See https://llvm.org/LICENSE.txt for license information. 52357e899Savl-llvm // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62357e899Savl-llvm // 72357e899Savl-llvm //===----------------------------------------------------------------------===// 82357e899Savl-llvm 92357e899Savl-llvm #ifndef LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H 102357e899Savl-llvm #define LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H 112357e899Savl-llvm 122357e899Savl-llvm #include "llvm/Support/PerThreadBumpPtrAllocator.h" 132357e899Savl-llvm #include <atomic> 142357e899Savl-llvm 152357e899Savl-llvm namespace llvm { 162357e899Savl-llvm namespace dwarf_linker { 172357e899Savl-llvm namespace parallel { 182357e899Savl-llvm 192357e899Savl-llvm /// This class is a simple list of T structures. It keeps elements as 202357e899Savl-llvm /// pre-allocated groups to save memory for each element's next pointer. 212357e899Savl-llvm /// It allocates internal data using specified per-thread BumpPtrAllocator. 222357e899Savl-llvm /// Method add() can be called asynchronously. 232357e899Savl-llvm template <typename T, size_t ItemsGroupSize = 512> class ArrayList { 242357e899Savl-llvm public: ArrayList(llvm::parallel::PerThreadBumpPtrAllocator * Allocator)252357e899Savl-llvm ArrayList(llvm::parallel::PerThreadBumpPtrAllocator *Allocator) 262357e899Savl-llvm : Allocator(Allocator) {} 272357e899Savl-llvm 282357e899Savl-llvm /// Add specified \p Item to the list. add(const T & Item)292357e899Savl-llvm T &add(const T &Item) { 302357e899Savl-llvm assert(Allocator); 312357e899Savl-llvm 322357e899Savl-llvm // Allocate head group if it is not allocated yet. 332357e899Savl-llvm while (!LastGroup) { 342357e899Savl-llvm if (allocateNewGroup(GroupsHead)) 352357e899Savl-llvm LastGroup = GroupsHead.load(); 362357e899Savl-llvm } 372357e899Savl-llvm 382357e899Savl-llvm ItemsGroup *CurGroup; 392357e899Savl-llvm size_t CurItemsCount; 402357e899Savl-llvm do { 412357e899Savl-llvm CurGroup = LastGroup; 422357e899Savl-llvm CurItemsCount = CurGroup->ItemsCount.fetch_add(1); 432357e899Savl-llvm 442357e899Savl-llvm // Check whether current group is full. 452357e899Savl-llvm if (CurItemsCount < ItemsGroupSize) 462357e899Savl-llvm break; 472357e899Savl-llvm 482357e899Savl-llvm // Allocate next group if necessary. 492357e899Savl-llvm if (!CurGroup->Next) 502357e899Savl-llvm allocateNewGroup(CurGroup->Next); 512357e899Savl-llvm 522357e899Savl-llvm LastGroup.compare_exchange_weak(CurGroup, CurGroup->Next); 532357e899Savl-llvm } while (true); 542357e899Savl-llvm 552357e899Savl-llvm // Store item into the current group. 562357e899Savl-llvm CurGroup->Items[CurItemsCount] = Item; 572357e899Savl-llvm return CurGroup->Items[CurItemsCount]; 582357e899Savl-llvm } 592357e899Savl-llvm 602357e899Savl-llvm using ItemHandlerTy = function_ref<void(T &)>; 612357e899Savl-llvm 622357e899Savl-llvm /// Enumerate all items and apply specified \p Handler to each. forEach(ItemHandlerTy Handler)632357e899Savl-llvm void forEach(ItemHandlerTy Handler) { 642357e899Savl-llvm for (ItemsGroup *CurGroup = GroupsHead; CurGroup; 652357e899Savl-llvm CurGroup = CurGroup->Next) { 662357e899Savl-llvm for (T &Item : *CurGroup) 672357e899Savl-llvm Handler(Item); 682357e899Savl-llvm } 692357e899Savl-llvm } 702357e899Savl-llvm 712357e899Savl-llvm /// Check whether list is empty. empty()722357e899Savl-llvm bool empty() { return !GroupsHead; } 732357e899Savl-llvm 742357e899Savl-llvm /// Erase list. erase()752357e899Savl-llvm void erase() { 762357e899Savl-llvm GroupsHead = nullptr; 772357e899Savl-llvm LastGroup = nullptr; 782357e899Savl-llvm } 792357e899Savl-llvm sort(function_ref<bool (const T & LHS,const T & RHS)> Comparator)802357e899Savl-llvm void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) { 812357e899Savl-llvm SmallVector<T> SortedItems; 822357e899Savl-llvm forEach([&](T &Item) { SortedItems.push_back(Item); }); 832357e899Savl-llvm 842357e899Savl-llvm if (SortedItems.size()) { 85*fef144ceSKazu Hirata std::sort(SortedItems.begin(), SortedItems.end(), Comparator); 862357e899Savl-llvm 872357e899Savl-llvm size_t SortedItemIdx = 0; 882357e899Savl-llvm forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; }); 892357e899Savl-llvm assert(SortedItemIdx == SortedItems.size()); 902357e899Savl-llvm } 912357e899Savl-llvm } 922357e899Savl-llvm size()932357e899Savl-llvm size_t size() { 942357e899Savl-llvm size_t Result = 0; 952357e899Savl-llvm 962357e899Savl-llvm for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr; 972357e899Savl-llvm CurGroup = CurGroup->Next) 982357e899Savl-llvm Result += CurGroup->getItemsCount(); 992357e899Savl-llvm 1002357e899Savl-llvm return Result; 1012357e899Savl-llvm } 1022357e899Savl-llvm 1032357e899Savl-llvm protected: 1042357e899Savl-llvm struct ItemsGroup { 1052357e899Savl-llvm using ArrayTy = std::array<T, ItemsGroupSize>; 1062357e899Savl-llvm 1072357e899Savl-llvm // Array of items kept by this group. 1082357e899Savl-llvm ArrayTy Items; 1092357e899Savl-llvm 1102357e899Savl-llvm // Pointer to the next items group. 1112357e899Savl-llvm std::atomic<ItemsGroup *> Next = nullptr; 1122357e899Savl-llvm 1132357e899Savl-llvm // Number of items in this group. 1142357e899Savl-llvm // NOTE: ItemsCount could be inaccurate as it might be incremented by 1152357e899Savl-llvm // several threads. Use getItemsCount() method to get real number of items 1162357e899Savl-llvm // inside ItemsGroup. 1172357e899Savl-llvm std::atomic<size_t> ItemsCount = 0; 1182357e899Savl-llvm getItemsCountItemsGroup1192357e899Savl-llvm size_t getItemsCount() const { 1202357e899Savl-llvm return std::min(ItemsCount.load(), ItemsGroupSize); 1212357e899Savl-llvm } 1222357e899Savl-llvm beginItemsGroup1232357e899Savl-llvm typename ArrayTy::iterator begin() { return Items.begin(); } endItemsGroup1242357e899Savl-llvm typename ArrayTy::iterator end() { return Items.begin() + getItemsCount(); } 1252357e899Savl-llvm }; 1262357e899Savl-llvm 1272357e899Savl-llvm // Allocate new group. Put allocated group into the \p AtomicGroup if 1282357e899Savl-llvm // it is empty. If \p AtomicGroup is filled by another thread then 1292357e899Savl-llvm // put allocated group into the end of groups list. 1302357e899Savl-llvm // \returns true if allocated group is put into the \p AtomicGroup. allocateNewGroup(std::atomic<ItemsGroup * > & AtomicGroup)1312357e899Savl-llvm bool allocateNewGroup(std::atomic<ItemsGroup *> &AtomicGroup) { 1322357e899Savl-llvm ItemsGroup *CurGroup = nullptr; 1332357e899Savl-llvm 1342357e899Savl-llvm // Allocate new group. 1352357e899Savl-llvm ItemsGroup *NewGroup = Allocator->Allocate<ItemsGroup>(); 1362357e899Savl-llvm NewGroup->ItemsCount = 0; 1372357e899Savl-llvm NewGroup->Next = nullptr; 1382357e899Savl-llvm 1392357e899Savl-llvm // Try to replace current group with allocated one. 1402357e899Savl-llvm if (AtomicGroup.compare_exchange_weak(CurGroup, NewGroup)) 1412357e899Savl-llvm return true; 1422357e899Savl-llvm 1432357e899Savl-llvm // Put allocated group as last group. 1442357e899Savl-llvm while (CurGroup) { 1452357e899Savl-llvm ItemsGroup *NextGroup = CurGroup->Next; 1462357e899Savl-llvm 1472357e899Savl-llvm if (!NextGroup) { 1482357e899Savl-llvm if (CurGroup->Next.compare_exchange_weak(NextGroup, NewGroup)) 1492357e899Savl-llvm break; 1502357e899Savl-llvm } 1512357e899Savl-llvm 1522357e899Savl-llvm CurGroup = NextGroup; 1532357e899Savl-llvm } 1542357e899Savl-llvm 1552357e899Savl-llvm return false; 1562357e899Savl-llvm } 1572357e899Savl-llvm 1582357e899Savl-llvm std::atomic<ItemsGroup *> GroupsHead = nullptr; 1592357e899Savl-llvm std::atomic<ItemsGroup *> LastGroup = nullptr; 1602357e899Savl-llvm llvm::parallel::PerThreadBumpPtrAllocator *Allocator = nullptr; 1612357e899Savl-llvm }; 1622357e899Savl-llvm 1632357e899Savl-llvm } // end of namespace parallel 1642357e899Savl-llvm } // end of namespace dwarf_linker 1652357e899Savl-llvm } // end of namespace llvm 1662357e899Savl-llvm 1672357e899Savl-llvm #endif // LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H 168