| 1 | /* |
| 2 | This program can be used to test waiting for a semaphore |
| 3 | in the presence of signals that might interrupt the `wait()` call. |
| 4 | |
| 5 | In particular the effect of Boehm-GC can be investigated. |
| 6 | |
| 7 | To do so compile this program with `v -gc boehm semaphore_wait.v` |
| 8 | and run is as `./semaphore_wait > /dev/null` to test `sem.wait()` |
| 9 | or `./semaphore_wait -t > /dev/null` to test `sem.timedwait()` |
| 10 | on Windows: `.\semaphore_wait > NUL` or `.\semaphore_wait -t > NUL` |
| 11 | |
| 12 | On success (no interrupted `wait`) the output (from stderr) should like like: |
| 13 | |
| 14 | time: 524.228 result: `true` |
| 15 | time: 521.122 result: `true` |
| 16 | time: 523.714 result: `true` |
| 17 | time: 527.001 result: `true` |
| 18 | time: 521.696 result: `true` |
| 19 | ... |
| 20 | Finished |
| 21 | |
| 22 | (The "result" is only printed with `-t`.) |
| 23 | */ |
| 24 | import os |
| 25 | import time |
| 26 | import rand |
| 27 | import math |
| 28 | import sync |
| 29 | |
| 30 | struct DataObj { |
| 31 | mut: |
| 32 | data []f64 |
| 33 | } |
| 34 | |
| 35 | struct PtrObj { |
| 36 | mut: |
| 37 | nxt []&DataObj |
| 38 | } |
| 39 | |
| 40 | struct PtrPtrObj { |
| 41 | mut: |
| 42 | nxt []&PtrObj |
| 43 | } |
| 44 | |
| 45 | const log2n = 9 |
| 46 | const n = 1 << log2n |
| 47 | const n4 = f64(u64(1) << (4 * log2n)) |
| 48 | |
| 49 | fn waste_mem() ! { |
| 50 | mut objs := PtrPtrObj{ |
| 51 | nxt: unsafe { []&PtrObj{len: n} } |
| 52 | } |
| 53 | for { |
| 54 | sz := rand.int_in_range(10, 1000)! |
| 55 | mut new_obj := &PtrObj{ |
| 56 | nxt: unsafe { []&DataObj{len: sz} } |
| 57 | } |
| 58 | sz2 := rand.int_in_range(10, 500000)! |
| 59 | new_obj2 := &DataObj{ |
| 60 | data: []f64{len: sz2} |
| 61 | } |
| 62 | idx2 := rand.int_in_range(0, sz)! |
| 63 | new_obj.nxt[idx2] = new_obj2 |
| 64 | // non-equally distributed random index |
| 65 | idx := int(math.sqrt(math.sqrt(rand.f64n(n4)!))) |
| 66 | objs.nxt[idx] = new_obj |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | fn do_rec(mut sem sync.Semaphore, timed bool) { |
| 71 | mut start := time.sys_mono_now() |
| 72 | for { |
| 73 | r := if timed { |
| 74 | sem.timed_wait(600 * time.millisecond) |
| 75 | } else { |
| 76 | sem.wait() |
| 77 | false |
| 78 | } |
| 79 | end := time.sys_mono_now() |
| 80 | dur := f64(end - start) / f64(time.millisecond) |
| 81 | res_str := if timed { ' result: `${r}`' } else { '' } |
| 82 | if dur < 450.0 || dur > 550.0 { |
| 83 | eprintln('Problem: time: ${dur:.3f}${res_str}') |
| 84 | } else { |
| 85 | eprintln('time: ${dur:.3f}${res_str}') |
| 86 | } |
| 87 | start = end |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | fn do_send(mut sem sync.Semaphore) { |
| 92 | for { |
| 93 | time.sleep(500 * time.millisecond) |
| 94 | sem.post() |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | fn usage() { |
| 99 | eprintln('usage:\n\t${os.args[0]} [-t] [num_iterations]') |
| 100 | exit(1) |
| 101 | } |
| 102 | |
| 103 | fn main() { |
| 104 | mut n_iterations := 5_000_000 |
| 105 | mut timed := false |
| 106 | if os.args.len > 3 { |
| 107 | usage() |
| 108 | } |
| 109 | for i in 1 .. os.args.len { |
| 110 | if os.args[i][0].is_digit() { |
| 111 | if i > 1 && !timed { |
| 112 | usage() |
| 113 | } |
| 114 | n_iterations = os.args[1].int() |
| 115 | } else if os.args[i] == '-t' { |
| 116 | timed = true |
| 117 | } else { |
| 118 | usage() |
| 119 | } |
| 120 | } |
| 121 | if os.args.len > 3 || n_iterations <= 0 { |
| 122 | eprintln('usage:\n\t${os.args[0]} [num_iterations]') |
| 123 | exit(1) |
| 124 | } |
| 125 | mut sem := sync.new_semaphore() |
| 126 | spawn do_rec(mut sem, timed) |
| 127 | spawn do_send(mut sem) |
| 128 | for _ in 0 .. 4 { |
| 129 | spawn waste_mem() |
| 130 | } |
| 131 | mut last := time.sys_mono_now() |
| 132 | for _ in 0 .. n_iterations { |
| 133 | now := time.sys_mono_now() |
| 134 | interval := now - last |
| 135 | println(f64(interval) / f64(time.millisecond)) |
| 136 | last = now |
| 137 | } |
| 138 | sem.destroy() |
| 139 | eprintln('Finished') |
| 140 | } |
| 141 | |