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  }