MoonGen
 All Files Functions Variables Pages
histogram.lua
Go to the documentation of this file.
1 ---------------------------------
2 --- @file histogram.lua
3 --- @brief Histrogram ...
4 --- @todo TODO docu
5 ---------------------------------
6 
7 local histogram = {}
8 histogram.__index = histogram
9 
10 local serpent = require "Serpent"
11 
12 function histogram:create()
13  local histo = setmetatable({}, histogram)
14  histo.histo = {}
15  histo.dirty = true
16  return histo
17 end
18 
19 histogram.new = histogram.create
20 
21 setmetatable(histogram, { __call = histogram.create })
22 
23 function histogram:update(k)
24  if not k then return end
25  self.histo[k] = (self.histo[k] or 0) +1
26  self.dirty = true
27 end
28 
29 function histogram:calc()
30  self.sortedHisto = {}
31  self.sum = 0
32  self.numSamples = 0
33 
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
38  end
39  self.avg = self.sum / self.numSamples
40  local stdDevSum = 0
41  for k, v in pairs(self.histo) do
42  stdDevSum = stdDevSum + v * (k - self.avg)^2
43  end
44  self.stdDev = (stdDevSum / (self.numSamples - 1)) ^ 0.5
45 
46  table.sort(self.sortedHisto, function(e1, e2) return e1.k < e2.k end)
47 
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
51 
52  self.quarts = {}
53 
54  local idx = 0
55  for _, p in ipairs(self.sortedHisto) do
56  -- TODO: inefficient
57  for _ = 1, p.v do
58  if not self.quarts[1] and idx >= quartSamples then
59  self.quarts[1] = p.k
60  elseif not self.quarts[2] and idx >= quartSamples * 2 then
61  self.quarts[2] = p.k
62  elseif not self.quarts[3] and idx >= quartSamples * 3 then
63  self.quarts[3] = p.k
64  break
65  end
66  idx = idx + 1
67  end
68  end
69 
70  for i = 1, 3 do
71  if not self.quarts[i] then
72  self.quarts[i] = 0/0
73  end
74  end
75  self.dirty = false
76 end
77 
78 function histogram:totals()
79  if self.dirty then self:calc() end
80 
81  return self.numSamples, self.sum, self.avg
82 end
83 
84 function histogram:avg()
85  if self.dirty then self:calc() end
86 
87  return self.avg
88 end
89 
90 function histogram:standardDeviation()
91  if self.dirty then self:calc() end
92 
93  return self.stdDev
94 end
95 
96 function histogram:quartiles()
97  if self.dirty then self:calc() end
98 
99  return unpack(self.quarts)
100 end
101 
102 function histogram:median()
103  if self.dirty then self:calc() end
104 
105  return self.quarts[2]
106 end
107 
108 function histogram:samples()
109  local i = 0
110  if self.dirty then self:calc() end
111  local n = #self.sortedHisto
112  return function()
113  if not self.dirty then
114  i = i + 1
115  if i <= n then return self.sortedHisto[i] end
116  end
117  end
118 end
119 
120 -- FIXME: add support for different formats
121 function histogram:print(prefix)
122  if self.dirty then self:calc() end
123 
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))
125 end
126 
127 function histogram:save(file)
128  if self.dirty then self:calc() end
129  local close = false
130  if type(file) ~= "userdata" then
131  printf("Saving histogram to '%s'", file)
132  file = io.open(file, "w+")
133  close = true
134  end
135  for i, v in ipairs(self.sortedHisto) do
136  file:write(("%s,%s\n"):format(v.k, v.v))
137  end
138  if close then
139  file:close()
140  end
141 end
142 
143 
144 function histogram:__serialize()
145  return "require 'histogram'; return " .. serpent.addMt(serpent.dumpRaw(self), "require('histogram')"), true
146 end
147 
148 return histogram
149 
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).
Definition: memory.lua:76