Merge pull request #10644 from djdongjin/improve-gc-tricolor

Improve gc tricolor by avoiding revisiting nodes
This commit is contained in:
Maksym Pavlenko 2024-08-27 19:48:50 +00:00 committed by GitHub
commit 0027f817e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 1 deletions

View File

@ -69,12 +69,14 @@ func Tricolor(roots []Node, refs func(ref Node) ([]Node, error)) (map[Node]struc
) )
grays = append(grays, roots...) grays = append(grays, roots...)
for _, root := range roots {
seen[root] = struct{}{} // pre-mark this as not-white
}
for len(grays) > 0 { for len(grays) > 0 {
// Pick any gray object // Pick any gray object
id := grays[len(grays)-1] // effectively "depth first" because first element id := grays[len(grays)-1] // effectively "depth first" because first element
grays = grays[:len(grays)-1] grays = grays[:len(grays)-1]
seen[id] = struct{}{} // post-mark this as not-white
rs, err := refs(id) rs, err := refs(id)
if err != nil { if err != nil {
return nil, err return nil, err
@ -84,6 +86,7 @@ func Tricolor(roots []Node, refs func(ref Node) ([]Node, error)) (map[Node]struc
for _, target := range rs { for _, target := range rs {
if _, ok := seen[target]; !ok { if _, ok := seen[target]; !ok {
grays = append(grays, target) grays = append(grays, target)
seen[target] = struct{}{}
} }
} }

View File

@ -18,6 +18,7 @@ package gc
import ( import (
"context" "context"
"fmt"
"reflect" "reflect"
"testing" "testing"
) )
@ -52,6 +53,28 @@ func TestTricolorBasic(t *testing.T) {
} }
} }
func BenchmarkTricolor(b *testing.B) {
roots := []string{"A", "C"}
refs := map[string][]string{
"A": {"B", "C"},
"B": {"A", "C"},
"C": {"D", "F", "B"},
"E": {"F", "G", "C"},
"F": {"H", "C"},
}
// assume 100 nodes can reach D.
for i := 0; i < 100; i++ {
ref := fmt.Sprintf("X%d", i)
refs["A"] = append(refs["A"], ref)
refs[ref] = []string{"D"}
}
// Run the Add function b.N times to benchmark it.
for i := 0; i < b.N; i++ {
Tricolor(toNodes(roots), lookup(refs))
}
}
func TestConcurrentBasic(t *testing.T) { func TestConcurrentBasic(t *testing.T) {
roots := []string{"A", "C"} roots := []string{"A", "C"}
all := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I"} all := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I"}