Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a pipe operation to ranges #527

Merged
merged 4 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 38 additions & 31 deletions src/snmalloc/backend/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ namespace snmalloc
#endif

// Set up source of memory
using P = PalRange<PAL>;
using Base = std::conditional_t<
fixed_range,
EmptyRange,
PagemapRegisterRange<Pagemap, P, CONSOLIDATE_PAL_ALLOCS>>;
Pipe<
PalRange<Pal>,
PagemapRegisterRange<Pagemap, CONSOLIDATE_PAL_ALLOCS>>>;

static constexpr size_t MinBaseSizeBits()
{
Expand All @@ -117,50 +118,56 @@ namespace snmalloc
}

// Global range of memory
using GlobalR = GlobalRange<LogRange<
2,
LargeBuddyRange<Base, 24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>>>;
using GlobalR = Pipe<
Base,
LargeBuddyRange<24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>,
LogRange<2>,
GlobalRange<>>;

#ifdef SNMALLOC_META_PROTECTED
// Introduce two global ranges, so we don't mix Object and Meta
using CentralObjectRange = GlobalRange<LogRange<
3,
LargeBuddyRange<
GlobalR,
24,
bits::BITS - 1,
Pagemap,
MinBaseSizeBits()>>>;
using CentralMetaRange = GlobalRange<LogRange<
4,
LargeBuddyRange<
SubRange<GlobalR, PAL, 6>, // Use SubRange to introduce guard pages.
24,
bits::BITS - 1,
Pagemap,
MinBaseSizeBits()>>>;
using CentralObjectRange = Pipe<
GlobalR,
LargeBuddyRange<24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>,
LogRange<3>,
GlobalRange<>>;

using CentralMetaRange = Pipe<
GlobalR,
SubRange<PAL, 6>, // Use SubRange to introduce guard pages.
LargeBuddyRange<24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>,
LogRange<4>,
GlobalRange<>>;

// Source for object allocations
using StatsObject = StatsRange<CommitRange<CentralObjectRange, PAL>>;
using StatsObject =
Pipe<CentralObjectRange, CommitRange<PAL>, StatsRange<>>;

using ObjectRange =
LogRange<5, LargeBuddyRange<StatsObject, 21, 21, Pagemap>>;
Pipe<StatsObject, LargeBuddyRange<21, 21, Pagemap>, LogRange<5>>;

using StatsMeta = Pipe<CentralMetaRange, CommitRange<PAL>, StatsRange<>>;

using StatsMeta = StatsRange<CommitRange<CentralMetaRange, PAL>>;
using MetaRange = Pipe<
StatsMeta,
LargeBuddyRange<21 - 6, bits::BITS - 1, Pagemap>,
SmallBuddyRange<>>;

using MetaRange = SmallBuddyRange<
LargeBuddyRange<StatsMeta, 21 - 6, bits::BITS - 1, Pagemap>>;
// Create global range that can service small meta-data requests.
// Don't want to add this to the CentralMetaRange to move Commit outside the
// lock on the common case.
using GlobalMetaRange = GlobalRange<SmallBuddyRange<StatsMeta>>;
using GlobalMetaRange = Pipe<StatsMeta, SmallBuddyRange<>, GlobalRange<>>;
using Stats = StatsCombiner<StatsObject, StatsMeta>;
#else
// Source for object allocations and metadata
// No separation between the two
using Stats = StatsRange<GlobalR>;
using ObjectRange = SmallBuddyRange<
LargeBuddyRange<CommitRange<Stats, PAL>, 21, 21, Pagemap>>;
using GlobalMetaRange = GlobalRange<ObjectRange>;
using Stats = Pipe<GlobalR, StatsRange<>>;
using ObjectRange = Pipe<
Stats,
CommitRange<PAL>,
LargeBuddyRange<21, 21, Pagemap>,
SmallBuddyRange<>>;
using GlobalMetaRange = Pipe<ObjectRange, GlobalRange<>>;
#endif

struct LocalState
Expand Down
10 changes: 8 additions & 2 deletions src/snmalloc/backend_helpers/commitrange.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
#pragma once

#include "../pal/pal.h"
#include "empty_range.h"

namespace snmalloc
{
template<typename ParentRange, typename PAL>
template<typename PAL, typename ParentRange = EmptyRange>
class CommitRange
{
ParentRange parent{};

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = CommitRange<PAL, ParentRange2>;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little sad that we have to repeat this for every Range type, but I can't see a way to avoid it. AFAICT, even with CRTP-esque stunts we still need to say exactly something like this anyway, so it doesn't help to have a CRTP parent class.

(Would that we had higher-kinded template types more generally, as we kind of do over in concepts land, but that is tricky with defaulting, so we don't get it in general and so we can't take advantage of the fact that it's always the last argument to the Range class templates that we want to use when Pipe-ing.)

static constexpr bool Aligned = ParentRange::Aligned;

static constexpr bool ConcurrencySafe = ParentRange::ConcurrencySafe;
Expand Down
9 changes: 8 additions & 1 deletion src/snmalloc/backend_helpers/globalrange.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#pragma once

#include "../ds/ds.h"
#include "empty_range.h"

namespace snmalloc
{
/**
* Makes the supplied ParentRange into a global variable,
* and protects access with a lock.
*/
template<typename ParentRange>
template<typename ParentRange = EmptyRange>
class GlobalRange
{
SNMALLOC_REQUIRE_CONSTINIT static inline ParentRange parent{};
Expand All @@ -20,6 +21,12 @@ namespace snmalloc
SNMALLOC_REQUIRE_CONSTINIT static inline FlagWord spin_lock{};

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = GlobalRange<ParentRange2>;

static constexpr bool Aligned = ParentRange::Aligned;

static constexpr bool ConcurrencySafe = true;
Expand Down
16 changes: 14 additions & 2 deletions src/snmalloc/backend_helpers/largebuddyrange.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "../ds/ds.h"
#include "../mem/mem.h"
#include "buddy.h"
#include "empty_range.h"
#include "range_helpers.h"

#include <string>
Expand Down Expand Up @@ -183,11 +184,11 @@ namespace snmalloc
* for
*/
template<
typename ParentRange,
size_t REFILL_SIZE_BITS,
size_t MAX_SIZE_BITS,
SNMALLOC_CONCEPT(ConceptBuddyRangeMeta) Pagemap,
size_t MIN_REFILL_SIZE_BITS = 0>
size_t MIN_REFILL_SIZE_BITS = 0,
typename ParentRange = EmptyRange>
class LargeBuddyRange
{
ParentRange parent{};
Expand Down Expand Up @@ -327,6 +328,17 @@ namespace snmalloc
}

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
mjp41 marked this conversation as resolved.
Show resolved Hide resolved
using Apply = LargeBuddyRange<
REFILL_SIZE_BITS,
MAX_SIZE_BITS,
Pagemap,
MIN_REFILL_SIZE_BITS,
ParentRange2>;

static constexpr bool Aligned = true;

static constexpr bool ConcurrencySafe = false;
Expand Down
10 changes: 9 additions & 1 deletion src/snmalloc/backend_helpers/logrange.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include "empty_range.h"

namespace snmalloc
{
/**
Expand All @@ -8,12 +10,18 @@ namespace snmalloc
*
* ParentRange is what the range is logging calls to.
*/
template<size_t RangeName, typename ParentRange>
template<size_t RangeName, typename ParentRange = EmptyRange>
class LogRange
{
ParentRange parent{};

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = LogRange<RangeName, ParentRange2>;

static constexpr bool Aligned = ParentRange::Aligned;

static constexpr bool ConcurrencySafe = ParentRange::ConcurrencySafe;
Expand Down
11 changes: 9 additions & 2 deletions src/snmalloc/backend_helpers/pagemapregisterrange.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
#pragma once

#include "../pal/pal.h"
#include "empty_range.h"

namespace snmalloc
{
template<
SNMALLOC_CONCEPT(ConceptBackendMetaRange) Pagemap,
typename ParentRange,
bool CanConsolidate = true>
bool CanConsolidate = true,
typename ParentRange = EmptyRange>
class PagemapRegisterRange
{
ParentRange state{};

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = PagemapRegisterRange<Pagemap, CanConsolidate, ParentRange2>;

constexpr PagemapRegisterRange() = default;

static constexpr bool Aligned = ParentRange::Aligned;
Expand Down
35 changes: 35 additions & 0 deletions src/snmalloc/backend_helpers/range_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,39 @@ namespace snmalloc
length -= align;
}
}

/**
* Forward definition to allow multiple template specialisations.
*
* This struct is used to recursively compose ranges.
*/
template<typename... Args>
struct PipeImpl;

/**
* Base case of one range that needs nothing.
*/
template<typename Only>
struct PipeImpl<Only>
{
using result = Only;
};

/**
* Recursive case of applying a base range as an argument to the
* next, and then using that as the new base range.
*/
template<typename First, typename Fun, typename... Rest>
struct PipeImpl<First, Fun, Rest...>
{
public:
using result =
typename PipeImpl<typename Fun::template Apply<First>, Rest...>::result;
};

/**
* Nice type so the caller doesn't need to call result explicitly.
*/
template<typename... Args>
using Pipe = typename PipeImpl<Args...>::result;
} // namespace snmalloc
9 changes: 8 additions & 1 deletion src/snmalloc/backend_helpers/smallbuddyrange.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "../pal/pal.h"
#include "empty_range.h"
#include "range_helpers.h"

namespace snmalloc
Expand Down Expand Up @@ -142,7 +143,7 @@ namespace snmalloc
}
};

template<typename ParentRange>
template<typename ParentRange = EmptyRange>
class SmallBuddyRange
{
ParentRange parent{};
Expand Down Expand Up @@ -179,6 +180,12 @@ namespace snmalloc
}

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = SmallBuddyRange<ParentRange2>;

static constexpr bool Aligned = true;
static_assert(ParentRange::Aligned, "ParentRange must be aligned");

Expand Down
10 changes: 9 additions & 1 deletion src/snmalloc/backend_helpers/statsrange.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#pragma once

#include "empty_range.h"

#include <atomic>

namespace snmalloc
{
/**
* Used to measure memory usage.
*/
template<typename ParentRange>
template<typename ParentRange = EmptyRange>
class StatsRange
{
ParentRange parent{};
Expand All @@ -16,6 +18,12 @@ namespace snmalloc
static inline std::atomic<size_t> peak_usage{};

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = StatsRange<ParentRange2>;

static constexpr bool Aligned = ParentRange::Aligned;

static constexpr bool ConcurrencySafe = ParentRange::ConcurrencySafe;
Expand Down
9 changes: 8 additions & 1 deletion src/snmalloc/backend_helpers/subrange.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "../mem/mem.h"
#include "empty_range.h"

namespace snmalloc
{
Expand All @@ -8,12 +9,18 @@ namespace snmalloc
* 2^RATIO_BITS. Will not return a the block at the start or
* the end of the large allocation.
*/
template<typename ParentRange, typename PAL, size_t RATIO_BITS>
template<typename PAL, size_t RATIO_BITS, typename ParentRange = EmptyRange>
class SubRange
{
ParentRange parent{};

public:
/**
* We use a nested Apply type to enable a Pipe operation.
*/
template<typename ParentRange2>
using Apply = SubRange<PAL, RATIO_BITS, ParentRange2>;

constexpr SubRange() = default;

static constexpr bool Aligned = ParentRange::Aligned;
Expand Down