From: Egon Elbre <egonelbre@gmail.com>
By keeping all the information in a single map, we avoid multiple
lookups and can switch between frames more easily.
Before ~35us, after ~20us for adding 50 new+old and switching
the frame.
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
---
gpu/caches.go | 44 +++++++++++++++++++++++++-------------------
gpu/caches_test.go | 24 ++++++++++++++++++++++++
2 files changed, 49 insertions(+), 19 deletions(-)
create mode 100644 gpu/caches_test.go
diff --git a/gpu/caches.go b/gpu/caches.go
index 762f3e77..b44f7ead 100644
--- a/gpu/caches.go
+++ b/gpu/caches.go
@@ -9,8 +9,12 @@ import (
)
type resourceCache struct {
- res map[interface{}]resource
- newRes map[interface{}]resource
+ res map[interface{}]resourceCacheValue
+}
+
+type resourceCacheValue struct {
+ used bool
+ resource resource
}
// opCache is like a resourceCache but using concrete types and a
@@ -35,46 +39,48 @@ type opCacheValue struct {
func newResourceCache() *resourceCache {
return &resourceCache{
- res: make(map[interface{}]resource),
- newRes: make(map[interface{}]resource),
+ res: make(map[interface{}]resourceCacheValue),
}
}
func (r *resourceCache) get(key interface{}) (resource, bool) {
v, exists := r.res[key]
- if exists {
- r.newRes[key] = v
+ if !exists {
+ return nil, false
}
- return v, exists
+ if !v.used {
+ v.used = true
+ r.res[key] = v
+ }
+ return v.resource, exists
}
func (r *resourceCache) put(key interface{}, val resource) {
- if _, exists := r.newRes[key]; exists {
+ v, exists := r.res[key]
+ if exists && v.used {
panic(fmt.Errorf("key exists, %p", key))
}
- r.res[key] = val
- r.newRes[key] = val
+ v.used = true
+ v.resource = val
+ r.res[key] = v
}
func (r *resourceCache) frame() {
for k, v := range r.res {
- if _, exists := r.newRes[k]; !exists {
+ if v.used {
+ v.used = false
+ r.res[k] = v
+ } else {
delete(r.res, k)
- v.release()
+ v.resource.release()
}
}
- for k, v := range r.newRes {
- delete(r.newRes, k)
- r.res[k] = v
- }
}
func (r *resourceCache) release() {
- r.frame()
for _, v := range r.res {
- v.release()
+ v.resource.release()
}
- r.newRes = nil
r.res = nil
}
diff --git a/gpu/caches_test.go b/gpu/caches_test.go
new file mode 100644
index 00000000..411de5af
--- /dev/null
+++ b/gpu/caches_test.go
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: Unlicense OR MIT
+
+package gpu
+
+import "testing"
+
+func BenchmarkResourceCache(b *testing.B) {
+ offset := 0
+ const N = 100
+
+ cache := newResourceCache()
+ for i := 0; i < b.N; i++ {
+ // half are the same and half updated
+ for k := 0; k < N; k++ {
+ cache.put(offset+k, nullResource{})
+ }
+ cache.frame()
+ offset += N / 2
+ }
+}
+
+type nullResource struct{}
+
+func (nullResource) release() {}
--
2.34.2