v2 / vlib / x / async / benchmarks / async_benchmark.v
173 lines · 157 sloc · 4.3 KB · 15fb60b77ea6073658aa8355b247f2e1ae03b714
Raw
1import benchmark
2import context
3import os
4import time
5import x.async as xasync
6
7const default_group_rounds = 8
8const default_group_jobs = 16
9const default_task_rounds = 32
10const default_pool_jobs = 64
11const default_pool_workers = 4
12const default_timeout_rounds = 32
13const default_every_iterations = 5
14const default_every_interval_ms = 1
15
16fn main() {
17 run_benchmarks() or {
18 eprintln('x.async benchmark failed: ${err.msg()}')
19 exit(1)
20 }
21}
22
23fn run_benchmarks() ! {
24 group_rounds := env_int('XASYNC_BENCH_GROUP_ROUNDS', default_group_rounds, 1, 200)
25 group_jobs := env_int('XASYNC_BENCH_GROUP_JOBS', default_group_jobs, 1, 512)
26 task_rounds := env_int('XASYNC_BENCH_TASK_ROUNDS', default_task_rounds, 1, 500)
27 pool_jobs := env_int('XASYNC_BENCH_POOL_JOBS', default_pool_jobs, 1, 1000)
28 pool_workers := env_int('XASYNC_BENCH_POOL_WORKERS', default_pool_workers, 1, 64)
29 timeout_rounds := env_int('XASYNC_BENCH_TIMEOUT_ROUNDS', default_timeout_rounds, 1, 500)
30 every_iterations := env_int('XASYNC_BENCH_EVERY_ITERATIONS', default_every_iterations, 1, 100)
31 every_interval_ms :=
32 env_int('XASYNC_BENCH_EVERY_INTERVAL_MS', default_every_interval_ms, 1, 100)
33
34 println('x.async cautious benchmark')
35 println('Override sizes with XASYNC_BENCH_* environment variables.')
36
37 mut checksum := 0
38 mut b := benchmark.start()
39 checksum += bench_group(group_rounds, group_jobs)!
40 b.measure('Group: rounds=${group_rounds}, jobs_per_round=${group_jobs}, checksum=${checksum}')
41
42 checksum += bench_task(task_rounds)!
43 b.measure('Task: rounds=${task_rounds}, checksum=${checksum}')
44
45 checksum += bench_pool(pool_jobs, pool_workers)!
46 b.measure('Pool: jobs=${pool_jobs}, workers=${pool_workers}, checksum=${checksum}')
47
48 checksum += bench_timeout(timeout_rounds)!
49 b.measure('with_timeout: rounds=${timeout_rounds}, checksum=${checksum}')
50
51 checksum += bench_every(every_iterations, every_interval_ms)!
52 b.measure('every: iterations=${every_iterations}, interval_ms=${every_interval_ms}, checksum=${checksum}')
53}
54
55fn env_int(name string, default_value int, min_value int, max_value int) int {
56 raw := os.getenv(name)
57 if raw == '' {
58 return default_value
59 }
60 mut value := raw.int()
61 if value < min_value {
62 value = min_value
63 }
64 if value > max_value {
65 value = max_value
66 }
67 return value
68}
69
70fn bench_group(rounds int, jobs_per_round int) !int {
71 mut total := 0
72 for _ in 0 .. rounds {
73 done := chan int{cap: jobs_per_round}
74 mut group := xasync.new_group(context.background())
75 for _ in 0 .. jobs_per_round {
76 group.go(fn [done] (mut ctx context.Context) ! {
77 _ = ctx
78 done <- 1
79 })!
80 }
81 group.wait()!
82 for _ in 0 .. jobs_per_round {
83 total += <-done
84 }
85 }
86 return total
87}
88
89fn bench_task(rounds int) !int {
90 mut total := 0
91 for i in 0 .. rounds {
92 mut task := xasync.run[int](fn [i] (mut ctx context.Context) !int {
93 _ = ctx
94 return i + 1
95 })!
96 total += task.wait()!
97 }
98 return total
99}
100
101fn bench_pool(jobs int, workers int) !int {
102 done := chan int{cap: jobs}
103 mut pool := xasync.new_pool(workers: workers, queue_size: jobs)!
104 for _ in 0 .. jobs {
105 pool.try_submit(fn [done] (mut ctx context.Context) ! {
106 _ = ctx
107 done <- 1
108 })!
109 }
110 pool.close()!
111 mut total := 0
112 for _ in 0 .. jobs {
113 total += <-done
114 }
115 return total
116}
117
118fn bench_timeout(rounds int) !int {
119 mut total := 0
120 for _ in 0 .. rounds {
121 xasync.with_timeout(1 * time.second, fn (mut ctx context.Context) ! {
122 _ = ctx
123 })!
124 total++
125 }
126 return total
127}
128
129fn bench_every(iterations int, interval_ms int) !int {
130 ctx, cancel := xasync.with_cancel()
131 ticks := chan int{cap: iterations + 4}
132 result := chan string{cap: 1}
133 interval := time.Duration(interval_ms) * time.millisecond
134 worker := spawn fn [ctx, ticks, result, interval] () {
135 xasync.every(ctx, interval, fn [ticks] (mut ctx context.Context) ! {
136 _ = ctx
137 ticks <- 1
138 }) or {
139 result <- err.msg()
140 return
141 }
142 result <- 'ok'
143 }()
144
145 mut total := 0
146 for _ in 0 .. iterations {
147 select {
148 value := <-ticks {
149 total += value
150 }
151 1 * time.second {
152 cancel()
153 worker.wait()
154 return error('every benchmark did not receive a tick')
155 }
156 }
157 }
158 cancel()
159 select {
160 msg := <-result {
161 if msg != 'context canceled' {
162 worker.wait()
163 return error('unexpected every benchmark result: ${msg}')
164 }
165 }
166 1 * time.second {
167 worker.wait()
168 return error('every benchmark did not stop after cancellation')
169 }
170 }
171 worker.wait()
172 return total
173}
174