Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

168 lines
4.9 KiB
C++

//===- ArrayList.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM 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 LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H
#define LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H
#include "llvm/Support/PerThreadBumpPtrAllocator.h"
#include <atomic>
namespace llvm {
namespace dwarf_linker {
namespace parallel {
/// This class is a simple list of T structures. It keeps elements as
/// pre-allocated groups to save memory for each element's next pointer.
/// It allocates internal data using specified per-thread BumpPtrAllocator.
/// Method add() can be called asynchronously.
template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
public:
ArrayList(llvm::parallel::PerThreadBumpPtrAllocator *Allocator)
: Allocator(Allocator) {}
/// Add specified \p Item to the list.
T &add(const T &Item) {
assert(Allocator);
// Allocate head group if it is not allocated yet.
while (!LastGroup) {
if (allocateNewGroup(GroupsHead))
LastGroup = GroupsHead.load();
}
ItemsGroup *CurGroup;
size_t CurItemsCount;
do {
CurGroup = LastGroup;
CurItemsCount = CurGroup->ItemsCount.fetch_add(1);
// Check whether current group is full.
if (CurItemsCount < ItemsGroupSize)
break;
// Allocate next group if necessary.
if (!CurGroup->Next)
allocateNewGroup(CurGroup->Next);
LastGroup.compare_exchange_weak(CurGroup, CurGroup->Next);
} while (true);
// Store item into the current group.
CurGroup->Items[CurItemsCount] = Item;
return CurGroup->Items[CurItemsCount];
}
using ItemHandlerTy = function_ref<void(T &)>;
/// Enumerate all items and apply specified \p Handler to each.
void forEach(ItemHandlerTy Handler) {
for (ItemsGroup *CurGroup = GroupsHead; CurGroup;
CurGroup = CurGroup->Next) {
for (T &Item : *CurGroup)
Handler(Item);
}
}
/// Check whether list is empty.
bool empty() { return !GroupsHead; }
/// Erase list.
void erase() {
GroupsHead = nullptr;
LastGroup = nullptr;
}
void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) {
SmallVector<T> SortedItems;
forEach([&](T &Item) { SortedItems.push_back(Item); });
if (SortedItems.size()) {
std::sort(SortedItems.begin(), SortedItems.end(), Comparator);
size_t SortedItemIdx = 0;
forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });
assert(SortedItemIdx == SortedItems.size());
}
}
size_t size() {
size_t Result = 0;
for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
CurGroup = CurGroup->Next)
Result += CurGroup->getItemsCount();
return Result;
}
protected:
struct ItemsGroup {
using ArrayTy = std::array<T, ItemsGroupSize>;
// Array of items kept by this group.
ArrayTy Items;
// Pointer to the next items group.
std::atomic<ItemsGroup *> Next = nullptr;
// Number of items in this group.
// NOTE: ItemsCount could be inaccurate as it might be incremented by
// several threads. Use getItemsCount() method to get real number of items
// inside ItemsGroup.
std::atomic<size_t> ItemsCount = 0;
size_t getItemsCount() const {
return std::min(ItemsCount.load(), ItemsGroupSize);
}
typename ArrayTy::iterator begin() { return Items.begin(); }
typename ArrayTy::iterator end() { return Items.begin() + getItemsCount(); }
};
// Allocate new group. Put allocated group into the \p AtomicGroup if
// it is empty. If \p AtomicGroup is filled by another thread then
// put allocated group into the end of groups list.
// \returns true if allocated group is put into the \p AtomicGroup.
bool allocateNewGroup(std::atomic<ItemsGroup *> &AtomicGroup) {
ItemsGroup *CurGroup = nullptr;
// Allocate new group.
ItemsGroup *NewGroup = Allocator->Allocate<ItemsGroup>();
NewGroup->ItemsCount = 0;
NewGroup->Next = nullptr;
// Try to replace current group with allocated one.
if (AtomicGroup.compare_exchange_strong(CurGroup, NewGroup))
return true;
// Put allocated group as last group.
while (CurGroup) {
ItemsGroup *NextGroup = CurGroup->Next;
if (!NextGroup) {
if (CurGroup->Next.compare_exchange_weak(NextGroup, NewGroup))
break;
}
CurGroup = NextGroup;
}
return false;
}
std::atomic<ItemsGroup *> GroupsHead = nullptr;
std::atomic<ItemsGroup *> LastGroup = nullptr;
llvm::parallel::PerThreadBumpPtrAllocator *Allocator = nullptr;
};
} // end of namespace parallel
} // end of namespace dwarf_linker
} // end of namespace llvm
#endif // LLVM_LIB_DWARFLINKER_PARALLEL_ARRAYLIST_H