Codebase list golang-github-beorn7-perks / 456f18a
quantile: Replace container/list with a slice Better data locality trumps asymptotic behavior in this case. benchmark old ns/op new ns/op delta BenchmarkQuerySmallEpsilon 44491 6782 -84.76% BenchmarkInsertBiasedSmallEpsilon 2641 871 -67.02% BenchmarkQuery 691 306 -55.72% BenchmarkInsertBiased 324 177 -45.37% BenchmarkInsertTargetedSmallEpsilon 1016 616 -39.37% BenchmarkInsertTargeted 294 191 -35.03% Caleb Spare 9 years ago
1 changed file(s) with 28 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
1414 package quantile
1515
1616 import (
17 "container/list"
1817 "math"
1918 "sort"
2019 )
8685
8786 func newStream(ƒ invariant) *Stream {
8887 const defaultEpsilon = 0.01
89 x := &stream{epsilon: defaultEpsilon, ƒ: ƒ, l: list.New()}
88 x := &stream{epsilon: defaultEpsilon, ƒ: ƒ}
9089 return &Stream{x, make(Samples, 0, 500), true}
9190 }
9291
169168 }
170169
171170 func (s *Stream) flushed() bool {
172 return s.stream.l.Len() > 0
171 return len(s.stream.l) > 0
173172 }
174173
175174 type stream struct {
176175 epsilon float64
177176 n float64
178 l *list.List
177 l []*Sample
179178 ƒ invariant
180179 }
181180
188187 }
189188
190189 func (s *stream) reset() {
191 s.l.Init()
190 s.l = s.l[:0]
192191 s.n = 0
193192 }
194193
208207 // NOTE: I used a goto over defer because it bought me a few extra
209208 // nanoseconds. I know. I know.
210209 var r float64
211 e := s.l.Front()
210 i := 0
212211 return func(v, w float64) {
213 for ; e != nil; e = e.Next() {
214 c := e.Value.(*Sample)
212 for ; i < len(s.l); i++ {
213 c := s.l[i]
215214 if c.Value > v {
216 sm := &Sample{v, w, math.Floor(s.ƒ(s, r)) - 1}
217 s.l.InsertBefore(sm, e)
215 // Insert at position i.
216 s.l = append(s.l, nil)
217 copy(s.l[i+1:], s.l[i:])
218 s.l[i] = &Sample{v, w, math.Floor(s.ƒ(s, r)) - 1}
219 i++
218220 goto inserted
219221 }
220222 r += c.Width
221223 }
222 s.l.PushBack(&Sample{v, w, 0})
224 s.l = append(s.l, &Sample{v, w, 0})
225 i++
223226 inserted:
224227 s.n += w
225228 }
230233 }
231234
232235 func (s *stream) query(q float64) float64 {
233 e := s.l.Front()
234236 t := math.Ceil(q * s.n)
235237 t += math.Ceil(s.ƒ(s, t) / 2)
236 p := e.Value.(*Sample)
237 e = e.Next()
238 p := s.l[0]
238239 r := float64(0)
239 for e != nil {
240 c := e.Value.(*Sample)
240 for _, c := range s.l[1:] {
241241 if r+c.Width+c.Delta > t {
242242 return p.Value
243243 }
244244 r += p.Width
245245 p = c
246 e = e.Next()
247246 }
248247 return p.Value
249248 }
250249
251250 func (s *stream) compress() {
252 if s.l.Len() < 2 {
251 if len(s.l) < 2 {
253252 return
254253 }
255 e := s.l.Back()
256 x := e.Value.(*Sample)
254 x := s.l[len(s.l)-1]
257255 r := s.n - 1 - x.Width
258 e = e.Prev()
259 for e != nil {
260 c := e.Value.(*Sample)
256
257 for i := len(s.l) - 2; i >= 0; i-- {
258 c := s.l[i]
261259 if c.Width+x.Width+x.Delta <= s.ƒ(s, r) {
262260 x.Width += c.Width
263 o := e
264 e = e.Prev()
265 s.l.Remove(o)
261 // Remove element at i.
262 copy(s.l[i:], s.l[i+1:])
263 s.l[len(s.l)-1] = nil
264 s.l = s.l[:len(s.l)-1]
266265 } else {
267266 x = c
268 e = e.Prev()
269267 }
270268 r -= c.Width
271269 }
272270 }
273271
274272 func (s *stream) samples() Samples {
275 samples := make(Samples, 0, s.l.Len())
276 for e := s.l.Front(); e != nil; e = e.Next() {
277 samples = append(samples, *e.Value.(*Sample))
273 samples := make(Samples, len(s.l))
274 for i, c := range s.l {
275 samples[i] = *c
278276 }
279277 return samples
280278 }