github.com/uber/kraken@v0.1.4/lib/torrent/scheduler/buckets.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package scheduler 15 16 import ( 17 "time" 18 19 "github.com/uber/kraken/utils/memsize" 20 "github.com/uber-go/tally" 21 ) 22 23 type bucket struct { 24 sizeTag string 25 min uint64 26 durations tally.DurationBuckets 27 } 28 29 func newBucket(sizeTag string, min uint64) *bucket { 30 return &bucket{sizeTag, min, nil} 31 } 32 33 func (b *bucket) addRange(start, stop, width time.Duration) { 34 cur := start 35 for cur < stop { 36 b.durations = append(b.durations, cur) 37 cur += width 38 } 39 } 40 41 var _buckets []*bucket 42 43 func init() { 44 xs := newBucket("xsmall", 0) 45 xs.addRange(250*time.Millisecond, time.Second, 250*time.Millisecond) 46 xs.addRange(time.Second, 20*time.Second, time.Second) 47 xs.addRange(20*time.Second, time.Minute, 5*time.Second) 48 xs.addRange(time.Minute, 5*time.Minute, time.Minute) 49 xs.addRange(5*time.Minute, 30*time.Minute, 5*time.Minute) 50 _buckets = append(_buckets, xs) 51 52 s := newBucket("small", 100*memsize.MB) 53 s.addRange(time.Second, 30*time.Second, time.Second) 54 s.addRange(30*time.Second, time.Minute, 5*time.Second) 55 s.addRange(time.Minute, 5*time.Minute, time.Minute) 56 s.addRange(5*time.Minute, 30*time.Minute, 5*time.Minute) 57 _buckets = append(_buckets, s) 58 59 m := newBucket("medium", memsize.GB) 60 m.addRange(2*time.Second, time.Minute, 2*time.Second) 61 m.addRange(time.Minute, 2*time.Minute, 5*time.Second) 62 m.addRange(2*time.Minute, 5*time.Minute, 30*time.Second) 63 m.addRange(5*time.Minute, 10*time.Minute, time.Minute) 64 m.addRange(10*time.Minute, 30*time.Minute, 5*time.Minute) 65 _buckets = append(_buckets, m) 66 67 l := newBucket("large", 2*memsize.GB) 68 l.addRange(5*time.Second, 3*time.Minute, 5*time.Second) 69 l.addRange(3*time.Minute, 5*time.Minute, 30*time.Second) 70 l.addRange(5*time.Minute, 10*time.Minute, time.Minute) 71 l.addRange(10*time.Minute, 30*time.Minute, 5*time.Minute) 72 _buckets = append(_buckets, l) 73 74 xl := newBucket("xlarge", 5*memsize.GB) 75 xl.addRange(10*time.Second, 5*time.Minute, 10*time.Second) 76 xl.addRange(5*time.Minute, 10*time.Minute, 30*time.Second) 77 xl.addRange(10*time.Minute, 30*time.Minute, time.Minute) 78 _buckets = append(_buckets, xl) 79 80 xxl := newBucket("xxlarge", 10*memsize.GB) 81 xxl.addRange(15*time.Second, 10*time.Minute, 15*time.Second) 82 xxl.addRange(10*time.Minute, 15*time.Minute, 30*time.Second) 83 xxl.addRange(15*time.Minute, 30*time.Minute, time.Minute) 84 _buckets = append(_buckets, xxl) 85 86 // Sanity check to ensure buckets are sorted. 87 for i := 0; i < len(_buckets)-1; i++ { 88 if _buckets[i].min >= _buckets[i+1].min { 89 panic("buckets are not sorted properly") 90 } 91 } 92 } 93 94 // getBucket selects the largest bucket size fits into. 95 func getBucket(size uint64) (b *bucket) { 96 for i := len(_buckets) - 1; i >= 0; i-- { 97 b = _buckets[i] 98 if size >= b.min { 99 break 100 } 101 } 102 return b 103 } 104 105 func recordDownloadTime(stats tally.Scope, size int64, t time.Duration) { 106 b := getBucket(uint64(size)) 107 stats.Tagged(map[string]string{ 108 "size": b.sizeTag, 109 "version": "3", 110 }).Histogram("download_time", b.durations).RecordDuration(t) 111 }