From fff3bce92dce1501846a3f8ee6b350375ed22c58 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 12 Jan 2015 15:10:37 +0100 Subject: util.hex: Pedantic optimization, 1 table lookup per byte instead of 3 function calls makes it go faster --- util/hex.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'util') diff --git a/util/hex.lua b/util/hex.lua index b21ee17e..e41f4863 100644 --- a/util/hex.lua +++ b/util/hex.lua @@ -1,19 +1,25 @@ local s_char = string.char; +local s_format = string.format; +local s_gsub = string.gsub; -local function char_to_hex(c) - return ("%02x"):format(c:byte()) -end +local char_to_hex = {}; +local hex_to_char = {}; -local function hex_to_char(h) - return s_char(tonumber(h, 16)); +do + local char, hex; + for i = 0,255 do + char, hex = s_char(i), s_format("%02x", i); + char_to_hex[char] = hex; + hex_to_char[hex] = char; + end end local function to(s) - return s:gsub(".", char_to_hex); + return (s_gsub(s, ".", char_to_hex)); end local function from(s) - return s:gsub("..", hex_to_char); + return (s_gsub(s, "..", hex_to_char)); end return { to = to, from = from } -- cgit v1.2.3 From 4554389fc92b39024a811315776a4a272dac115b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 12:31:32 +0000 Subject: util.statistics: New library for gathering various kinds of statistics --- util/statistics.lua | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 util/statistics.lua (limited to 'util') diff --git a/util/statistics.lua b/util/statistics.lua new file mode 100644 index 00000000..9d332053 --- /dev/null +++ b/util/statistics.lua @@ -0,0 +1,131 @@ +local t_sort = table.sort +local m_floor = math.floor; +local time = require "socket".gettime; + +local function nop_function() end + +local function percentile(arr, length, pc) + local n = pc/100 * (length + 1); + local k, d = m_floor(n), n%1; + if k == 0 then + return arr[1]; + elseif k >= length then + return arr[length]; + end + return arr[k] + d*(arr[k+1] - arr[k]); +end + +local function new_registry(config) + config = config or {}; + local duration_sample_interval = config.duration_sample_interval or 5; + local duration_max_samples = config.duration_max_stored_samples or 5000; + + local registry = {}; + local methods; + methods = { + amount = function (name, initial) + local v = initial or 0; + registry[name] = function () return "amount", v; end + return function (new_v) v = new_v; end + end; + counter = function (name, initial) + local v = initial or 0; + registry[name] = function () return "amount", v; end + return function (delta) + v = v + delta; + end; + end; + rate = function (name) + local since, n = time(), 0; + registry[name] = function () + local t = time(); + local stats = { + rate = n/(t-since); + count = n; + }; + since, n = t, 0; + return "rate", stats.rate, stats; + end; + return function () + n = n + 1; + end; + end; + duration = function (name) + local events, last_event = {}, 0; + local n_actual_events = 0; + local since = time(); + + registry[name] = function () + local n_stored_events = #events; + t_sort(events); + local sum = 0; + for i = 1, n_stored_events do + sum = sum + events[i]; + end + + local new_time = time(); + + local stats = { + samples = events; + sample_count = n_stored_events; + count = n_actual_events, + rate = n_actual_events/(new_time-since); + average = n_stored_events > 0 and sum/n_stored_events or 0, + min = events[1], + max = events[n_stored_events], + }; + + events, last_event = {}, 0; + n_actual_events = 0; + since = new_time; + + return "duration", stats.average, stats; + end; + + return function () + n_actual_events = n_actual_events + 1; + if n_actual_events%duration_sample_interval > 0 then + return nop_function; + end + + local start_time = time(); + return function () + local end_time = time(); + local duration = end_time - start_time; + last_event = (last_event%duration_max_samples) + 1; + events[last_event] = duration; + end + end; + end; + + get_stats = function () + return registry; + end; + }; + return methods; +end + +return { + new = new_registry; + get_histogram = function (duration, n_buckets) + n_buckets = n_buckets or 100; + local events, n_events = duration.samples, duration.sample_count; + if not (events and n_events) then + return nil, "not a valid duration stat"; + end + local histogram = {}; + + for i = 1, 100, 100/n_buckets do + histogram[i] = percentile(events, n_events, i); + end + return histogram; + end; + + get_percentile = function (duration, pc) + local events, n_events = duration.samples, duration.sample_count; + if not (events and n_events) then + return nil, "not a valid duration stat"; + end + return percentile(events, n_events, pc); + end; +} -- cgit v1.2.3 From 6790b2a0ba6b2b10ad327334296b48544e2c6553 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 21 Jan 2015 01:26:06 +0000 Subject: statsmanager, util.statistics: API changes, remove debugging --- util/statistics.lua | 77 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 24 deletions(-) (limited to 'util') diff --git a/util/statistics.lua b/util/statistics.lua index 9d332053..08c765ae 100644 --- a/util/statistics.lua +++ b/util/statistics.lua @@ -20,24 +20,45 @@ local function new_registry(config) local duration_sample_interval = config.duration_sample_interval or 5; local duration_max_samples = config.duration_max_stored_samples or 5000; + local function get_distribution_stats(events, n_actual_events, since, new_time, units) + local n_stored_events = #events; + t_sort(events); + local sum = 0; + for i = 1, n_stored_events do + sum = sum + events[i]; + end + + return { + samples = events; + sample_count = n_stored_events; + count = n_actual_events, + rate = n_actual_events/(new_time-since); + average = n_stored_events > 0 and sum/n_stored_events or 0, + min = events[1] or 0, + max = events[n_stored_events] or 0, + units = units, + }; + end + + local registry = {}; local methods; methods = { amount = function (name, initial) local v = initial or 0; - registry[name] = function () return "amount", v; end + registry[name..":amount"] = function () return "amount", v; end return function (new_v) v = new_v; end end; counter = function (name, initial) local v = initial or 0; - registry[name] = function () return "amount", v; end + registry[name..":amount"] = function () return "amount", v; end return function (delta) v = v + delta; end; end; rate = function (name) local since, n = time(), 0; - registry[name] = function () + registry[name..":rate"] = function () local t = time(); local stats = { rate = n/(t-since); @@ -50,35 +71,43 @@ local function new_registry(config) n = n + 1; end; end; - duration = function (name) + distribution = function (name, unit, type) + type = type or "distribution"; local events, last_event = {}, 0; local n_actual_events = 0; local since = time(); - registry[name] = function () - local n_stored_events = #events; - t_sort(events); - local sum = 0; - for i = 1, n_stored_events do - sum = sum + events[i]; - end - + registry[name..":"..type] = function () local new_time = time(); + local stats = get_distribution_stats(events, n_actual_events, since, new_time, unit); + events, last_event = {}, 0; + n_actual_events = 0; + since = new_time; + return type, stats.average, stats; + end; - local stats = { - samples = events; - sample_count = n_stored_events; - count = n_actual_events, - rate = n_actual_events/(new_time-since); - average = n_stored_events > 0 and sum/n_stored_events or 0, - min = events[1], - max = events[n_stored_events], - }; + return function (value) + n_actual_events = n_actual_events + 1; + if n_actual_events%duration_sample_interval > 0 then + last_event = (last_event%duration_max_samples) + 1; + events[last_event] = value; + end + end; + end; + sizes = function (name) + return methods.distribution(name, "bytes", "size"); + end; + times = function (name) + local events, last_event = {}, 0; + local n_actual_events = 0; + local since = time(); + registry[name..":duration"] = function () + local new_time = time(); + local stats = get_distribution_stats(events, n_actual_events, since, new_time, "seconds"); events, last_event = {}, 0; n_actual_events = 0; since = new_time; - return "duration", stats.average, stats; end; @@ -111,7 +140,7 @@ return { n_buckets = n_buckets or 100; local events, n_events = duration.samples, duration.sample_count; if not (events and n_events) then - return nil, "not a valid duration stat"; + return nil, "not a valid distribution stat"; end local histogram = {}; @@ -124,7 +153,7 @@ return { get_percentile = function (duration, pc) local events, n_events = duration.samples, duration.sample_count; if not (events and n_events) then - return nil, "not a valid duration stat"; + return nil, "not a valid distribution stat"; end return percentile(events, n_events, pc); end; -- cgit v1.2.3