Skip to content

Commit

Permalink
fix conditional bug in bufPool which exploded memory usage
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Aug 18, 2024
1 parent 03aad5e commit 8cd5581
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 6 deletions.
21 changes: 17 additions & 4 deletions examples/test/glsdf3test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ var OtherUnaryRandomizedOps2D3D = []func(a glbuild.Shader2D, rng *rand.Rand) glb
randomRevolve,
}

const (
_ = 1 << (iota * 10)
kB
MB
)

func test_sdf_gpu_cpu() error {
const maxBuf = 16 * 16 * 16
const nx, ny, nz = 10, 10, 10
Expand All @@ -131,7 +137,7 @@ func test_sdf_gpu_cpu() error {
scratchPos := make([]ms3.Vec, maxBuf)
scratchPos2 := make([]ms2.Vec, maxBuf)
for _, primitive := range PremadePrimitives {
log.Printf("begin evaluating %s\n", getBaseTypename(primitive))
log.Printf("begin evaluating %s", getBaseTypename(primitive))
bounds := primitive.Bounds()
pos := appendMeshgrid(scratchPos[:0], bounds, nx, ny, nz)
distCPU := scratchDistCPU[:len(pos)]
Expand Down Expand Up @@ -287,6 +293,7 @@ func test_sdf_gpu_cpu() error {
description := sprintOpPrimitive(op, primitive)
return fmt.Errorf("%d %s: %s", i, description, err)
}
// log.Printf("allocated v3=%dMB v2=%dMB f32=%dMB", vp.V3.TotalAlloc()/MB, vp.V2.TotalAlloc()/MB, vp.Float.TotalAlloc()/MB)
if getBaseTypename(primitive) == "screw" ||
(getBaseTypename(primitive) == "tri" && getFnName(op) == "randomRotation") {
log.Println("omit screw unary testbounds checks")
Expand All @@ -299,6 +306,7 @@ func test_sdf_gpu_cpu() error {
}
}
}

for _, op := range OtherUnaryRandomizedOps2D3D {
log.Printf("begin evaluating %s\n", getFnName(op))
for i := 0; i < 10; i++ {
Expand Down Expand Up @@ -326,9 +334,14 @@ func test_sdf_gpu_cpu() error {
description := sprintOpPrimitive(op, primitive)
return fmt.Errorf("%s: %s", description, err)
}
err = vp.AssertAllReleased()
if err != nil {
return err
}
}
}
log.Println("PASS CPU vs. GPU comparisons")
log.Printf("Allocated: v3:%s v2:%s f32:%s", vp.V3.String(), vp.V2.String(), vp.Float.String())
log.Printf("PASS CPU vs. GPU comparisons.")
return nil
}

Expand Down Expand Up @@ -374,7 +387,7 @@ func test_stl_generation() error {
return fmt.Errorf("triangle %d: got %+v, want %+v", i, got, want)
}
}
log.Printf("wrote+read %d triangles (rendered in %s)", len(triangles), elapsed.String())
log.Printf("wrote+read %d triangles with %d evaluations (rendered in %s)", len(triangles), sdfgpu.Evaluations(), elapsed.String())
return err
}

Expand Down Expand Up @@ -585,7 +598,7 @@ func appendMeshgrid2D(dst []ms2.Vec, bounds ms2.Box, nx, ny, nz int) []ms2.Vec {
return dst
}

func makeGPUSDF3(s glbuild.Shader3D) gleval.SDF3 {
func makeGPUSDF3(s glbuild.Shader3D) *gleval.SDF3Compute {
if s == nil {
panic("nil Shader3D")
}
Expand Down
42 changes: 40 additions & 2 deletions gleval/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,23 @@ func (vp *VecPool) AssertAllReleased() error {
return nil
}

// TotalAlloc returns the number of bytes allocated by all underlying buffers.
func (vp *VecPool) TotalAlloc() uint64 {
return vp.Float.TotalAlloc() + vp.V2.TotalAlloc() + vp.V3.TotalAlloc()
}

type bufPool[T any] struct {
_ins [][]T
_acquired []bool
// releaseErr stores error on Release call since Release is usually used in concert with defer, thus losing the error.
releaseErr error
}

// Acquire gets a buffer from the pool of the desired length and marks it as used.
// If no buffer is available then a new one is allocated.
func (bp *bufPool[T]) Acquire(length int) []T {
for i, locked := range bp._acquired {
if !locked && len(bp._ins[i]) > length {
if !locked && len(bp._ins[i]) >= length {
bp._acquired[i] = true
return bp._ins[i][:length]
}
Expand All @@ -159,6 +166,8 @@ var (
errBufpoolReleaseNonexistent = errors.New("release of nonexistent resource")
)

// Release receives a buffer that was previously returned by [bufPool.Acquire]
// and returns it to the pool and marks it as unused/free.
func (bp *bufPool[T]) Release(buf []T) error {
for i, instance := range bp._ins {
if &instance[0] == &buf[0] {
Expand Down Expand Up @@ -187,7 +196,7 @@ func (bp *bufPool[T]) assertAllReleased() error {
return nil
}

// NumBuffers returns quantity of buffers.
// NumBuffers returns quantity of buffers allocated by the pool.
func (bp *bufPool[T]) NumBuffers() int {
return len(bp._ins)
}
Expand All @@ -202,3 +211,32 @@ func (bp *bufPool[T]) TotalAlloc() uint64 {
}
return size * n
}

// Free returns total number of free buffers. To calculate number of used buffers do [bufPool.NumBuffers]() - [bufPool.Free]().
func (bp *bufPool[T]) Free() (free int) {
for _, b := range bp._acquired {
if !b {
free++
}
}
return free
}

func (bp *bufPool[T]) String() string {
alloc := bp.TotalAlloc()
const (
_ = 1 << (10 * iota)
kB
MB
)
units := "b"
switch {
case alloc > MB:
alloc /= MB
units = "MB"
case alloc > kB:
alloc /= kB
units = "kB"
}
return fmt.Sprintf("bufPool{free:%d/%d mem:%d%s}", bp.Free(), bp.NumBuffers(), alloc, units)
}

0 comments on commit 8cd5581

Please sign in to comment.