1 ---------------------------------
2 --- @file histogram.lua
3 --- @brief Histrogram ...
5 ---------------------------------
8 histogram.__index = histogram
10 local serpent = require
"Serpent"
12 function histogram:create()
13 local histo = setmetatable({}, histogram)
19 histogram.new = histogram.create
21 setmetatable(histogram, {
__call = histogram.create })
23 function histogram:update(k)
24 if not k then return end
25 self.histo[k] = (self.histo[k] or 0) +1
29 function histogram:calc()
34 for k, v in pairs(
self.histo) do
35 table.insert(self.sortedHisto, { k = k, v = v })
36 self.numSamples =
self.numSamples + v
37 self.sum =
self.sum + k * v
39 self.avg =
self.sum /
self.numSamples
41 for k, v in pairs(
self.histo) do
42 stdDevSum = stdDevSum + v * (k - self.avg)^2
44 self.stdDev = (stdDevSum / (self.numSamples - 1)) ^ 0.5
46 table.sort(self.sortedHisto, function(e1, e2) return e1.k < e2.k end)
48 -- TODO: this is obviously not entirely correct for numbers not divisible by 4
49 -- however, it doesn't really matter for the number of samples we usually use
50 local quartSamples = self.numSamples / 4
55 for _, p in ipairs(
self.sortedHisto) do
58 if not self.quarts[1] and idx >= quartSamples then
60 elseif not self.quarts[2] and idx >= quartSamples * 2 then
62 elseif not self.quarts[3] and idx >= quartSamples * 3 then
71 if not self.quarts[i] then
78 function histogram:totals()
79 if self.dirty then self:calc() end
81 return self.numSamples, self.sum, self.avg
84 function histogram:avg()
85 if self.dirty then self:calc() end
90 function histogram:standardDeviation()
91 if self.dirty then self:calc() end
96 function histogram:quartiles()
97 if self.dirty then self:calc() end
99 return unpack(self.quarts)
102 function histogram:median()
103 if self.dirty then self:calc() end
105 return self.quarts[2]
108 function histogram:samples()
110 if self.dirty then self:calc() end
111 local
n =
#self.sortedHisto
113 if not
self.dirty then
115 if i <=
n then
return self.sortedHisto[i] end
120 -- FIXME:
add support
for different formats
121 function histogram:print(prefix)
122 if self.dirty then self:calc() end
124 printf("%sSamples: %d, Average: %.1f ns, StdDev: %.1f ns, Quartiles: %.1f/%.1f/%.1f ns", prefix and ("[" .. prefix .. "] ") or "", self.numSamples, self.avg, self.stdDev, unpack(self.quarts))
127 function histogram:save(file)
128 if self.dirty then self:calc() end
130 if type(file) ~= "userdata" then
131 printf("Saving histogram to '%s'", file)
132 file = io.open(file, "w+")
135 for i, v in ipairs(self.sortedHisto) do
136 file:write(("%s,%s\
n"):format(v.k, v.v))
144 function histogram:__serialize()
145 return "require 'histogram'; return " .. serpent.addMt(serpent.dumpRaw(self), "require('histogram')"), true
function lock __call(func,...)
Wrap a function call in lock/unlock calls.
function printf(str,...)
Print a formatted string.
function ip4Addr add(val)
Add a number to an IPv4 address in-place.
n
Create a new array of memory buffers (initialized to nil).