time_up 0.0.3 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.standard.yml +1 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +1 -1
- data/README.md +68 -36
- data/lib/time_up.rb +85 -4
- data/lib/time_up/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c18c0412768d6e182c94ef02f66e630508f5c959f433d1d1ecf322ce16107c3a
|
4
|
+
data.tar.gz: c18ce6ae92e02cd52ddad357d8f542185869d8e6fa5cebf090ee3bc4b576a44c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a73b80a2193a5df7ce3bae010b109c3e5c34de5329ca34c75cc6d7b296aae395c81ed1488a64e932069c7da8a496ea175d81f6ae4defe214445760c98a01551
|
7
|
+
data.tar.gz: 610cc5554be65e278b2187c56e0d2ebc382b5c916a2e666c39ba84da9ede77bc618ff3c4d58d2df22030bf9a8ad049cbd3eb45827bd0a7c7419e46d8166035f4
|
data/.standard.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby_version: 2.4
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# 0.0.6
|
2
|
+
|
3
|
+
- Add `TimeUp.all_timers`. It's weird that it's not a thing.
|
4
|
+
|
5
|
+
# 0.0.5
|
6
|
+
|
7
|
+
- Add `median` and `percentile` timer statistics, and added them to
|
8
|
+
`print_detailed_summary`
|
9
|
+
|
10
|
+
# 0.0.4
|
11
|
+
|
12
|
+
- Add `TimeUp.print_detailed_summary`
|
13
|
+
|
1
14
|
# 0.0.3
|
2
15
|
|
3
16
|
- Change the return value of TimeUp.start when passed a block to be the
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -11,6 +11,9 @@ process and that you want to measure in aggregate. (For example, to see how
|
|
11
11
|
much time your test suite spends creating factories, truncating the database, or
|
12
12
|
invoking a critical code path.)
|
13
13
|
|
14
|
+
Here's a [blog post about time_up](https://blog.testdouble.com/posts/2021-07-19-benchmarking-your-ruby-with-time_up/) and
|
15
|
+
a [great example of when it can be useful](https://gist.github.com/searls/feee0b0eac7c329b390fed90c4714afb).
|
16
|
+
|
14
17
|
## Install
|
15
18
|
|
16
19
|
Just run `gem install time_up` or add time_up to your Gemfile:
|
@@ -107,7 +110,7 @@ TimeUp.print_summary
|
|
107
110
|
Which will output something like:
|
108
111
|
|
109
112
|
```
|
110
|
-
TimeUp
|
113
|
+
TimeUp summary
|
111
114
|
========================
|
112
115
|
:roast 0.07267s
|
113
116
|
:veggies 0.03760s
|
@@ -117,10 +120,27 @@ TimeUp timers summary
|
|
117
120
|
* Denotes that the timer is still active
|
118
121
|
```
|
119
122
|
|
123
|
+
And if you're calling the timers multiple times and want to see some basic
|
124
|
+
statistics in the print-out, you can call `TimeUp.print_detailed_summary`, which
|
125
|
+
will produce this:
|
126
|
+
|
127
|
+
```
|
128
|
+
=============================================================================
|
129
|
+
Name | Elapsed | Count | Min | Max | Mean | Median | 95th %
|
130
|
+
-----------------------------------------------------------------------------
|
131
|
+
:roast | 0.08454 | 3 | 0.00128 | 0.07280 | 0.02818 | 0.01046 | 0.06657
|
132
|
+
:veggies | 0.03779 | 1 | 0.03779 | 0.03779 | 0.03779 | 0.03779 | 0.03779
|
133
|
+
:pasta | 0.01260 | 11 | 0.00000 | 0.01258 | 0.00115 | 0.00000 | 0.00630
|
134
|
+
:souffle* | 0.00024 | 1 | 0.00024 | 0.00025 | 0.00025 | 0.00025 | 0.00026
|
135
|
+
|
136
|
+
* Denotes that the timer is still active
|
137
|
+
```
|
138
|
+
|
120
139
|
## API
|
121
140
|
|
122
141
|
This gem defines a bunch of public methods but they're all pretty short and
|
123
|
-
straightforward, so I'd encourage you to [read the
|
142
|
+
straightforward, so when in doubt, I'd encourage you to [read the
|
143
|
+
code](/lib/time_up.rb).
|
124
144
|
|
125
145
|
### `TimeUp` module
|
126
146
|
|
@@ -128,51 +148,60 @@ straightforward, so I'd encourage you to [read the code](/lib/time_up.rb).
|
|
128
148
|
if it doesn't exist)
|
129
149
|
|
130
150
|
`TimeUp.start(name, [&blk])` - Starts (or restarts) a named
|
131
|
-
[Timer](#timeuptimer-class). If passed
|
132
|
-
|
151
|
+
[Timer](#timeuptimer-class). If passed a block, will return whatever the block
|
152
|
+
evaluates to. If called without a block, it will return the timer object
|
133
153
|
|
134
|
-
`TimeUp.stop(name)` - Stops the named timer
|
154
|
+
`TimeUp.stop(name)` - Stops the named timer
|
135
155
|
|
136
156
|
`TimeUp.reset(name)` - Resets the named timer's elapsed time to 0, effectively
|
137
|
-
restarting it if it's currently running
|
157
|
+
restarting it if it's currently running
|
138
158
|
|
139
159
|
`TimeUp.elapsed(name)` - Returns a `Float` of the total elapsed seconds that the
|
140
|
-
named timer has been running
|
141
|
-
`name`)
|
160
|
+
named timer has been running
|
142
161
|
|
143
162
|
`TimeUp.timings(name)` - Returns an array of each recorded start-to-stop
|
144
|
-
duration
|
163
|
+
duration (including the current one, if the timer is running) of the named timer
|
164
|
+
|
165
|
+
`TimeUp.count(name)` - The number of times the timer has been started (including
|
166
|
+
the current timing, if the timer is running)
|
167
|
+
|
168
|
+
`TimeUp.min(name)` - The shortest recording by the timer
|
145
169
|
|
146
|
-
`TimeUp.
|
147
|
-
stopped (including the current timing, if active)
|
170
|
+
`TimeUp.max(name)` - The longest recording by the timer
|
148
171
|
|
149
|
-
`TimeUp.
|
150
|
-
one, if active)
|
172
|
+
`TimeUp.mean(name)` - The arithmetic mean of all recordings by the timer
|
151
173
|
|
152
|
-
`TimeUp.
|
153
|
-
one, if active)
|
174
|
+
`TimeUp.median(name)` - The median of all recordings by the timer
|
154
175
|
|
155
|
-
`TimeUp.
|
176
|
+
`TimeUp.percentile(name, percent)` - The timing for the given
|
177
|
+
[percentile](https://en.wikipedia.org/wiki/Percentile) of all recordings by the
|
178
|
+
timer
|
156
179
|
|
157
|
-
`TimeUp.total_elapsed` - Returns a `Float` of the sum of `elapsed`
|
158
|
-
timers you've created
|
180
|
+
`TimeUp.total_elapsed` - Returns a `Float` of the sum of `elapsed` across all
|
181
|
+
the timers you've created (note that because you can easily run multiple logical
|
182
|
+
timers simultaneously, this figure may exceed the total time spent by the
|
183
|
+
computer)
|
159
184
|
|
160
|
-
`TimeUp.all_elapsed` - Returns a
|
161
|
-
`elapsed` values. Handy for grabbing a snapshot of the state of
|
162
|
-
|
185
|
+
`TimeUp.all_elapsed` - Returns a Hash of timer name keys mapped to their
|
186
|
+
`elapsed` values. Handy for grabbing a reference to a snapshot of the state of
|
187
|
+
things without requiring you to stop your timers
|
163
188
|
|
164
|
-
`TimeUp.all_stats` - Returns a
|
165
|
-
hash of their basic statistics (elapsed
|
166
|
-
and mean)
|
189
|
+
`TimeUp.all_stats` - Returns a Hash of timer name keys mapped to another
|
190
|
+
hash of their basic statistics (`elapsed`, `count`, `min`, `max`,
|
191
|
+
and `mean`)
|
167
192
|
|
168
|
-
`TimeUp.active_timers` - Returns an
|
169
|
-
running. Useful for detecting cases where you might be
|
170
|
-
|
193
|
+
`TimeUp.active_timers` - Returns an Array of all timers that are currently
|
194
|
+
running. Useful for detecting cases where you might be keeping time in multiple
|
195
|
+
places simultaneously
|
171
196
|
|
172
197
|
`TimeUp.print_summary([io])` - Pretty-prints a multi-line summary of all your
|
173
|
-
timers to standard output (or the provided
|
198
|
+
timers' total elapsed times to standard output (or the provided
|
174
199
|
[IO](https://ruby-doc.org/core-3.0.1/IO.html))
|
175
200
|
|
201
|
+
`TimeUp.print_detailed_summary([io])` - Pretty-prints a multi-line summary of
|
202
|
+
all your timers' elapsed times and basic statistics to standard output (or the
|
203
|
+
provided [IO](https://ruby-doc.org/core-3.0.1/IO.html))
|
204
|
+
|
176
205
|
`TimeUp.stop_all` - Stops all timers
|
177
206
|
|
178
207
|
`TimeUp.reset_all` - Resets all timers
|
@@ -188,20 +217,23 @@ reference to them
|
|
188
217
|
|
189
218
|
`elapsed` - A `Float` of the total elapsed seconds the timer has been running
|
190
219
|
|
191
|
-
`timings` - Returns an
|
192
|
-
timer (including the current one, if
|
220
|
+
`timings` - Returns an Array of each recorded start-to-stop duration of the
|
221
|
+
timer (including the current one, if the timer is running)
|
193
222
|
|
194
|
-
`count` - The number of times the timer has been started and stopped
|
195
|
-
the current timing, if active)
|
223
|
+
`count` - The number of times the timer has been started and stopped
|
196
224
|
|
197
|
-
`min` - The shortest recording of the timer
|
198
|
-
active)
|
225
|
+
`min` - The shortest recording of the timer
|
199
226
|
|
200
|
-
`max` - The longest recording of the timer
|
201
|
-
active)
|
227
|
+
`max` - The longest recording of the timer
|
202
228
|
|
203
229
|
`mean` - The arithmetic mean of all recorded durations of the timer
|
204
230
|
|
231
|
+
`median(name)` - The median of all recordings by the timer
|
232
|
+
|
233
|
+
`percentile(name, percent)` - The timing for the given
|
234
|
+
[percentile](https://en.wikipedia.org/wiki/Percentile) of all recordings by the
|
235
|
+
timer
|
236
|
+
|
205
237
|
`active?` - Returns `true` if the timer is running
|
206
238
|
|
207
239
|
`reset(force: false)` - Resets the timer to 0 elapsed seconds. If `force` is
|
data/lib/time_up.rb
CHANGED
@@ -22,7 +22,8 @@ module TimeUp
|
|
22
22
|
:count,
|
23
23
|
:min,
|
24
24
|
:max,
|
25
|
-
:mean
|
25
|
+
:mean,
|
26
|
+
:median
|
26
27
|
].each do |method_name|
|
27
28
|
define_singleton_method method_name do |name|
|
28
29
|
__ensure_timer(name)
|
@@ -30,6 +31,11 @@ module TimeUp
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
34
|
+
def self.percentile(name, percentage)
|
35
|
+
__ensure_timer(name)
|
36
|
+
__timers[name].percentile(percentage)
|
37
|
+
end
|
38
|
+
|
33
39
|
# Interrogative methods
|
34
40
|
def self.total_elapsed
|
35
41
|
__timers.values.sum(&:elapsed)
|
@@ -41,6 +47,10 @@ module TimeUp
|
|
41
47
|
}.to_h
|
42
48
|
end
|
43
49
|
|
50
|
+
def self.all_timers
|
51
|
+
__timers.values
|
52
|
+
end
|
53
|
+
|
44
54
|
def self.all_stats
|
45
55
|
__timers.values.map { |timer|
|
46
56
|
[timer.name, {
|
@@ -48,7 +58,9 @@ module TimeUp
|
|
48
58
|
count: timer.count,
|
49
59
|
min: timer.min,
|
50
60
|
max: timer.max,
|
51
|
-
mean: timer.mean
|
61
|
+
mean: timer.mean,
|
62
|
+
median: timer.median,
|
63
|
+
"95th": timer.percentile(95)
|
52
64
|
}]
|
53
65
|
}.to_h
|
54
66
|
end
|
@@ -65,7 +77,7 @@ module TimeUp
|
|
65
77
|
}
|
66
78
|
io.puts <<~SUMMARY
|
67
79
|
|
68
|
-
TimeUp
|
80
|
+
TimeUp summary
|
69
81
|
========================
|
70
82
|
#{summaries.join("\n")}
|
71
83
|
|
@@ -73,6 +85,56 @@ module TimeUp
|
|
73
85
|
SUMMARY
|
74
86
|
end
|
75
87
|
|
88
|
+
def self.print_detailed_summary(io = $stdout)
|
89
|
+
cols = {
|
90
|
+
names: ["Name"],
|
91
|
+
elapsed: ["Elapsed"],
|
92
|
+
count: ["Count"],
|
93
|
+
min: ["Min"],
|
94
|
+
max: ["Max"],
|
95
|
+
mean: ["Mean"],
|
96
|
+
median: ["Median"],
|
97
|
+
"95th": ["95th %"]
|
98
|
+
}
|
99
|
+
__timers.values.each { |timer|
|
100
|
+
cols[:names] << "#{timer.name.inspect}#{"*" if timer.active?}"
|
101
|
+
cols[:elapsed] << "%.5f" % timer.elapsed
|
102
|
+
cols[:count] << timer.count.to_s
|
103
|
+
cols[:min] << "%.5f" % timer.min
|
104
|
+
cols[:max] << "%.5f" % timer.max
|
105
|
+
cols[:mean] << "%.5f" % timer.mean
|
106
|
+
cols[:median] << "%.5f" % timer.median
|
107
|
+
cols[:"95th"] << "%.5f" % timer.percentile(95)
|
108
|
+
}
|
109
|
+
|
110
|
+
widths = cols.map { |name, vals|
|
111
|
+
[name, vals.map(&:length).max]
|
112
|
+
}.to_h
|
113
|
+
|
114
|
+
rows = cols[:names].size.times.map { |i|
|
115
|
+
if i == 0
|
116
|
+
cols.keys.map { |name|
|
117
|
+
cols[name][i].center(widths[name])
|
118
|
+
}
|
119
|
+
else
|
120
|
+
cols.keys.map { |name|
|
121
|
+
cols[name][i].ljust(widths[name])
|
122
|
+
}
|
123
|
+
end
|
124
|
+
}
|
125
|
+
|
126
|
+
full_width = widths.values.sum + (rows[0].size - 1) * 3
|
127
|
+
io.puts <<~SUMMARY
|
128
|
+
|
129
|
+
#{"=" * full_width}
|
130
|
+
#{rows[0].join(" | ")}
|
131
|
+
#{"-" * full_width}
|
132
|
+
#{rows[1..-1].map { |row| row.join(" | ") }.join("\n")}
|
133
|
+
|
134
|
+
#{"* Denotes that the timer is still active\n" if __timers.values.any?(&:active?)}
|
135
|
+
SUMMARY
|
136
|
+
end
|
137
|
+
|
76
138
|
# Iterative methods
|
77
139
|
def self.stop_all
|
78
140
|
__timers.values.each(&:stop)
|
@@ -89,7 +151,7 @@ module TimeUp
|
|
89
151
|
|
90
152
|
# Internal methods
|
91
153
|
def self.__timers
|
92
|
-
Thread.current[:time_up_timers]
|
154
|
+
Thread.current[:time_up_timers] ||= {}
|
93
155
|
end
|
94
156
|
|
95
157
|
def self.__ensure_timer(name)
|
@@ -165,6 +227,25 @@ module TimeUp
|
|
165
227
|
times.sum / times.size
|
166
228
|
end
|
167
229
|
|
230
|
+
def median
|
231
|
+
times = timings.sort
|
232
|
+
return if times.empty?
|
233
|
+
(times[(times.size - 1) / 2] + times[times.size / 2]) / 2.0
|
234
|
+
end
|
235
|
+
|
236
|
+
def percentile(percent)
|
237
|
+
times = timings.sort
|
238
|
+
return if times.empty?
|
239
|
+
return 0 if percent <= 0
|
240
|
+
return max if percent >= 100
|
241
|
+
return times.first if times.size == 1
|
242
|
+
position = (percent / 100.0) * (times.size - 1)
|
243
|
+
|
244
|
+
partial_ratio = position - position.floor
|
245
|
+
whole, partial = times[position.floor, 2]
|
246
|
+
whole + (partial - whole) * partial_ratio
|
247
|
+
end
|
248
|
+
|
168
249
|
def timings
|
169
250
|
if active?
|
170
251
|
@past_timings + [now - @start_time]
|
data/lib/time_up/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_up
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -19,6 +19,7 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- ".github/workflows/main.yml"
|
21
21
|
- ".gitignore"
|
22
|
+
- ".standard.yml"
|
22
23
|
- CHANGELOG.md
|
23
24
|
- Gemfile
|
24
25
|
- Gemfile.lock
|