Comparison

util/statistics.lua @ 6557:8aa967c81cbc

Merge 0.10->trunk
author Matthew Wild <mwild1@gmail.com>
date Wed, 21 Jan 2015 01:29:00 +0000
parent 6555:7b2d16c14659
child 6562:2b5ced5ca31f
comparison
equal deleted inserted replaced
6543:01cd51777abb 6557:8aa967c81cbc
1 local t_sort = table.sort
2 local m_floor = math.floor;
3 local time = require "socket".gettime;
4
5 local function nop_function() end
6
7 local function percentile(arr, length, pc)
8 local n = pc/100 * (length + 1);
9 local k, d = m_floor(n), n%1;
10 if k == 0 then
11 return arr[1];
12 elseif k >= length then
13 return arr[length];
14 end
15 return arr[k] + d*(arr[k+1] - arr[k]);
16 end
17
18 local function new_registry(config)
19 config = config or {};
20 local duration_sample_interval = config.duration_sample_interval or 5;
21 local duration_max_samples = config.duration_max_stored_samples or 5000;
22
23 local function get_distribution_stats(events, n_actual_events, since, new_time, units)
24 local n_stored_events = #events;
25 t_sort(events);
26 local sum = 0;
27 for i = 1, n_stored_events do
28 sum = sum + events[i];
29 end
30
31 return {
32 samples = events;
33 sample_count = n_stored_events;
34 count = n_actual_events,
35 rate = n_actual_events/(new_time-since);
36 average = n_stored_events > 0 and sum/n_stored_events or 0,
37 min = events[1] or 0,
38 max = events[n_stored_events] or 0,
39 units = units,
40 };
41 end
42
43
44 local registry = {};
45 local methods;
46 methods = {
47 amount = function (name, initial)
48 local v = initial or 0;
49 registry[name..":amount"] = function () return "amount", v; end
50 return function (new_v) v = new_v; end
51 end;
52 counter = function (name, initial)
53 local v = initial or 0;
54 registry[name..":amount"] = function () return "amount", v; end
55 return function (delta)
56 v = v + delta;
57 end;
58 end;
59 rate = function (name)
60 local since, n = time(), 0;
61 registry[name..":rate"] = function ()
62 local t = time();
63 local stats = {
64 rate = n/(t-since);
65 count = n;
66 };
67 since, n = t, 0;
68 return "rate", stats.rate, stats;
69 end;
70 return function ()
71 n = n + 1;
72 end;
73 end;
74 distribution = function (name, unit, type)
75 type = type or "distribution";
76 local events, last_event = {}, 0;
77 local n_actual_events = 0;
78 local since = time();
79
80 registry[name..":"..type] = function ()
81 local new_time = time();
82 local stats = get_distribution_stats(events, n_actual_events, since, new_time, unit);
83 events, last_event = {}, 0;
84 n_actual_events = 0;
85 since = new_time;
86 return type, stats.average, stats;
87 end;
88
89 return function (value)
90 n_actual_events = n_actual_events + 1;
91 if n_actual_events%duration_sample_interval > 0 then
92 last_event = (last_event%duration_max_samples) + 1;
93 events[last_event] = value;
94 end
95 end;
96 end;
97 sizes = function (name)
98 return methods.distribution(name, "bytes", "size");
99 end;
100 times = function (name)
101 local events, last_event = {}, 0;
102 local n_actual_events = 0;
103 local since = time();
104
105 registry[name..":duration"] = function ()
106 local new_time = time();
107 local stats = get_distribution_stats(events, n_actual_events, since, new_time, "seconds");
108 events, last_event = {}, 0;
109 n_actual_events = 0;
110 since = new_time;
111 return "duration", stats.average, stats;
112 end;
113
114 return function ()
115 n_actual_events = n_actual_events + 1;
116 if n_actual_events%duration_sample_interval > 0 then
117 return nop_function;
118 end
119
120 local start_time = time();
121 return function ()
122 local end_time = time();
123 local duration = end_time - start_time;
124 last_event = (last_event%duration_max_samples) + 1;
125 events[last_event] = duration;
126 end
127 end;
128 end;
129
130 get_stats = function ()
131 return registry;
132 end;
133 };
134 return methods;
135 end
136
137 return {
138 new = new_registry;
139 get_histogram = function (duration, n_buckets)
140 n_buckets = n_buckets or 100;
141 local events, n_events = duration.samples, duration.sample_count;
142 if not (events and n_events) then
143 return nil, "not a valid distribution stat";
144 end
145 local histogram = {};
146
147 for i = 1, 100, 100/n_buckets do
148 histogram[i] = percentile(events, n_events, i);
149 end
150 return histogram;
151 end;
152
153 get_percentile = function (duration, pc)
154 local events, n_events = duration.samples, duration.sample_count;
155 if not (events and n_events) then
156 return nil, "not a valid distribution stat";
157 end
158 return percentile(events, n_events, pc);
159 end;
160 }