examples: speed up mandelbrot.v by using a constant size thread pool, processing smaller chunks
parent
50ab2cfd1a
commit
64a686f41f
|
@ -7,6 +7,8 @@ const pwidth = 800
|
||||||
|
|
||||||
const pheight = 600
|
const pheight = 600
|
||||||
|
|
||||||
|
const chunk_height = 2 // the image is recalculated in chunks, each chunk processed in a separate thread
|
||||||
|
|
||||||
const zoom_factor = 1.1
|
const zoom_factor = 1.1
|
||||||
|
|
||||||
struct ViewRect {
|
struct ViewRect {
|
||||||
|
@ -17,22 +19,47 @@ mut:
|
||||||
y_max f64
|
y_max f64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (v &ViewRect) width() f64 {
|
||||||
|
return v.x_max - v.x_min
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (v &ViewRect) height() f64 {
|
||||||
|
return v.y_max - v.y_min
|
||||||
|
}
|
||||||
|
|
||||||
struct AppState {
|
struct AppState {
|
||||||
mut:
|
mut:
|
||||||
gg &gg.Context = 0
|
gg &gg.Context = 0
|
||||||
iidx int
|
iidx int
|
||||||
pixels []u32 = []u32{len: pwidth * pheight}
|
pixels &u32 = unsafe { vcalloc(pwidth * pheight * sizeof(u32)) }
|
||||||
npixels []u32 = []u32{len: pwidth * pheight} // all drawing happens here, results are copied at the end
|
npixels &u32 = unsafe { vcalloc(pwidth * pheight * sizeof(u32)) } // all drawing happens here, results are swapped at the end
|
||||||
view ViewRect = ViewRect{-2.7610033817025625, 1.1788897130338223, -1.824584023871934, 2.1153096311072788}
|
view ViewRect = ViewRect{-2.7610033817025625, 1.1788897130338223, -1.824584023871934, 2.1153096311072788}
|
||||||
ntasks int = runtime.nr_jobs()
|
ntasks int = runtime.nr_jobs()
|
||||||
}
|
}
|
||||||
|
|
||||||
const colors = [gx.black, gx.blue, gx.red, gx.green, gx.yellow, gx.orange, gx.purple, gx.white,
|
const colors = [gx.black, gx.blue, gx.red, gx.green, gx.yellow, gx.orange, gx.purple, gx.white,
|
||||||
gx.indigo, gx.violet, gx.black]
|
gx.indigo, gx.violet, gx.black].map(u32(it.abgr8()))
|
||||||
|
|
||||||
|
struct MandelChunk {
|
||||||
|
cview ViewRect
|
||||||
|
ymin f64
|
||||||
|
ymax f64
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut state AppState) update() {
|
fn (mut state AppState) update() {
|
||||||
mut sw := time.new_stopwatch()
|
mut chunk_channel := chan MandelChunk{cap: state.ntasks}
|
||||||
|
mut chunk_ready_channel := chan bool{cap: 1000}
|
||||||
|
mut threads := []thread{cap: state.ntasks}
|
||||||
|
defer {
|
||||||
|
chunk_channel.close()
|
||||||
|
threads.wait()
|
||||||
|
}
|
||||||
|
for t in 0 .. state.ntasks {
|
||||||
|
threads << go state.worker(t, chunk_channel, chunk_ready_channel)
|
||||||
|
}
|
||||||
|
//
|
||||||
mut oview := ViewRect{}
|
mut oview := ViewRect{}
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
for {
|
for {
|
||||||
sw.restart()
|
sw.restart()
|
||||||
cview := state.view
|
cview := state.view
|
||||||
|
@ -40,23 +67,36 @@ fn (mut state AppState) update() {
|
||||||
time.sleep(5 * time.millisecond)
|
time.sleep(5 * time.millisecond)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sheight := pheight / state.ntasks
|
// schedule chunks, describing the work:
|
||||||
mut threads := []thread{}
|
mut nchunks := 0
|
||||||
for start := 0; start < pheight; start += sheight {
|
for start := 0; start < pheight; start += chunk_height {
|
||||||
threads << go state.recalc_lines(cview, start, start + sheight)
|
chunk_channel <- MandelChunk{
|
||||||
|
cview: cview
|
||||||
|
ymin: start
|
||||||
|
ymax: start + chunk_height
|
||||||
}
|
}
|
||||||
threads.wait()
|
nchunks++
|
||||||
state.pixels = state.npixels
|
}
|
||||||
|
// wait for all chunks to be processed:
|
||||||
|
for _ in 0 .. nchunks {
|
||||||
|
_ := <-chunk_ready_channel
|
||||||
|
}
|
||||||
|
// everything is done, swap the buffer pointers
|
||||||
|
state.pixels, state.npixels = state.npixels, state.pixels
|
||||||
println('$state.ntasks threads; $sw.elapsed().milliseconds() ms / frame')
|
println('$state.ntasks threads; $sw.elapsed().milliseconds() ms / frame')
|
||||||
oview = cview
|
oview = cview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut state AppState) recalc_lines(cview ViewRect, ymin f64, ymax f64) {
|
fn (mut state AppState) worker(id int, input chan MandelChunk, ready chan bool) {
|
||||||
for y_pixel := ymin; y_pixel < ymax && y_pixel < pheight; y_pixel++ {
|
for {
|
||||||
y0 := (y_pixel / pheight) * (cview.y_max - cview.y_min) + cview.y_min
|
chunk := <-input or { break }
|
||||||
|
yscale := chunk.cview.height() / pheight
|
||||||
|
xscale := chunk.cview.width() / pwidth
|
||||||
|
for y_pixel := chunk.ymin; y_pixel < chunk.ymax && y_pixel < pheight; y_pixel++ {
|
||||||
|
y0 := y_pixel * yscale + chunk.cview.y_min
|
||||||
for x_pixel := 0.0; x_pixel < pwidth; x_pixel++ {
|
for x_pixel := 0.0; x_pixel < pwidth; x_pixel++ {
|
||||||
x0 := (x_pixel / pwidth) * (cview.x_max - cview.x_min) + cview.x_min
|
x0 := x_pixel * xscale + chunk.cview.x_min
|
||||||
mut x, mut y := x0, y0
|
mut x, mut y := x0, y0
|
||||||
mut iter := 0
|
mut iter := 0
|
||||||
for ; iter < 80; iter++ {
|
for ; iter < 80; iter++ {
|
||||||
|
@ -65,14 +105,18 @@ fn (mut state AppState) recalc_lines(cview ViewRect, ymin f64, ymax f64) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.npixels[int(y_pixel) * pwidth + int(x_pixel)] = u32(colors[iter % 8].abgr8())
|
unsafe {
|
||||||
|
state.npixels[int(y_pixel * pwidth) + int(x_pixel)] = colors[iter & 7]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ready <- true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut state AppState) draw() {
|
fn (mut state AppState) draw() {
|
||||||
mut istream_image := state.gg.get_cached_image_by_idx(state.iidx)
|
mut istream_image := state.gg.get_cached_image_by_idx(state.iidx)
|
||||||
istream_image.update_pixel_data(&state.pixels[0])
|
istream_image.update_pixel_data(state.pixels)
|
||||||
size := gg.window_size()
|
size := gg.window_size()
|
||||||
state.gg.draw_image(0, 0, size.width, size.height, istream_image)
|
state.gg.draw_image(0, 0, size.width, size.height, istream_image)
|
||||||
}
|
}
|
||||||
|
@ -110,8 +154,8 @@ fn graphics_frame(mut state AppState) {
|
||||||
fn graphics_click(x f32, y f32, btn gg.MouseButton, mut state AppState) {
|
fn graphics_click(x f32, y f32, btn gg.MouseButton, mut state AppState) {
|
||||||
if btn == .right {
|
if btn == .right {
|
||||||
size := gg.window_size()
|
size := gg.window_size()
|
||||||
m_x := (x / size.width) * (state.view.x_max - state.view.x_min) + state.view.x_min
|
m_x := (x / size.width) * state.view.width() + state.view.x_min
|
||||||
m_y := (y / size.height) * (state.view.y_max - state.view.y_min) + state.view.y_min
|
m_y := (y / size.height) * state.view.height() + state.view.y_min
|
||||||
state.center(m_x, m_y)
|
state.center(m_x, m_y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,8 +163,8 @@ fn graphics_click(x f32, y f32, btn gg.MouseButton, mut state AppState) {
|
||||||
fn graphics_move(x f32, y f32, mut state AppState) {
|
fn graphics_move(x f32, y f32, mut state AppState) {
|
||||||
if state.gg.mouse_buttons.has(.left) {
|
if state.gg.mouse_buttons.has(.left) {
|
||||||
size := gg.window_size()
|
size := gg.window_size()
|
||||||
d_x := (f64(state.gg.mouse_dx) / size.width) * (state.view.x_max - state.view.x_min)
|
d_x := (f64(state.gg.mouse_dx) / size.width) * state.view.width()
|
||||||
d_y := (f64(state.gg.mouse_dy) / size.height) * (state.view.y_max - state.view.y_min)
|
d_y := (f64(state.gg.mouse_dy) / size.height) * state.view.height()
|
||||||
state.view.x_min -= d_x
|
state.view.x_min -= d_x
|
||||||
state.view.x_max -= d_x
|
state.view.x_max -= d_x
|
||||||
state.view.y_min -= d_y
|
state.view.y_min -= d_y
|
||||||
|
@ -133,8 +177,8 @@ fn graphics_scroll(e &gg.Event, mut state AppState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn graphics_keydown(code gg.KeyCode, mod gg.Modifier, mut state AppState) {
|
fn graphics_keydown(code gg.KeyCode, mod gg.Modifier, mut state AppState) {
|
||||||
s_x := (state.view.x_max - state.view.x_min) / 5
|
s_x := state.view.width() / 5
|
||||||
s_y := (state.view.y_max - state.view.y_min) / 5
|
s_y := state.view.height() / 5
|
||||||
// movement
|
// movement
|
||||||
mut d_x, mut d_y := 0.0, 0.0
|
mut d_x, mut d_y := 0.0, 0.0
|
||||||
if code == .enter {
|
if code == .enter {
|
||||||
|
|
Loading…
Reference in New Issue