gpu: optimize resourceCache

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>
This commit is contained in:
Egon Elbre
2022-07-02 19:16:19 +03:00
committed by Elias Naur
parent f8f68a4e9f
commit 6bf5d4dc2d
2 changed files with 49 additions and 19 deletions
+25 -19
View File
@@ -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
}
+24
View File
@@ -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() {}