v2 / vlib / sync / bench / many_writers_and_receivers_on_1_channel.v
149 lines · 140 sloc · 3.8 KB · c51d30bf5309653c6b573ec815268e69a78ea8cc
Raw
1import os
2import os.cmdline
3import time
4import sync
5
6// Usage:
7// many_writers_and_receivers_on_1_channel [-readers 1] [-writers 4] [-chan_cap 100] [-iterations 25000] > results.csv
8//
9// You can then open results.csv in Excel/Calc and for example plot the first vs the second column.
10enum EventKind {
11 push
12 pop
13}
14
15struct Event {
16 is_set bool
17 id int
18 gtime u64 // nanoseconds
19 i int
20 kind EventKind
21 elapsed i64 // nanoseconds, elapsed after the previous event of the same kind
22}
23
24struct Context {
25mut:
26 n_iters int
27 n_readers int
28 n_writers int
29
30 pops_wg &sync.WaitGroup
31 pops []Event
32
33 pushes_wg &sync.WaitGroup
34 pushes []Event
35}
36
37fn do_rec(ch chan int, id int, mut ctx Context) {
38 eprintln('start of do_rec id: ${id}')
39 mut timer_sw_x := time.new_stopwatch()
40 mut tmp := int(0)
41 mut i := int(0)
42 // Note: a single receiver thread can get slightly more
43 // than its fair share of sends, that is why
44 // the receiver's Event array is much larger,
45 // enough so a single receiver can potentially process all
46 // writers pushes, and it is partitioned over all of
47 // id, ctx.n_writers and n_iters:
48 n_iters := ctx.n_iters
49 base := id * n_iters * ctx.n_writers
50 for {
51 for ch.try_pop(mut tmp) == .success {
52 ctx.pops[base + i] = Event{
53 is_set: true
54 id: id
55 gtime: time.sys_mono_now()
56 i: i
57 kind: .pop
58 elapsed: timer_sw_x.elapsed().nanoseconds()
59 }
60 timer_sw_x.restart()
61 i++
62 if tmp == 1 {
63 ctx.pops_wg.done()
64 return
65 }
66 }
67 }
68}
69
70fn do_send(ch chan int, id int, mut ctx Context) {
71 eprintln('start of do_send id: ${id}')
72 mut timer_sw_x := time.new_stopwatch()
73 n_iters := ctx.n_iters
74 base := n_iters * id // sender events can not overlap
75 for i := 0; i < n_iters; i++ {
76 idx := base + i
77 ctx.pushes[idx] = Event{
78 is_set: true
79 id: id
80 gtime: time.sys_mono_now()
81 i: i
82 kind: .push
83 elapsed: timer_sw_x.elapsed().nanoseconds()
84 }
85 timer_sw_x.restart()
86 tmp := int(0)
87 ch <- tmp
88 }
89 ctx.pushes_wg.done()
90}
91
92fn main() {
93 args := os.args[1..]
94 if '-h' in args || '--help' in args {
95 eprintln('Usage:\n many_writers_and_receivers_on_1_channel [-readers 1] [-writers 4] [-chan_cap 100] [-iterations 25000]')
96 exit(0)
97 }
98 n_iters := cmdline.option(args, '-iterations', '25000').int()
99 n_readers := cmdline.option(args, '-readers', '1').int()
100 n_writers := cmdline.option(args, '-writers', '4').int()
101 chan_cap := cmdline.option(args, '-chan_cap', '100').int()
102 eprintln('> n_iters, ${n_iters}, n_writers, ${n_writers}, n_readers, ${n_readers}, chan_cap, ${chan_cap}')
103
104 ch := chan int{cap: chan_cap}
105 max_number_of_pushes := n_writers * (n_iters + 2)
106 max_number_of_pops := max_number_of_pushes * n_readers
107 eprintln('> max_number_of_pushes, ${max_number_of_pushes}, max_number_of_pops (per receiver), ${max_number_of_pops}')
108 mut ctx := &Context{
109 n_iters: n_iters
110 n_readers: n_readers
111 n_writers: n_writers
112 pushes_wg: sync.new_waitgroup()
113 pops_wg: sync.new_waitgroup()
114 pushes: []Event{len: max_number_of_pushes}
115 pops: []Event{len: max_number_of_pops}
116 }
117 ctx.pops_wg.add(n_readers)
118 for i := 0; i < n_readers; i++ {
119 spawn do_rec(ch, i, mut ctx)
120 }
121 ctx.pushes_wg.add(n_writers)
122 for i := 0; i < n_writers; i++ {
123 spawn do_send(ch, i, mut ctx)
124 }
125 ctx.pushes_wg.wait()
126 eprintln('>> all pushes done')
127 for i := 0; i < n_readers; i++ {
128 ch <- 1
129 }
130 ctx.pops_wg.wait()
131 eprintln('>> all pops done')
132 mut all_events := []Event{}
133 all_events << ctx.pops
134 all_events << ctx.pushes
135 all_events.sort(a.elapsed < b.elapsed)
136 mut i := 0
137 for e in all_events {
138 if !e.is_set {
139 continue
140 }
141 i++
142 if e.kind == .pop {
143 println('${i:8} , ${e.elapsed:10}, ns , do_rec id:, ${e.id:3} , i=, ${e.i:5} , ${e.gtime:20}')
144 }
145 if e.kind == .push {
146 println('${i:8} , ${e.elapsed:10}, ns , do_send id:, ${e.id:3} , i=, ${e.i:5} , ${e.gtime:20}')
147 }
148 }
149}
150