Skip to content

Commit

Permalink
add benchmark for OverlapDetector
Browse files Browse the repository at this point in the history
  • Loading branch information
Strorkis committed Jan 9, 2025
1 parent ef48b24 commit bef8f08
Show file tree
Hide file tree
Showing 2 changed files with 268 additions and 2 deletions.
4 changes: 2 additions & 2 deletions detector/check_spatial_id_overlap.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,13 @@ func NewSpatialIdTreeOverlapDetector(spatialIds []string) (SpatialIdOverlapDetec
positiveTree = tree.CreateTree(tree.Create3DTable())
}
treeIndex := tree.Indexs{int64(f), int64(x), int64(y)}
positiveTree.Append(treeIndex, tree.ZoomSetLevel(zoom), spatialId)
positiveTree.Append(treeIndex, tree.ZoomSetLevel(zoom), struct{}{})
} else {
if negativeTree == nil {
negativeTree = tree.CreateTree(tree.Create3DTable())
}
treeIndex := tree.Indexs{int64(^f), int64(x), int64(y)}
negativeTree.Append(treeIndex, tree.ZoomSetLevel(zoom), spatialId)
negativeTree.Append(treeIndex, tree.ZoomSetLevel(zoom), struct{}{})
}
}
return &SpatialIdTreeOverlapDetector{positiveTree, negativeTree}, nil
Expand Down
266 changes: 266 additions & 0 deletions detector/check_spatial_id_overlap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package detector

import (
"errors"
"fmt"
"reflect"
"runtime"
"testing"

sperrors "github.com/trajectoryjp/spatial_id_go/v4/common/errors"
Expand Down Expand Up @@ -610,6 +612,261 @@ func TestSpatialIdOverlapDetector(t *testing.T) {
}
}

// OverlapDetectorBenchmarkCase OverlapDetectorのベンチマークケース
type OverlapDetectorBenchmarkCase struct {
name string
detectIdNumberCbrt int
detectedIdNumberCbrt int
detectZoomLevel int
detectedZoomLevel int
unmatchDepth int
}

// newOverlapDetectorBenchmarkCase ベンチマークケース名nameを受け取り、OverlapDetectorBenchmarkCaseを返す
func newOverlapDetectorBenchmarkCase(name string) OverlapDetectorBenchmarkCase {
return OverlapDetectorBenchmarkCase{
name: name,
detectIdNumberCbrt: 1,
detectedIdNumberCbrt: 10,
detectZoomLevel: 23,
detectedZoomLevel: 23,
unmatchDepth: 18,
}
}

// createDetectSpatialIds ベンチマークケースから検知空間IDを生成する
func (benchmarkCase *OverlapDetectorBenchmarkCase) createDetectSpatialIds() []string {
zoomLevelDiff := max(0, benchmarkCase.detectZoomLevel-benchmarkCase.detectedZoomLevel)
unmatchHeight := benchmarkCase.detectZoomLevel - benchmarkCase.unmatchDepth

detectSpatialIds := []string{}
for f := range benchmarkCase.detectIdNumberCbrt {
for x := range benchmarkCase.detectIdNumberCbrt {
for y := range benchmarkCase.detectIdNumberCbrt {
detectSpatialId := fmt.Sprintf(
"%d/%d/%d/%d",
benchmarkCase.detectZoomLevel,
(1<<unmatchHeight)|(f<<zoomLevelDiff),
(1<<unmatchHeight)|(x<<zoomLevelDiff),
(1<<unmatchHeight)|(y<<zoomLevelDiff),
)
detectSpatialIds = append(detectSpatialIds, detectSpatialId)
}
}
}
return detectSpatialIds
}

// createDetectedSpatialIds ベンチマークケースから被検知空間IDを生成する
func (benchmarkCase *OverlapDetectorBenchmarkCase) createDetectedSpatialIds() []string {
detectedSpatialIds := []string{}
for f := range benchmarkCase.detectedIdNumberCbrt {
for x := range benchmarkCase.detectedIdNumberCbrt {
for y := range benchmarkCase.detectedIdNumberCbrt {
detectedSpatialId := fmt.Sprintf(
"%d/%d/%d/%d",
benchmarkCase.detectedZoomLevel,
f,
x,
y,
)
detectedSpatialIds = append(detectedSpatialIds, detectedSpatialId)
}
}
}
return detectedSpatialIds
}

// BenchmarkOverlapDetectorProcessingTime OverlapDetectorの処理時間に対するベンチマークを行う
func BenchmarkOverlapDetectorProcessingTime(b *testing.B) {
benchmarkCases := []OverlapDetectorBenchmarkCase{}
for _, detectIdNumberCbrt := range []int{1, 10} {
for detectedIdNumberCbrt := 6; detectedIdNumberCbrt <= 10; detectedIdNumberCbrt += 1 {
name := fmt.Sprintf("Pattern=1,DetectIdNumberCbrt=%d,DetectedIdNumberCbrt=%d", detectIdNumberCbrt, detectedIdNumberCbrt)
benchmarkCase := newOverlapDetectorBenchmarkCase(name)
benchmarkCase.detectIdNumberCbrt = detectIdNumberCbrt
benchmarkCase.detectedIdNumberCbrt = detectedIdNumberCbrt
benchmarkCases = append(benchmarkCases, benchmarkCase)
}
for detectedZoomLevel := 10; detectedZoomLevel <= 35; detectedZoomLevel += 5 {
name := fmt.Sprintf("Pattern=2,DetectIdNumberCbrt=%d,DetectedZoomLevel=%d", detectIdNumberCbrt, detectedZoomLevel)
benchmarkCase := newOverlapDetectorBenchmarkCase(name)
benchmarkCase.detectIdNumberCbrt = detectIdNumberCbrt
benchmarkCase.detectedZoomLevel = detectedZoomLevel
benchmarkCase.unmatchDepth = 5
benchmarkCases = append(benchmarkCases, benchmarkCase)
}
for unmatchDepth := 5; unmatchDepth <= 30; unmatchDepth += 5 {
name := fmt.Sprintf("Pattern=3,DetectIdNumberCbrt=%d,UnmatchDepth=%d", detectIdNumberCbrt, unmatchDepth)
benchmarkCase := newOverlapDetectorBenchmarkCase(name)
benchmarkCase.detectIdNumberCbrt = detectIdNumberCbrt
benchmarkCase.detectedZoomLevel = 35
benchmarkCase.detectZoomLevel = 35
benchmarkCase.unmatchDepth = unmatchDepth
benchmarkCases = append(benchmarkCases, benchmarkCase)
}
}

for _, benchmarkCase := range benchmarkCases {
detectSpatialIds := benchmarkCase.createDetectSpatialIds()
detectedSpatialIds := benchmarkCase.createDetectedSpatialIds()

// ベンチマーク内ではエラーが無視されるため、エラーが出ていないかの確認
greedyDetector, err := NewSpatialIdGreedyOverlapDetector(detectedSpatialIds)
if err != nil {
b.Error(err)
return
}
if _, err := greedyDetector.IsOverlap(detectSpatialIds); err != nil {
b.Error(err)
return
}
treeDetector, err := NewSpatialIdTreeOverlapDetector(detectedSpatialIds)
if err != nil {
b.Error(err)
return
}
if _, err := treeDetector.IsOverlap(detectSpatialIds); err != nil {
b.Error(err)
return
}

logic_slice := []string{"greedy", "tree"}
step_slice := []string{"construct", "search"}
for _, logic := range logic_slice {
for _, step := range step_slice {
name := fmt.Sprintf("Logic=%s,Step=%s,%s", logic, step, benchmarkCase.name)

var f func(b *testing.B)
switch logic {
case "greedy":
switch step {
case "construct":
f = func(b *testing.B) {
for range b.N {
NewSpatialIdGreedyOverlapDetector(detectedSpatialIds)
}
}
case "search":
f = func(b *testing.B) {
for range b.N {
greedyDetector.IsOverlap(detectSpatialIds)
}
}
}
case "tree":
switch step {
case "construct":
f = func(b *testing.B) {
for range b.N {
NewSpatialIdTreeOverlapDetector(detectedSpatialIds)
}
}
case "search":
f = func(b *testing.B) {
for range b.N {
treeDetector.IsOverlap(detectSpatialIds)
}
}
}
}

b.Run(name, f)
}
}
}
}

// BenchmarkOverlapDetectorMemoryUsage OverlapDetectorのメモリ使用量に対するベンチマークを行う
func BenchmarkOverlapDetectorMemoryUsage(b *testing.B) {
benchmarkCases := []OverlapDetectorBenchmarkCase{}
for _, detectIdNumberCbrt := range []int{1, 10} {
for detectedIdNumberCbrt := 6; detectedIdNumberCbrt <= 10; detectedIdNumberCbrt += 1 {
name := fmt.Sprintf("Pattern=1,DetectIdNumberCbrt=%d,DetectedIdNumberCbrt=%d", detectIdNumberCbrt, detectedIdNumberCbrt)
benchmarkCase := newOverlapDetectorBenchmarkCase(name)
benchmarkCase.detectIdNumberCbrt = detectIdNumberCbrt
benchmarkCase.detectedIdNumberCbrt = detectedIdNumberCbrt
benchmarkCases = append(benchmarkCases, benchmarkCase)
}
for detectedZoomLevel := 5; detectedZoomLevel <= 35; detectedZoomLevel += 5 {
name := fmt.Sprintf("Pattern=2,DetectIdNumberCbrt=%d,DetectedZoomLevel=%d", detectIdNumberCbrt, detectedZoomLevel)
benchmarkCase := newOverlapDetectorBenchmarkCase(name)
benchmarkCase.detectIdNumberCbrt = detectIdNumberCbrt
benchmarkCase.detectedZoomLevel = detectedZoomLevel
benchmarkCase.unmatchDepth = 5
benchmarkCases = append(benchmarkCases, benchmarkCase)
}
}

var detector SpatialIdOverlapDetector // コンパイラに最適化されないように
for _, benchmarkCase := range benchmarkCases {
detectedSpatialIds := benchmarkCase.createDetectedSpatialIds()

// ベンチマーク内ではエラーが無視されるため、エラーが出ていないかの確認
var err error
_, err = NewSpatialIdGreedyOverlapDetector(detectedSpatialIds)
if err != nil {
b.Error(err)
return
}
_, err = NewSpatialIdTreeOverlapDetector(detectedSpatialIds)
if err != nil {
b.Error(err)
return
}

logic_slice := []string{"greedy", "tree"}
step := "construct"
for _, logic := range logic_slice {
name := fmt.Sprintf("Logic=%s,Step=%s,%s", logic, step, benchmarkCase.name)

memAllocSum := uint64(0)
var f func(b *testing.B)
switch logic {
case "greedy":
for range 100 {
startAllocatedMemory := getAllocatedMemory()
detector, _ = NewSpatialIdGreedyOverlapDetector(detectedSpatialIds)
goalAllocatedMemory := getAllocatedMemory()
if goalAllocatedMemory < startAllocatedMemory {
b.Error("goalAllocatedMemory < startAllocatedMemory")
return
}
memAllocSum += goalAllocatedMemory - startAllocatedMemory
}

f = func(b *testing.B) {
for range b.N {
NewSpatialIdGreedyOverlapDetector(detectedSpatialIds)
}
}
case "tree":
for range 100 {
startAllocatedMemory := getAllocatedMemory()
detector, _ = NewSpatialIdTreeOverlapDetector(detectedSpatialIds)
goalAllocatedMemory := getAllocatedMemory()
memAllocSum += goalAllocatedMemory - startAllocatedMemory
if goalAllocatedMemory < startAllocatedMemory {
b.Error("goalAllocatedMemory < startAllocatedMemory")
return
}
}

f = func(b *testing.B) {
for range b.N {
NewSpatialIdTreeOverlapDetector(detectedSpatialIds)
}
}
}

fmt.Printf("BenchmarkOverlapDetectorMemoryUsage/%s,AllocatedMemoryMean=%d\n", name, memAllocSum/100)

b.Run(name, f)
}
}
fmt.Println(detector)
}

// TestCheckExtendedSpatialIdsOverlap01 拡張空間IDの重複確認関数 正常系動作確認
//
// 試験詳細:
Expand Down Expand Up @@ -897,3 +1154,12 @@ func BenchmarkCheckExtendedSpatialIdsArrayOverlap01(b *testing.B) {
b.StopTimer()
b.Log("テスト終了")
}

// getAllocatedMemory GC後の現在のメモリ使用量を取得する
func getAllocatedMemory() uint64 {
runtime.GC()

var mem runtime.MemStats
runtime.ReadMemStats(&mem)
return mem.Alloc
}

0 comments on commit bef8f08

Please sign in to comment.