Page MenuHomeFreeBSD

uma: Use a hand-rolled bitset implementation
Needs ReviewPublic

Authored by markj on Jun 2 2025, 1:51 AM.
Tags
None
Referenced Files
Unknown Object (File)
Sep 12 2025, 4:33 PM
Unknown Object (File)
Sep 7 2025, 11:34 PM
Unknown Object (File)
Sep 7 2025, 3:36 AM
Unknown Object (File)
Sep 5 2025, 1:13 PM
Unknown Object (File)
Sep 3 2025, 5:45 PM
Unknown Object (File)
Sep 2 2025, 11:21 PM
Unknown Object (File)
Sep 1 2025, 11:16 PM
Unknown Object (File)
Aug 26 2025, 3:10 AM
Subscribers
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Summary

Using bitset.h means that each bitset word has size 8 on 64-bit
platforms, which complicates the problem of embedding a slab header in
struct vm_page. Stop using bitset.h and instead make each word an int.
This requires more code, but not a prohibitive amount.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 64619
Build 61503: arc lint + arc unit

Event Timeline

markj requested review of this revision.Jun 2 2025, 1:51 AM

Could you shrink uma_slab at still use BITSET?

  1. In slab_sizeof, replace sizeof(struct uma_slab) with __offsetof(struct uma_slab, us_free[1])
  2. In uma_core.c, define

long *slab_bits(uma_slab_t slab)
{ return ((long *)&slab->us_free[1]); }

and replace &slab-us_free with slab_bits(slab) in several places.

sys/vm/uma_core.c
161

ffsl ->ffs

162

When is bit == 0?

Could you shrink uma_slab at still use BITSET?

  1. In slab_sizeof, replace sizeof(struct uma_slab) with __offsetof(struct uma_slab, us_free[1])
  2. In uma_core.c, define

long *slab_bits(uma_slab_t slab)
{ return ((long *)&slab->us_free[1]); }

and replace &slab-us_free with slab_bits(slab) in several places.

Do you mean that slab->us_free should still have type int *? Then, is the idea that BIT_* would only access the low 32 bits of each bitset (us_free and slab_dbg_bits()), so it's okay to let them overlap from the perspective of BIT_*?

To describe the final result more concretely, when a uma_slab is embedded in the page header, the slab header layout effectively becomes:

struct uma_slab {
    LIST_ENTRY(uma_slab) us_link;
    uint16_t us_freecount;
    uint8_t us_flags;
    uint8_t us_domain;
    int us_free[3];
};

In a non-INVARIANTS kernel, this permits a set size of up to 96, and in an INVARIANTS kernel the maximum set size is 32.

Do you mean that slab->us_free should still have type int *? Then, is the idea that BIT_* would only access the low 32 bits of each bitset (us_free and slab_dbg_bits()), so it's okay to let them overlap from the perspective of BIT_*?

I mean that slab->us_free should have type int[], as it does with your proposed change, which is not a pointer, but just a name that marks the end of the struct. Because it is an int[] and not a long[], it does not add padding when it is embedded in a page struct.
The idea is that, with this change, (long *)&slab->us_free[1] has the same behavior as &slab->us_free does now - it is an offset where an array of longs begins.

Do you mean that slab->us_free should still have type int *? Then, is the idea that BIT_* would only access the low 32 bits of each bitset (us_free and slab_dbg_bits()), so it's okay to let them overlap from the perspective of BIT_*?

I mean that slab->us_free should have type int[], as it does with your proposed change, which is not a pointer, but just a name that marks the end of the struct. Because it is an int[] and not a long[], it does not add padding when it is embedded in a page struct.
The idea is that, with this change, (long *)&slab->us_free[1] has the same behavior as &slab->us_free does now - it is an offset where an array of longs begins.

Sorry, I don't quite follow--with that scheme there is indeed no padding, but the 4 bytes between us_domain and us_free[1] are still unused. The reason for using int[] is to be able to fit two bitmaps into 12 bytes. The BIT_* macros want each bitmap to be at least 8 bytes in size (on 64-bit platforms, where sizeof(long) == 8).

Fix issues in slab_bitset_ffs().