From 7fd42f61d5cd0b7f6c9e011686496c1523467825 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Mon, 11 Dec 2023 12:15:26 -0800 Subject: [PATCH] Reuse analysis result buffers --- analysis.go | 4 +-- board.go | 73 ++++++++++++++++++++++++++++------------------ board_test.go | 11 +++---- cmd/tabula/main.go | 3 +- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/analysis.go b/analysis.go index 9a1ce88..9b225d2 100644 --- a/analysis.go +++ b/analysis.go @@ -6,7 +6,7 @@ import ( "sync" ) -const queueBufferSize = 4096000 +var QueueBufferSize = 4096000 var ( WeightBlot = 1.05 @@ -39,7 +39,7 @@ var rollProbabilities = [21][3]int{ {6, 6, 1}, } -var analysisQueue = make(chan *Analysis, queueBufferSize) +var analysisQueue = make(chan *Analysis, QueueBufferSize) func init() { cpus := runtime.NumCPU() diff --git a/board.go b/board.go index 06d284a..892601e 100644 --- a/board.go +++ b/board.go @@ -7,9 +7,9 @@ import ( "sync" ) -const ( - analysisBufferSize = 128 - subAnalysisBufferSize = 1024 +var ( + AnalysisBufferSize = 128 + SubAnalysisBufferSize = 1024 ) const ( @@ -445,34 +445,51 @@ func (b Board) Evaluation(player int, hitScore int, moves [][]int) *Analysis { return a } -func (b Board) Analyze(available [][][]int) []*Analysis { +func (b Board) Analyze(available [][][]int, result *[]*Analysis) { if len(available) == 0 { - return nil + *result = (*result)[:0] + return } - result := make([]*Analysis, 0, analysisBufferSize) + var reuse []*[]*Analysis + for _, r := range *result { + if r.result != nil { + reuse = append(reuse, r.result) + } + } + *result = (*result)[:0] + reuseLen := len(reuse) + var reuseIndex int + w := &sync.WaitGroup{} past := b.Past() w.Add(len(available)) for _, moves := range available { - r := make([]*Analysis, 0, subAnalysisBufferSize) + var r *[]*Analysis + if reuseIndex < reuseLen { + r = reuse[reuseIndex] + reuseIndex++ + } else { + v := make([]*Analysis, 0, SubAnalysisBufferSize) + r = &v + } a := &Analysis{ Board: b, Moves: moves, Past: past, player: 1, chance: 1, - result: &r, + result: r, resultMutex: &sync.Mutex{}, wg: w, } - result = append(result, a) + *result = append(*result, a) analysisQueue <- a } w.Wait() - for _, a := range result { + for _, a := range *result { if a.player == 1 && !a.Past { var oppPips float64 var oppBlots float64 @@ -504,36 +521,34 @@ func (b Board) Analyze(available [][][]int) []*Analysis { } } - sort.Slice(result, func(i, j int) bool { - return result[i].Score < result[j].Score + sort.Slice(*result, func(i, j int) bool { + return (*result)[i].Score < (*result)[j].Score }) - return result } -func (b Board) ChooseDoubles() (int, [][]*Analysis) { - if !b.Acey() { - return 0, nil - } - var allAnalysis = make([][]*Analysis, 6) - for i := 0; i < 6; i++ { - doubles := int8(i + 1) - bc := b - bc[SpaceRoll1], bc[SpaceRoll2], bc[SpaceRoll3], bc[SpaceRoll4] = doubles, doubles, doubles, doubles - available, _ := bc.Available(1) - allAnalysis[i] = bc.Analyze(available) +func (b Board) ChooseDoubles(result *[]*Analysis) int { + if !b.Acey() { + return 0 } bestDoubles := 6 bestScore := math.MaxFloat64 + + var available [][][]int for i := 0; i < 6; i++ { - if len(allAnalysis[i]) == 0 { - continue - } else if allAnalysis[i][0].Score < bestScore { + doubles := int8(i + 1) + bc := b + bc[SpaceRoll1], bc[SpaceRoll2], bc[SpaceRoll3], bc[SpaceRoll4] = doubles, doubles, doubles, doubles + + available, _ = bc.Available(1) + bc.Analyze(available, result) + if len(*result) > 0 && (*result)[0].Score < bestScore { bestDoubles = i + 1 - bestScore = allAnalysis[i][0].Score + bestScore = (*result)[0].Score } } - return bestDoubles, allAnalysis + + return bestDoubles } func (b Board) Print() { diff --git a/board_test.go b/board_test.go index 62272a5..4c1a5f0 100644 --- a/board_test.go +++ b/board_test.go @@ -103,9 +103,10 @@ func TestAnalyze(t *testing.T) { b[SpaceRoll1], b[SpaceRoll2] = 1, 2 available, _ := b.Available(1) - r := b.Analyze(available) + analysis := make([]*Analysis, 0, AnalysisBufferSize) + b.Analyze(available, &analysis) var blots int - for _, r := range r { + for _, r := range analysis { blots += r.Blots } if blots <= 0 { @@ -137,7 +138,7 @@ func TestAnalyze(t *testing.T) { board[SpaceRoll4] = c.roll4 available, _ := board.Available(1) - _ = board.Analyze(available) + board.Analyze(available, &analysis) }) } } @@ -203,11 +204,11 @@ func BenchmarkAnalyze(b *testing.B) { board[SpaceRoll3] = c.roll3 board[SpaceRoll4] = c.roll4 available, _ := board.Available(1) + analysis := make([]*Analysis, 0, AnalysisBufferSize) - var analysis []*Analysis b.ResetTimer() for i := 0; i < b.N; i++ { - analysis = board.Analyze(available) + board.Analyze(available, &analysis) } _ = analysis diff --git a/cmd/tabula/main.go b/cmd/tabula/main.go index 644a6fb..8bc2712 100644 --- a/cmd/tabula/main.go +++ b/cmd/tabula/main.go @@ -33,7 +33,8 @@ func main() { t := time.Now() available, _ := b.Available(1) t2 := time.Now() - analysis := b.Analyze(available) + analysis := make([]*tabula.Analysis, 0, tabula.AnalysisBufferSize) + b.Analyze(available, &analysis) t3 := time.Now() log.Println("AVAILABLE TOOK ", t2.Sub(t))