quantile: Speed up queries by avoiding creating closures
benchmark old ns/op new ns/op delta
BenchmarkQuery 306 105 -65.69%
BenchmarkInsertBiasedSmallEpsilon 871 833 -4.36%
BenchmarkQuerySmallEpsilon 6782 6599 -2.70%
BenchmarkInsertTargeted 191 188 -1.57%
BenchmarkInsertTargetedSmallEpsilon 616 611 -0.81%
BenchmarkInsertBiased 177 176 -0.56%
Caleb Spare
9 years ago
192 | 192 | } |
193 | 193 | |
194 | 194 | func (s *stream) insert(v float64) { |
195 | fn := s.mergeFunc() | |
196 | fn(v, 1) | |
195 | s.merge(Samples{{v, 1, 0}}) | |
197 | 196 | } |
198 | 197 | |
199 | 198 | func (s *stream) merge(samples Samples) { |
200 | fn := s.mergeFunc() | |
201 | for _, s := range samples { | |
202 | fn(s.Value, s.Width) | |
203 | } | |
204 | } | |
205 | ||
206 | func (s *stream) mergeFunc() func(v, w float64) { | |
207 | // NOTE: I used a goto over defer because it bought me a few extra | |
208 | // nanoseconds. I know. I know. | |
209 | 199 | var r float64 |
210 | 200 | i := 0 |
211 | return func(v, w float64) { | |
201 | for _, sample := range samples { | |
212 | 202 | for ; i < len(s.l); i++ { |
213 | 203 | c := s.l[i] |
214 | if c.Value > v { | |
204 | if c.Value > sample.Value { | |
215 | 205 | // Insert at position i. |
216 | 206 | s.l = append(s.l, nil) |
217 | 207 | copy(s.l[i+1:], s.l[i:]) |
218 | s.l[i] = &Sample{v, w, math.Floor(s.ƒ(s, r)) - 1} | |
208 | s.l[i] = &Sample{sample.Value, sample.Width, math.Floor(s.ƒ(s, r)) - 1} | |
219 | 209 | i++ |
220 | 210 | goto inserted |
221 | 211 | } |
222 | 212 | r += c.Width |
223 | 213 | } |
224 | s.l = append(s.l, &Sample{v, w, 0}) | |
214 | s.l = append(s.l, &Sample{sample.Value, sample.Width, 0}) | |
225 | 215 | i++ |
226 | 216 | inserted: |
227 | s.n += w | |
217 | s.n += sample.Width | |
228 | 218 | } |
229 | 219 | } |
230 | 220 |