v2 / vlib / v / util / timers.v
201 lines · 177 sloc · 3.96 KB · fd504030dfc5085f4509d3d078f6150c38a4aea9
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4@[has_globals]
5module util
6
7import time
8
9__global g_timers = new_timers(should_print: false, label: 'g_timers')
10
11@[heap]
12pub struct Timers {
13 label string
14pub mut:
15 swatches shared map[string]time.StopWatch
16 should_print bool
17 // already_shown records for which of the swatches .show() or .show_if_exists() had been called already
18 already_shown []string
19}
20
21@[params]
22pub struct TimerParams {
23pub:
24 should_print bool
25 label string
26}
27
28pub fn new_timers(params TimerParams) &Timers {
29 $if trace_timers_creation ? {
30 eprintln('>>>> new_timers, should_print: ${params.should_print} | label: ${params.label}')
31 }
32 return &Timers{
33 label: params.label
34 swatches: map[string]time.StopWatch{}
35 should_print: params.should_print
36 already_shown: []string{cap: 100}
37 }
38}
39
40pub fn get_timers() &Timers {
41 return g_timers
42}
43
44pub fn timing_start(label string) {
45 if !g_timers.should_print {
46 return
47 }
48 mut t := get_timers()
49 t.start(label)
50}
51
52pub fn timing_measure(label string) {
53 if !g_timers.should_print {
54 return
55 }
56 g_timers.show(label)
57}
58
59pub fn timing_measure_cumulative(label string) {
60 if !g_timers.should_print {
61 return
62 }
63 g_timers.measure_cumulative(label)
64}
65
66pub fn timing_set_should_print(should_print bool) {
67 g_timers.should_print = should_print
68}
69
70pub fn (mut t Timers) start(name string) {
71 if !t.should_print {
72 return
73 }
74 mut sw := t.tsafe_get_sw(name) or { time.new_stopwatch() }
75 sw.start()
76 t.tsafe_set_sw(name, sw)
77}
78
79pub fn (mut t Timers) measure(name string) i64 {
80 if !t.should_print {
81 return 0
82 }
83 mut sw := t.tsafe_get_sw(name) or {
84 timer_keys := t.tsafe_get_keys()
85 eprintln('> Timer `${name}` was NOT started.')
86 eprintln('> Available timers:')
87 eprintln('> ${timer_keys}')
88 time.new_stopwatch()
89 }
90 ms := sw.elapsed().microseconds()
91 sw.pause()
92 t.tsafe_set_sw(name, sw)
93 return ms
94}
95
96pub fn (mut t Timers) measure_cumulative(name string) i64 {
97 if !t.should_print {
98 return 0
99 }
100 ms := t.measure(name)
101 mut sw := t.tsafe_get_sw(name) or { return ms }
102 sw.pause()
103 t.tsafe_set_sw(name, sw)
104 return ms
105}
106
107pub fn (mut t Timers) measure_pause(name string) {
108 if !t.should_print {
109 return
110 }
111 mut sw := t.tsafe_get_sw(name) or { return }
112 sw.pause()
113 t.tsafe_set_sw(name, sw)
114}
115
116pub fn (mut t Timers) measure_resume(name string) {
117 if !t.should_print {
118 return
119 }
120 mut sw := t.tsafe_get_sw(name) or { return }
121 sw.start()
122 t.tsafe_set_sw(name, sw)
123}
124
125pub fn (mut t Timers) message(name string) string {
126 ms := f64(t.measure(name)) / 1000.0
127 value := bold('${ms:-8.3f}')
128 formatted_message := '${value} ms ${name}'
129 return formatted_message
130}
131
132pub fn (mut t Timers) show(label string) {
133 if v_memory_panic {
134 // Showing timers uses string interpolation, and allocating in this case
135 // will just cause a second panic to be shown; it is better to just not show anything
136 return
137 }
138 if t.should_print {
139 formatted_message := t.message(label)
140 println(formatted_message)
141 }
142 t.already_shown << label
143}
144
145pub fn (mut t Timers) show_if_exists(label string) {
146 if !t.should_print {
147 return
148 }
149 t.tsafe_get_sw(label) or { return }
150 t.show(label)
151 t.already_shown << label
152}
153
154pub fn (mut t Timers) show_remaining() {
155 if !t.should_print {
156 return
157 }
158 keys := t.tsafe_get_keys()
159 for k in keys {
160 if k in t.already_shown {
161 continue
162 }
163 t.show(k)
164 }
165}
166
167pub fn (mut t Timers) dump_all() {
168 if !t.should_print {
169 return
170 }
171 keys := t.tsafe_get_keys()
172 for k in keys {
173 elapsed := t.message(k)
174 println(elapsed)
175 }
176}
177
178//
179
180fn (mut t Timers) tsafe_get_keys() []string {
181 keys := rlock t.swatches {
182 t.swatches.keys()
183 }
184 return keys
185}
186
187fn (mut t Timers) tsafe_set_sw(name string, sw time.StopWatch) {
188 lock t.swatches {
189 t.swatches[name] = sw
190 }
191}
192
193fn (mut t Timers) tsafe_get_sw(name string) ?time.StopWatch {
194 rlock t.swatches {
195 if name !in t.swatches {
196 return none
197 }
198 return t.swatches[name]
199 }
200 return none
201}
202