-
Notifications
You must be signed in to change notification settings - Fork 0
/
latency_factory.rb
116 lines (98 loc) · 2.34 KB
/
latency_factory.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class LatencyGenerator
def initialize(profile)
@profile = profile
end
def next
min, max = choose_range(rand)
min + ((max - min) * rand) # uniform distribution withiin range
end
def choose_range(seed)
fits_range = dist.keys.first
dist.keys.each do |range|
if seed <= range
fits_range = range
end
end
dist[fits_range].map(&:to_f)
end
def dist
@dist ||= {
0.5 => [@profile[:min], @profile[:p50]],
0.4 => [@profile[:p50], @profile[:p75]],
0.1 => [@profile[:p75], @profile[:p90]],
0.05 => [@profile[:p90], @profile[:p95]],
0.01 => [@profile[:p95], @profile[:p99]],
0.009 => [@profile[:p99], @profile[:p999]],
0.0009 => [@profile[:p999], @profile[:p9999]],
}
end
end
class LatencyReader
def initialize(filename, min_latency = 20)
@filename = filename
@min_latency = min_latency
end
def next
lat = enum.next
if lat < @min_latency
return self.next
end
lat
rescue StopIteration
@enum = latencies.shuffle.to_enum
retry
end
def enum
@enum ||= latencies.shuffle.to_enum
end
def latencies
@latencies ||= read_latencies_from_file
end
def read_latencies_from_file
f = File.open(@filename)
f.readlines.map(&:to_i)
ensure
f.close
end
end
class LatencyFactory
DEFAULT_PROFILE = {
min: 60 ,
p50: 80 ,
p75: 150 ,
p90: 480 ,
p95: 900 ,
p99: 2500 ,
p999: 8000 ,
p9999: 20000 ,
}
def self.from_profile(dist=DEFAULT_PROFILE)
LatencyGenerator.new(dist)
end
def self.from_file(file="latencies.csv")
LatencyReader.new(file)
end
end
def test_factory
require 'pp'
# lat = LatencyFactory.from_profile
lat = LatencyFactory.from_file
decisions = []
2000000.times do
decisions << lat.next
end
sorted = decisions.sort
stats = {
avg: sorted.sum / sorted.size.to_f,
p50: sorted.take((sorted.size * 0.5).to_i).last,
p75: sorted.take((sorted.size * 0.75).to_i).last,
p90: sorted.take((sorted.size * 0.9).to_i).last,
p95: sorted.take((sorted.size * 0.95).to_i + 1).last,
p99: sorted.take((sorted.size * 0.99).to_i).last,
p999: sorted.take((sorted.size * 0.999).to_i).last,
p9999: sorted.take((sorted.size * 0.9999).to_i).last,
}
# pp sorted
pp stats
end
# test_factory