Skip to content

Commit

Permalink
Fixed: sparse_storage id->page index
Browse files Browse the repository at this point in the history
Added: custom storage for ilist
Changed: JobManager job data stored in a sparse set now
  • Loading branch information
richardbiely committed Nov 24, 2024
1 parent 5bd7d06 commit 5343606
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 84 deletions.
7 changes: 4 additions & 3 deletions include/gaia/cnt/ilist.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ namespace gaia {

//! Implicit list. Rather than with pointers, items \tparam TListItem are linked
//! together through an internal indexing mechanism. To the outside world they are
//! presented as \tparam TItemHandle.
//! presented as \tparam TItemHandle. All items are stored in a container instance
//! of the type \tparam TInternalStorage.
//! \tparam TListItem needs to have idx and gen variables and expose a constructor
//! that initializes them.
template <typename TListItem, typename TItemHandle>
template <typename TListItem, typename TItemHandle, typename TInternalStorage = cnt::darray<TListItem>>
struct ilist {
using internal_storage = cnt::darray<TListItem>;
using internal_storage = TInternalStorage;
// TODO: replace this iterator with a real list iterator
using iterator = typename internal_storage::iterator;

Expand Down
70 changes: 42 additions & 28 deletions include/gaia/cnt/sparse_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ namespace gaia {
using iterator = sparse_iterator;

private:
constexpr static detail::size_type to_page_index = core::count_bits(PageCapacity);
static_assert((PageCapacity & (PageCapacity - 1)) == 0, "PageCapacity of sparse_iterator must be a power of 2");
constexpr static detail::size_type page_mask = PageCapacity - 1;
constexpr static detail::size_type to_page_index = core::count_bits(page_mask);

using page_type = detail::sparse_page<T, PageCapacity, Allocator, void>;

uint32_t* m_pDense;
Expand All @@ -61,14 +64,14 @@ namespace gaia {
reference operator*() const {
const auto sid = *m_pDense;
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
auto& page = m_pPages[pid];
return page.set_data(did);
}
pointer operator->() const {
const auto sid = *m_pDense;
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
auto& page = m_pPages[pid];
return &page.set_data(did);
}
Expand Down Expand Up @@ -144,7 +147,10 @@ namespace gaia {
using iterator = sparse_iterator;

private:
constexpr static detail::size_type to_page_index = core::count_bits(PageCapacity);
static_assert((PageCapacity & (PageCapacity - 1)) == 0, "PageCapacity of sparse_iterator must be a power of 2");
constexpr static detail::size_type page_mask = PageCapacity - 1;
constexpr static detail::size_type to_page_index = core::count_bits(page_mask);

using page_type = detail::sparse_page<T, PageCapacity, Allocator, std::enable_if_t<std::is_empty_v<T>>>;

uint32_t* m_pDense;
Expand Down Expand Up @@ -232,7 +238,11 @@ namespace gaia {
using iterator = sparse_iterator_soa;

private:
constexpr static detail::size_type to_page_index = core::count_bits(PageCapacity);
static_assert(
(PageCapacity & (PageCapacity - 1)) == 0, "PageCapacity of sparse_iterator_soa must be a power of 2");
constexpr static detail::size_type page_mask = PageCapacity - 1;
constexpr static detail::size_type to_page_index = core::count_bits(page_mask);

using page_type = detail::sparse_page<T, PageCapacity, Allocator, void>;

uint32_t* m_pDense;
Expand All @@ -244,14 +254,14 @@ namespace gaia {
value_type operator*() const {
const auto sid = *m_pDense;
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
const auto& page = m_pPages[pid];
return page.get_data(did);
}
value_type operator->() const {
const auto sid = *m_pDense;
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
const auto& page = m_pPages[pid];
return page.get_data(did);
}
Expand Down Expand Up @@ -860,7 +870,9 @@ namespace gaia {
using page_type = detail::sparse_page<T, PageCapacity, Allocator>;

private:
constexpr static detail::size_type to_page_index = core::count_bits(PageCapacity);
static_assert((PageCapacity & (PageCapacity - 1)) == 0, "PageCapacity of sparse_storage must be a power of 2");
constexpr static detail::size_type page_mask = PageCapacity - 1;
constexpr static detail::size_type to_page_index = core::count_bits(page_mask);

//! Contains mappings to sparse storage inside pages
cnt::darray<sparse_id> m_dense;
Expand Down Expand Up @@ -937,7 +949,7 @@ namespace gaia {
GAIA_NODISCARD decltype(auto) operator[](size_type sid) noexcept {
GAIA_ASSERT(has(sid));
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

auto& page = m_pages[pid];
return view_policy::set({(typename view_policy::TargetCastType)page.data(), PageCapacity}, did);
Expand All @@ -946,7 +958,7 @@ namespace gaia {
GAIA_NODISCARD decltype(auto) operator[](size_type sid) const noexcept {
GAIA_ASSERT(has(sid));
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

auto& page = m_pages[pid];
return view_policy::get({(typename view_policy::TargetCastType)page.data(), PageCapacity}, did);
Expand All @@ -963,7 +975,7 @@ namespace gaia {
if (pid >= m_pages.size())
return false;

const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
const auto id = m_pages[pid].get_id(did);
return id != detail::InvalidId;
}
Expand All @@ -985,14 +997,14 @@ namespace gaia {
return;
else {
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
auto& page = m_pages[pid];
return page.set_data(did);
}
}

const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

try_grow(pid);
m_dense[m_cnt] = sid;
Expand All @@ -1014,14 +1026,14 @@ namespace gaia {
return;
else {
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
auto& page = m_pages[pid];
return page.set_data(did);
}
}

const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

try_grow(pid);
m_dense[m_cnt] = sid;
Expand All @@ -1040,7 +1052,7 @@ namespace gaia {
GAIA_ASSERT(has(sid));

const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

auto& page = m_pages[pid];
return page.set_data(did);
Expand All @@ -1055,10 +1067,10 @@ namespace gaia {
return;

const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

const auto sidLast = m_dense[m_cnt - 1];
const auto didLast = sidLast & (PageCapacity - 1);
const auto didLast = sidLast & page_mask;

auto& page = m_pages[pid];
const auto id = page.get_id(did);
Expand Down Expand Up @@ -1115,7 +1127,7 @@ namespace gaia {

const auto sid = m_dense[m_cnt - 1];
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

if constexpr (mem::is_soa_layout_v<T>)
return m_pages[pid].set_data(did);
Expand All @@ -1128,7 +1140,7 @@ namespace gaia {

const auto sid = m_dense[m_cnt - 1];
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

if constexpr (mem::is_soa_layout_v<T>)
return m_pages[pid].get_data(did);
Expand Down Expand Up @@ -1172,7 +1184,7 @@ namespace gaia {
for (size_type i = 0, cnt = 0; i < n && cnt < m_cnt; ++i, ++cnt) {
const auto sid = m_dense[i];
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

const auto& item0 = m_pages[pid].get_data(did);
const auto& item1 = m_pages[pid].get_data(did);
Expand Down Expand Up @@ -1208,7 +1220,9 @@ namespace gaia {
using page_type = detail::sparse_page<T, PageCapacity, Allocator, std::enable_if_t<std::is_empty_v<T>>>;

private:
constexpr static detail::size_type to_page_index = core::count_bits(PageCapacity);
static_assert((PageCapacity & (PageCapacity - 1)) == 0, "PageCapacity of sparse_storage must be a power of 2");
constexpr static detail::size_type page_mask = PageCapacity - 1;
constexpr static detail::size_type to_page_index = core::count_bits(page_mask);

//! Contains mappings to sparse storage inside pages
cnt::darray<sparse_id> m_dense;
Expand Down Expand Up @@ -1287,7 +1301,7 @@ namespace gaia {
if (pid >= m_pages.size())
return false;

const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;
const auto id = m_pages[pid].get_id(did);
return id != detail::InvalidId;
}
Expand All @@ -1299,7 +1313,7 @@ namespace gaia {
return;

const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

try_grow(pid);
m_dense[m_cnt] = sid;
Expand All @@ -1317,10 +1331,10 @@ namespace gaia {
return;

const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

const auto sidLast = m_dense[m_cnt - 1];
const auto didLast = sidLast & (PageCapacity - 1);
const auto didLast = sidLast & page_mask;

auto& page = m_pages[pid];
const auto id = page.get_id(did);
Expand Down Expand Up @@ -1364,7 +1378,7 @@ namespace gaia {

const auto sid = m_dense[m_cnt - 1];
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

return (reference)m_pages[pid].set_id(did);
}
Expand All @@ -1374,7 +1388,7 @@ namespace gaia {

const auto sid = m_dense[m_cnt - 1];
const auto pid = sid >> to_page_index;
const auto did = sid & (PageCapacity - 1);
const auto did = sid & page_mask;

return (const_reference)m_pages[pid].get_id(did);
}
Expand Down
31 changes: 27 additions & 4 deletions include/gaia/mt/jobmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,26 @@
#include <inttypes.h>

#include "../cnt/ilist.h"
#include "../cnt/sparse_storage.h"
#include "../core/span.h"
#include "../mem/mem_alloc.h"
#include "jobcommon.h"
#include "jobhandle.h"
#include "threadpool.h"

#define GAIA_LOG_JOB_STATES 0

namespace gaia {
namespace mt {
struct JobContainer;
}

namespace cnt {
template <>
struct to_sparse_id<mt::JobContainer> {
static sparse_id get(const mt::JobContainer& item) noexcept;
};
} // namespace cnt

namespace mt {
enum JobState : uint32_t {
DEP_BITS_START = 0,
Expand Down Expand Up @@ -144,10 +155,16 @@ namespace gaia {
}
};

class ilist_sparse_storageset_wrapper: public cnt::sparse_storage<JobContainer, 256> {
public:
void push_back(JobContainer&& container) {
add(GAIA_MOV(container));
}
};

class JobManager {
//! Implicit list of jobs
//! TODO: Implement paged allocation
cnt::ilist<JobContainer, JobHandle> m_jobData;
//! Implicit list of jobs. Page allocated, memory addresses are always fixed.
cnt::ilist<JobContainer, JobHandle, ilist_sparse_storageset_wrapper> m_jobData;

public:
JobContainer& data(JobHandle jobHandle) {
Expand Down Expand Up @@ -364,4 +381,10 @@ namespace gaia {
}
} // namespace detail
} // namespace mt

namespace cnt {
inline sparse_id to_sparse_id<mt::JobContainer>::get(const mt::JobContainer& item) noexcept {
return item.idx;
}
} // namespace cnt
} // namespace gaia
1 change: 0 additions & 1 deletion include/gaia/mt/jobqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <mutex>

#include "../cnt/sarray.h"
#include "../cnt/sringbuffer.h"
#include "../config/profiler.h"
#include "../core/utility.h"
#include "jobhandle.h"
Expand Down
11 changes: 4 additions & 7 deletions include/gaia/mt/threadpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ namespace gaia {
//! Manager for internal jobs
JobManager m_jobManager;
//! Job allocation mutex
//! TODO: Remove this once JobManager implements paged allocation for m_jobData
// NOTE: Allocs are done only from the main thread while there are no jobs running.
// Freeing can happen at any point from any thread. Therefore, we need to lock this point.
// Access do job data is not thread-safe. No jobs should be added while there is any job running.
GAIA_PROF_MUTEX(std::mutex, m_jobAllocMtx);

private:
Expand Down Expand Up @@ -244,15 +246,14 @@ namespace gaia {

//! Creates a threadpool job from \param job.
//! \warning Must be used from the main thread.
//! \warning Can't be called while there are any jobs being executed.
//! \return Job handle of the scheduled job.
template <typename TJob>
JobHandle add(TJob&& job) {
GAIA_ASSERT(main_thread());

job.priority = final_prio(job);

// Allocs are done only from the main thread while there are no jobs running.
// Freeing can happen at any point from any thread. Therefore, we need to lock this point.
auto& mtx = GAIA_PROF_EXTRACT_MUTEX(std::mutex, m_jobAllocMtx);
std::lock_guard lock(mtx);
return m_jobManager.alloc_job(GAIA_FWD(job));
Expand All @@ -263,8 +264,6 @@ namespace gaia {
GAIA_ASSERT(main_thread());
GAIA_ASSERT(!jobHandles.empty());

// Allocs are done only from the main thread while there are no jobs running.
// Freeing can happen at any point from any thread. Therefore, we need to lock this point.
auto& mtx = GAIA_PROF_EXTRACT_MUTEX(std::mutex, m_jobAllocMtx);
std::lock_guard lock(mtx);
for (auto& jobHandles: jobHandles)
Expand All @@ -285,8 +284,6 @@ namespace gaia {
}
#endif

// Allocs are done only from the main thread while there are no jobs running.
// Freeing can happen at any point from any thread. Therefore, we need to lock this point.
auto& mtx = GAIA_PROF_EXTRACT_MUTEX(std::mutex, m_jobAllocMtx);
std::lock_guard lock(mtx);
m_jobManager.free_job(jobHandle);
Expand Down
Loading

0 comments on commit 5343606

Please sign in to comment.