Skip to content

Commit

Permalink
[fold] Use 16 bit counts
Browse files Browse the repository at this point in the history
  • Loading branch information
seelabs committed Nov 14, 2023
1 parent e72f033 commit c752af2
Showing 1 changed file with 49 additions and 47 deletions.
96 changes: 49 additions & 47 deletions src/ripple/basics/IntrusiveRefCounts.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,102 +135,104 @@ struct IntrusiveRefCounts
*/

// TODO: We may be able to use a uint32_t for both counts for additional
// memory savings. Use type aliases to make it easy to switch types.
using count_type = std::uint32_t;
static constexpr size_t strong_count_bits = sizeof(count_type) * 8;
static constexpr size_t weak_count_bits = strong_count_bits - 2;
using field_type = std::uint64_t;
static constexpr size_t field_type_bits = sizeof(field_type) * 8;
static constexpr field_type one = 1;

mutable std::atomic<field_type> refCounts{strongDelta};
// TODO: We may need to use a uint64_t for both counts. This will reduce the
// memory savings. We need to audit the code to make sure 16 bit counts are
// enough for strong pointers and 14 bit counts are enough for weak
// pointers. Use type aliases to make it easy to switch types.
using CountType = std::uint16_t;
static constexpr size_t StrongCountNumBits = sizeof(CountType) * 8;
static constexpr size_t WeakCountNumBits = StrongCountNumBits - 2;
using FieldType = std::uint32_t;
static constexpr size_t FieldTypeBits = sizeof(FieldType) * 8;
static constexpr FieldType one = 1;

mutable std::atomic<FieldType> refCounts{strongDelta};

/** Amount to change the strong count when adding or releasing a reference
Note: The strong count is stored in the low `strong_count_bits` bits of
refCounts
Note: The strong count is stored in the low `StrongCountNumBits` bits
of refCounts
*/
static constexpr field_type strongDelta = 1;
static constexpr FieldType strongDelta = 1;

/** Amount to change the weak count when adding or releasing a reference
Note: The weak count is stored in the high `weak_count_bits` bits of
Note: The weak count is stored in the high `WeakCountNumBits` bits of
refCounts
*/
static constexpr field_type weakDelta = (one << strong_count_bits);
static constexpr FieldType weakDelta = (one << StrongCountNumBits);

/** Flag that is set when the partialDestroy function has started running
(or is about to start running).
See description of the `refCounts` field for a fuller description of
this field.
*/
static constexpr field_type partialDestroyStartedMask =
(one << (field_type_bits - 1));
static constexpr FieldType partialDestroyStartedMask =
(one << (FieldTypeBits - 1));

/** Flag that is set when the partialDestroy function has finished running
See description of the `refCounts` field for a fuller description of
this field.
*/
static constexpr field_type partialDestroyFinishedMask =
(one << (field_type_bits - 2));
static constexpr FieldType partialDestroyFinishedMask =
(one << (FieldTypeBits - 2));

/** Mask that will zero out all the `count` bits and leave the tag bits
unchanged.
*/
static constexpr field_type tagMask =
static constexpr FieldType tagMask =
partialDestroyStartedMask | partialDestroyFinishedMask;

/** Mask that will zero out the `tag` bits and leave the count bits
unchanged.
*/
static constexpr field_type valueMask = ~tagMask;
static constexpr FieldType valueMask = ~tagMask;

/** Mask that will zero out everything except the strong count.
*/
static constexpr field_type strongMask =
((one << strong_count_bits) - 1) & valueMask;
static constexpr FieldType strongMask =
((one << StrongCountNumBits) - 1) & valueMask;

/** Mask that will zero out everything except the weak count.
*/
static constexpr field_type weakMask =
(((one << weak_count_bits) - 1) << strong_count_bits) & valueMask;
static constexpr FieldType weakMask =
(((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask;

/** Unpack the count and tag fields from the packed atomic integer form. */
struct RefCountPair
{
count_type strong;
count_type weak;
CountType strong;
CountType weak;
/** The `partialDestroyStartedBit` is set to on when the partial
destroy function is started. It is not a boolean; it is a uint32
with all bits zero with the possible exception of the
`partialDestroyStartedMask` bit. This is done so it can be directly
masked into the `combinedValue`.
*/
field_type partialDestroyStartedBit{0};
FieldType partialDestroyStartedBit{0};
/** The `partialDestroyFinishedBit` is set to on when the partial
destroy function has finished.
*/
field_type partialDestroyFinishedBit{0};
RefCountPair(field_type v) noexcept;
RefCountPair(count_type s, count_type w) noexcept;
FieldType partialDestroyFinishedBit{0};
RefCountPair(FieldType v) noexcept;
RefCountPair(CountType s, CountType w) noexcept;

/** Convert back to the packed integer form. */
field_type
FieldType
combinedValue() const noexcept;

static constexpr count_type maxStrongValue =
static_cast<count_type>((one << strong_count_bits) - 1);
static constexpr count_type maxWeakValue =
static_cast<count_type>((one << weak_count_bits) - 1);
static constexpr CountType maxStrongValue =
static_cast<CountType>((one << StrongCountNumBits) - 1);
static constexpr CountType maxWeakValue =
static_cast<CountType>((one << WeakCountNumBits) - 1);
/** Put an extra margin to detect when running up against limits.
This is only used in debug code, and is useful if we reduce the
number of bits in the strong and weak counts (to 16 and 14 bits).
*/
static constexpr count_type checkStrongMaxValue = maxStrongValue - 32;
static constexpr count_type checkWeakMaxValue = maxWeakValue - 32;
static constexpr CountType checkStrongMaxValue = maxStrongValue - 32;
static constexpr CountType checkWeakMaxValue = maxWeakValue - 32;
};
};

Expand Down Expand Up @@ -387,30 +389,30 @@ inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
//------------------------------------------------------------------------------

inline IntrusiveRefCounts::RefCountPair::RefCountPair(
IntrusiveRefCounts::field_type v) noexcept
: strong{static_cast<count_type>(v & strongMask)}
, weak{static_cast<count_type>((v & weakMask) >> strong_count_bits)}
IntrusiveRefCounts::FieldType v) noexcept
: strong{static_cast<CountType>(v & strongMask)}
, weak{static_cast<CountType>((v & weakMask) >> StrongCountNumBits)}
, partialDestroyStartedBit{v & partialDestroyStartedMask}
, partialDestroyFinishedBit{v & partialDestroyFinishedMask}
{
assert(strong < checkStrongMaxValue && weak < checkWeakMaxValue);
}

inline IntrusiveRefCounts::RefCountPair::RefCountPair(
IntrusiveRefCounts::count_type s,
IntrusiveRefCounts::count_type w) noexcept
IntrusiveRefCounts::CountType s,
IntrusiveRefCounts::CountType w) noexcept
: strong{s}, weak{w}
{
assert(strong < checkStrongMaxValue && weak < checkWeakMaxValue);
}

inline IntrusiveRefCounts::field_type
inline IntrusiveRefCounts::FieldType
IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
{
assert(strong < checkStrongMaxValue && weak < checkWeakMaxValue);
return (static_cast<IntrusiveRefCounts::field_type>(weak)
<< IntrusiveRefCounts::strong_count_bits) |
static_cast<IntrusiveRefCounts::field_type>(strong) |
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
<< IntrusiveRefCounts::StrongCountNumBits) |
static_cast<IntrusiveRefCounts::FieldType>(strong) |
partialDestroyStartedBit | partialDestroyFinishedBit;
}

Expand Down

0 comments on commit c752af2

Please sign in to comment.