Why does scavChunkData use a 1-bit flag instead of a 10-bit counter to record whether free pages exist?

101 views
Skip to first unread message

Lidong Yan

unread,
Dec 11, 2025, 1:14:54 PM (2 days ago) Dec 11
to golang-nuts
Hi everyone, I am a newcomer reading Go runtime code, and I noticed that
```go
type scavChunkData struct {
// Only the first 10 bits are used.
inUse uint16

// Only the first 10 bits are used.
lastInUse uint16

// gen is the generation counter from a scavengeIndex from the
// last time this scavChunkData was updated.
gen uint32

// Note: only 6 bits are available.
scavChunkFlags
}
```

in scavChunkData, we only use 1-bit of scavChunkFlags to indicate whether there is free pages in a chunk. This could be imprecise because we use the following code to compute whether there are free pages,
```go
nofree = inUse == pagesInChunk
```

I think we could use a 10-bit counter to record how many pages are freed. Why go use a 1-bit flag instead of a 10-bit counter? Is it for performance reasons?

Ian Lance Taylor

unread,
Dec 11, 2025, 1:23:50 PM (2 days ago) Dec 11
to Lidong Yan, golang-nuts
I don't know all the details here, but scavChunkData packs into a
64-bit value (see the pack method). That is useful because that 64-bit
value can be loaded and stored atomically. It works out that there are
only six bits available for scavChunkFlags, as the comment says. So a
10-bit counter isn't available.

Ian

Lidong Yan

unread,
Dec 11, 2025, 7:37:15 PM (2 days ago) Dec 11
to Ian Lance Taylor, golang-nuts
Ian Lance Taylor <ia...@golang.org> writes:
>
> I don't know all the details here, but scavChunkData packs into a
> 64-bit value (see the pack method). That is useful because that 64-bit
> value can be loaded and stored atomically. It works out that there are
> only six bits available for scavChunkFlags, as the comment says. So a
> 10-bit counter isn't available.
>
> Ian

Thanks very much, but I also found the layout of scanChunkData is like:
| 10-bit [inUse] + 6-bit unused | 10-bit [lastInUse] + 6-bit [scavChunkFlag] | 32 bit [gen] |
And actually we have 12-bit left besides inUse/lastInUse/gen.

```go
// pack returns sc packed into a uint64.
func (sc scavChunkData) pack() uint64 {
return uint64(sc.inUse) |
(uint64(sc.lastInUse) << 16) |
(uint64(sc.scavChunkFlags) << (16 + logScavChunkInUseMax)) |
(uint64(sc.gen) << 32)
}
```

Lidong Yan

unread,
Dec 11, 2025, 7:47:27 PM (2 days ago) Dec 11
to boubaker issa, golang-nuts
boubaker issa <mrbouba...@gmail.com> writes:
>
> but why !!
>

You mean why I am proposing to use a counter? Think about the condition that we first allocate 2 pages, then free 1 page, and finally allocate 1 page. In this case, the current chunk has no free pages in it, but the flag in scavChunkFlag is 0 so the scavenger has to step into the chunk to find out whether there are certain page to scavenge. With a free-page counter, the scavenger does not need to check this chunk anymore.

Ian Lance Taylor

unread,
Dec 11, 2025, 8:25:35 PM (2 days ago) Dec 11
to Lidong Yan, golang-nuts
Thanks, I think you're right.

I suppose I'm not sure why a counter would help very much in practice.
The scenario in which it helps doesn't seem like a common one. But you
could try it and see if it helps with any benchmarks.

Ian

Lidong Yan

unread,
Dec 11, 2025, 8:47:17 PM (2 days ago) Dec 11
to Ian Lance Taylor, golang-nuts
I agree, counter may not help very much but will not hurt much either I suppose.
Besides I think it is more precise than 1-bit flag. I will make some experiments
on benchmarks.

Regards.
Lidong

Lidong Yan

unread,
Dec 12, 2025, 2:07:18 AM (yesterday) Dec 12
to Ian Lance Taylor, golang-nuts
When we allocate some pages in a chunk, it is possible we would allocate new pages
rather than freed pages in this chunk (e.g. we want 10 contiguous pages and we only
have two freed pages). So I don’t think I can calculate a value for freed-pages counter
after an allocation. And I think that why go use an imprecise 1-bit flag here.

Lidong

Reply all
Reply to author
Forward
0 new messages