Skip to content

Commit

Permalink
lru: swap linked-list and map fields
Browse files Browse the repository at this point in the history
The Garbage-Collector enqueues objects to scan to a work-queue in-order.
Place the map before the LRU-stack linked-list so it has an extra
head-start on scanning the much more efficient-to-scan datastructure
(the map).

The GC's mark-phase's traversal of the linked-list is a bit expensive
because it'll have to jump one link at a time, enqueuing the next and/or
previous pointers.  By traversing the map first, a pseudo-random
assortment of entry-points are used, rather than just the first and
last.

If large-ish (where we actually care) the map will be broken up into a
number of pieces for scanning, so the first chunk will be scanned;
enqueuing those linked-list elements before the head and tail get
scanned.

This swap will only have a modest effect because the map is already
scanned, but hopefully we can reduce the recursion-depth by one.

(We'll have to switch to something more CLOCK-ish without a linked-list
to be GC-friendly; this change is just making the LRU modestly less
GC-hostile)
  • Loading branch information
dfinkel committed Jul 29, 2022
1 parent 83c6207 commit 2574e46
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 2 deletions.
5 changes: 4 additions & 1 deletion lru/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ type Cache struct {
// executed when an entry is purged from the cache.
OnEvicted func(key Key, value interface{})

ll *list.List
// cache comes first so the GC enqueues marking the map-contents first
// (which will mark the contents of the linked-list much more
// efficiently than traversing the linked-list directly)
cache map[interface{}]*list.Element
ll *list.List
}

// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
Expand Down
5 changes: 4 additions & 1 deletion lru/typed_lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ type TypedCache[K comparable, V any] struct {
// executed when an typedEntry is purged from the cache.
OnEvicted func(key K, value V)

ll linkedList[typedEntry[K, V]]
// cache comes first so the GC enqueues marking the map-contents first
// (which will mark the contents of the linked-list much more
// efficiently than traversing the linked-list directly)
cache map[K]*llElem[typedEntry[K, V]]
ll linkedList[typedEntry[K, V]]
}

type typedEntry[K comparable, V any] struct {
Expand Down

0 comments on commit 2574e46

Please sign in to comment.