// Copyright (C) 2019 Yasuhiro Matsumoto . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. //go:build cgo // +build cgo package sqlite3 import ( "sync" "sync/atomic" "testing" "unsafe" ) func BenchmarkHandleLookupParallel(b *testing.B) { d := SQLiteDriver{} conn, err := d.Open(":memory:") if err != nil { b.Fatal(err) } defer conn.Close() c := conn.(*SQLiteConn) handle := newHandle(c, func() {}) benchmarkHandleLookupParallel(b, func() any { return lookupHandle(handle) }) } func BenchmarkHandleLookupBeforeAfter(b *testing.B) { value := handleVal{val: func() {}} handle := unsafe.Pointer(&value) before := mutexHandleTable{vals: map[unsafe.Pointer]handleVal{handle: value}} after := atomicHandleTable{} after.vals.Store(map[unsafe.Pointer]handleVal{handle: value}) b.Run("before_mutex", func(b *testing.B) { benchmarkHandleLookupParallel(b, func() any { return before.lookup(handle).val }) }) b.Run("after_atomic", func(b *testing.B) { benchmarkHandleLookupParallel(b, func() any { return after.lookup(handle).val }) }) } func benchmarkHandleLookupParallel(b *testing.B, lookup func() any) { b.Helper() b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { if lookup() == nil { b.Fatal("lookup returned nil") } } }) } type mutexHandleTable struct { mu sync.Mutex vals map[unsafe.Pointer]handleVal } func (t *mutexHandleTable) lookup(handle unsafe.Pointer) handleVal { t.mu.Lock() defer t.mu.Unlock() return t.vals[handle] } type atomicHandleTable struct { vals atomic.Value } func (t *atomicHandleTable) lookup(handle unsafe.Pointer) handleVal { m, _ := t.vals.Load().(map[unsafe.Pointer]handleVal) return m[handle] }