live.odin (2757B)
1 package main 2 3 import "core:fmt" 4 import "core:sync" 5 import "core:thread" 6 import "core:time" 7 8 import "scan" 9 10 /* 11 Stand in for a UI. 12 13 Three jobs, as the scan is meant to run: a reader filling the tree, a builder owning 14 everything derived from it, and this loop drawing. The point of the arrangement is 15 that a frame costs the same whatever the volume holds, because it reads a published 16 snapshot of twenty rows rather than the tree. 17 18 Which reader fills it is not decided here, and nothing here knows which one did. A 19 reader settles nodes, and restates if it has to correct itself; that is the whole of 20 the conversation. 21 22 Nothing here waits on the builder. If a build pass is mid-write the loop draws the 23 answer from the last one. 24 */ 25 FRAME :: 16 * time.Millisecond 26 27 run_live :: proc(f: ^Fill) -> int { 28 out: Publisher 29 started := time.tick_now() 30 31 f.watched = true 32 sync.atomic_store(&f.scanning, true) 33 34 b := Builder { 35 tree = f.tree, 36 out = &out, 37 scanning = &f.scanning, 38 started = started, 39 } 40 41 filler := thread.create_and_start_with_poly_data(f, fill_thread) 42 if filler == nil { 43 fmt.eprintln("error: could not start the reader") 44 return 1 45 } 46 defer thread.destroy(filler) 47 48 builder := thread.create_and_start_with_poly_data(&b, build_thread) 49 if builder == nil { 50 fmt.eprintln("error: could not start the builder") 51 return 1 52 } 53 defer thread.destroy(builder) 54 defer rollup_destroy(&b.roll) 55 56 frames, drawn, missed := 0, 0, 0 57 last: Snapshot 58 have := false 59 60 for { 61 frame_start := time.tick_now() 62 finished := bool(sync.atomic_load(&b.done)) 63 64 if s, ok := current(&out); ok { 65 last = s 66 have = true 67 drawn += 1 68 } else { 69 missed += 1 70 } 71 72 if have && last.count > 0 { 73 fmt.printfln( 74 "frame %3d %6.0f ms %8d nodes %6d pending %10s %s frame %5.2f ms%s", 75 frames, 76 last.elapsed, 77 last.nodes, 78 last.pending, 79 human(last.rows[0].bytes), 80 scan.path(f.tree, last.rows[0].node, context.temp_allocator), 81 time.duration_milliseconds(time.tick_since(frame_start)), 82 last.complete ? " (final)" : "", 83 ) 84 free_all(context.temp_allocator) 85 } 86 frames += 1 87 88 if finished { 89 break 90 } 91 92 if spent := time.tick_since(frame_start); spent < FRAME { 93 time.sleep(FRAME - spent) 94 } 95 } 96 97 thread.join(filler) 98 thread.join(builder) 99 100 if fill_report(f) { 101 return 1 102 } 103 104 fmt.println() 105 fmt.printfln( 106 "scan finished in %.0f ms over %d frames, %d drawn, %d skipped mid-write", 107 time.duration_milliseconds(time.tick_since(started)), 108 frames, 109 drawn, 110 missed, 111 ) 112 113 print_largest(f.tree, b.roll.totals[:], .files) 114 print_largest(f.tree, b.roll.totals[:], .directories) 115 116 return 0 117 } 118 119 @(private) 120 fill_thread :: proc(f: ^Fill) { 121 fill_run(f) 122 } 123 124 @(private) 125 build_thread :: proc(b: ^Builder) { 126 builder_run(b) 127 }