-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathattr_cache_benchmark_test.go
More file actions
154 lines (131 loc) · 3.58 KB
/
attr_cache_benchmark_test.go
File metadata and controls
154 lines (131 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package twig
import (
"fmt"
"reflect"
"testing"
)
// Struct for testing attribute cache
type testType struct {
Field1 string
Field2 int
Field3 bool
}
func (t *testType) Method1() string {
return t.Field1
}
func (t testType) Method2() int {
return t.Field2
}
// Create many distinct types to stress the attribute cache
type dynamicType struct {
name string
fields map[string]interface{}
}
// Custom interface to showcase reflection
type displayable interface {
Display() string
}
func (d dynamicType) Display() string {
return fmt.Sprintf("Type: %s", d.name)
}
// Benchmark the attribute cache with a small number of types
func BenchmarkAttributeCache_FewTypes(b *testing.B) {
// Reset the attribute cache
attributeCache.Lock()
attributeCache.m = make(map[attributeCacheKey]attributeCacheEntry)
attributeCache.currSize = 0
attributeCache.Unlock()
// Create a render context
ctx := NewRenderContext(nil, nil, nil)
defer ctx.Release()
obj := &testType{
Field1: "test",
Field2: 123,
Field3: true,
}
// Run the benchmark
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Access different fields and methods
_, _ = ctx.getAttribute(obj, "Field1")
_, _ = ctx.getAttribute(obj, "Field2")
_, _ = ctx.getAttribute(obj, "Field3")
_, _ = ctx.getAttribute(obj, "Method1")
_, _ = ctx.getAttribute(obj, "Method2")
}
}
// Benchmark the attribute cache with many different types
func BenchmarkAttributeCache_ManyTypes(b *testing.B) {
// Reset the attribute cache
attributeCache.Lock()
attributeCache.m = make(map[attributeCacheKey]attributeCacheEntry)
attributeCache.currSize = 0
attributeCache.Unlock()
// Create a render context
ctx := NewRenderContext(nil, nil, nil)
defer ctx.Release()
// Create 2000 different types (more than the cache limit)
types := make([]interface{}, 2000)
for i := 0; i < 2000; i++ {
types[i] = dynamicType{
name: fmt.Sprintf("Type%d", i),
fields: map[string]interface{}{
"field1": fmt.Sprintf("value%d", i),
"field2": i,
},
}
}
// Run the benchmark
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Access attributes across different types
typeIdx := i % 2000
_, _ = ctx.getAttribute(types[typeIdx], "name")
_, _ = ctx.getAttribute(types[typeIdx], "fields")
}
}
// Verify that the attribute cache properly performs LRU eviction
func TestAttributeCacheLRUEviction(t *testing.T) {
// Reset the attribute cache
attributeCache.Lock()
attributeCache.m = make(map[attributeCacheKey]attributeCacheEntry)
attributeCache.currSize = 0
attributeCache.maxSize = 10 // Small size for testing
attributeCache.Unlock()
// Create a render context
ctx := NewRenderContext(nil, nil, nil)
defer ctx.Release()
// Create 20 different types (more than the cache size)
types := make([]interface{}, 20)
for i := 0; i < 20; i++ {
types[i] = dynamicType{
name: fmt.Sprintf("Type%d", i),
fields: map[string]interface{}{
"field1": fmt.Sprintf("value%d", i),
},
}
}
// First access all types once
for i := 0; i < 20; i++ {
_, _ = ctx.getAttribute(types[i], "name")
}
// Now access the last 5 types more frequently
for i := 0; i < 100; i++ {
typeIdx := 15 + (i % 5) // Types 15-19
_, _ = ctx.getAttribute(types[typeIdx], "name")
}
// Check which types are in the cache
attributeCache.RLock()
defer attributeCache.RUnlock()
// The most recently/frequently used types should be in the cache
for i := 15; i < 20; i++ {
typeKey := attributeCacheKey{
typ: reflect.TypeOf(types[i]),
attr: "name",
}
_, found := attributeCache.m[typeKey]
if !found {
t.Errorf("Expected type %d to be in cache, but it wasn't", i)
}
}
}