Skip to content
This repository has been archived by the owner on Aug 12, 2024. It is now read-only.

Commit

Permalink
finish adding a slow multithreaded octree implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed May 15, 2022
1 parent 615e52e commit 6deeb5d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 14 deletions.
38 changes: 31 additions & 7 deletions render/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"bytes"
"errors"
"io"
"os"
"runtime"
"testing"

"github.com/soypat/sdf/form3/must3"
Expand Down Expand Up @@ -76,20 +76,44 @@ func TestSTLWriteReadback(t *testing.T) {
}

func TestOctreeMultithread(t *testing.T) {
oct := NewOctreeRenderer(must3.Sphere(1), 8)
oct := NewOctreeRenderer(must3.Sphere(20), 100)
oct.concurrent = 2
buf := make([]Triangle3, oct.concurrent*10)
buf := make([]Triangle3, oct.concurrent*100)
var err error
var nt int
var model []Triangle3
for err == nil {
nt, err = oct.ReadTriangles(buf)
model = append(model, buf[nt:]...)
model = append(model, buf[:nt]...)
}
if err != io.EOF {
t.Fatal(err)
}
fp, _ := os.Create("mt.stl")
defer fp.Close()
WriteSTL(fp, model)
if len(model) != oct.triangles {
t.Errorf("triangles lost. got %d. octree read %d", len(model), oct.triangles)
}
if oct.cubes != oct.cubesP {
t.Errorf("number of non empty cubes found %d must match number of cubes processed %d", oct.cubes, oct.cubesP)
}
t.Log(oct.triangles)

}

func BenchmarkBoltThreaded(b *testing.B) {
const output = "threaded_bolt.stl"
npt := thread.NPT{}
npt.SetFromNominal(1.0 / 2.0)
object, _ := thread.Bolt(thread.BoltParms{
Thread: npt, // M16x2
Style: thread.NutHex,
Tolerance: 0.1,
TotalLength: 20,
ShankLength: 10,
})

for i := 0; i < b.N; i++ {
oct := NewOctreeRenderer(object, 300)
oct.concurrent = runtime.NumCPU()
CreateSTL(output, oct)
}
}
29 changes: 23 additions & 6 deletions render/octree_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ type octree struct {
unwritten triangle3Buffer
// concurrent goroutine processing.
concurrent int
// Number of triangles generated.
triangles int
// number of non empty cubes found.
cubes int
// number of cubes processed.
cubesP int
}

type cube struct {
Expand Down Expand Up @@ -56,8 +62,8 @@ func NewOctreeRenderer(s sdf.SDF3, meshCells int) *octree {
return &octree{
dc: *newDc3(s, bb.Min, resolution, levels),
unwritten: triangle3Buffer{buf: make([]Triangle3, 0, 1024)},
todo: cubes, //[]cube{{sdf.V3i{0, 0, 0}, levels - 1}}, // process the octree, start at the top level
// concurrent: 2,
todo: cubes,
cubes: 1,
}
}

Expand All @@ -79,7 +85,7 @@ func (oc *octree) ReadTriangles(dst []Triangle3) (n int, err error) {
}
// Number of additional triangles proccessed.
var nt int
if oc.concurrent <= 1 || len(oc.todo) < oc.concurrent || n < oc.concurrent {
if oc.concurrent < 1 || len(oc.todo) < oc.concurrent || len(dst) < oc.concurrent {
tproc, nc, newCubes := oc.readTriangles(dst[n:], oc.todo)
oc.todo = append(oc.todo, newCubes...)
oc.todo = oc.todo[nc:] // this leaks, luckily this is a short lived function?
Expand Down Expand Up @@ -124,6 +130,7 @@ func (oc *octree) readTriangles(dst []Triangle3, todo []cube) (n, cubesProcessed
}

// readTrianglesThreaded is a multithreaded triangle reader implementation for octree.
// It writes nt triangles into dst.
func (oc *octree) readTrianglesThreaded(dst []Triangle3) (nt int) {
var wg sync.WaitGroup
div := len(dst) / oc.concurrent
Expand All @@ -136,8 +143,13 @@ func (oc *octree) readTrianglesThreaded(dst []Triangle3) (nt int) {
wg.Add(1)
go func() {
start := div * i
work[i] = dst[start : start+div]
cubeWork[i] = oc.todo[i*divC : (i+1)*divC]
if i == oc.concurrent-1 {
work[i] = dst[start:]
cubeWork[i] = oc.todo[i*divC:]
} else {
work[i] = dst[start : start+div]
cubeWork[i] = oc.todo[i*divC : (i+1)*divC]
}
ntc, nc, newC := oc.readTriangles(work[i], cubeWork[i])
newCubesC[i] = newC
work[i] = work[i][:ntc]
Expand All @@ -153,8 +165,8 @@ func (oc *octree) readTrianglesThreaded(dst []Triangle3) (nt int) {
// Triangles written.
start := div*i - offset
if i != oc.concurrent-1 && len(work[i]) != div {
offset += div - len(work[i])
copy(dst[start+len(work[i]):], dst[start+div:])
offset += div - len(work[i])
}
nt += len(work[i])
// Cubes unprocessed.
Expand Down Expand Up @@ -207,6 +219,11 @@ func (oc *octree) processCube(dst []Triangle3, c cube) (writtenTriangles int, ne
}
}
}
oc.mu.Lock()
oc.triangles += writtenTriangles
oc.cubes += len(newCubes)
oc.cubesP++
oc.mu.Unlock()
return writtenTriangles, newCubes
}

Expand Down
2 changes: 1 addition & 1 deletion render/stl.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (h stlHeader) put(b []byte) {
binary.LittleEndian.PutUint32(b[80:], h.Count)
}

const trianglesInBuffer = 1 << 10
const trianglesInBuffer = 1 << 14

type stlReader struct {
r Renderer
Expand Down

0 comments on commit 6deeb5d

Please sign in to comment.