mg.lua revision f71b5f99
1local mg      = require "moongen"
2local memory  = require "memory"
3local device  = require "device"
4local stats   = require "stats"
5local hist    = require "histogram"
6local timer   = require "timer"
7local barrier = require "barrier"
8local table   = require "table"
9local math    = require "math"
10
11function configure(parser)
12	parser:description("Packet loss graph.")
13	parser:option("--txport", "Device to transmit/receive from."):convert(tonumber)
14	parser:option("--rxport", "Device to transmit/receive from."):convert(tonumber)
15	parser:option("--dst", "Frame's destination hardware address")
16	parser:option("--duration", "Device to transmit/receive from."):default(20):convert(tonumber)
17	parser:option("--frameSize", "Ethernet frame size."):default(64):convert(tonumber)
18	parser:option("--maxRateInterval", "Max % rate interval between measures"):default(5):convert(tonumber)
19	parser:option("--minRateInterval", "Min % rate interval between measures"):default(0.1):convert(tonumber)
20	parser:option("--targetDropRateRatio", "Target drop rate ratio between measures"):default(2):convert(tonumber)
21	parser:option("--out", "Output file"):default("vhost_mg_"..os.date("%F_%H-%M")..".txt")
22end
23
24function getHeaderString(file)
25	return string.format("%10s\t%10s\t%12s\t%12s\t%12s\t%12s\t%12s\t%12s\t%12s\t%12s", 
26	"size(B)", "Time(s)", "Rate(Mbps)", "Tx(pkt)", "Rx(pkt)", "DropRate(%)", "Tx(Mpps)", "Rx(Mpps)", "Tx(Gbps)", "Rx(Gbps)")
27end
28
29function getResultString(result, file)
30	return string.format("%10d\t%10d\t%12f\t%12d\t%12d\t%12f\t%12f\t%12f\t%12f\t%12f", 
31	result.frameSize, result.duration, result.rate, result.tx, result.rx, result.dropRate, result.txMpps, result.rxMpps, result.txRate, result.rxRate)
32end
33
34function runMeasure(txDev, rxDev, frameSize, duration, rate)
35	local bar = barrier.new(2)
36	local result = {}
37	txDev:getTxQueue(0):setRate(rate * frameSize / (frameSize+20))
38	local stask = mg.startTask("loadSlave", txDev:getTxQueue(0), frameSize, duration, bar)
39	local rtask = mg.startTask("counterSlave", rxDev:getRxQueue(0), frameSize, duration, bar)
40	result.frameSize = frameSize
41	result.duration = duration
42	result.tx = stask:wait()
43	result.rx = rtask:wait()
44	result.rate = rate
45	result.dropRate = (result.tx - result.rx)/result.tx * 100
46	result.txMpps = (result.tx) / duration / 1000000
47	result.rxMpps = (result.rx) / duration / 1000000
48	result.txRate = (result.tx * frameSize * 8) / duration / 1000000000
49	result.rxRate = (result.rx * frameSize * 8) / duration / 1000000000
50	
51	print(getResultString(result))
52	return result
53end
54
55function master(args)
56	local txDev = device.config({port = args.txport, rxQueues = 1, txQueues = 1})
57	local rxDev = device.config({port = args.rxport, rxQueues = 1, txQueues = 1})
58	local frameSize = args.frameSize
59	local duration = args.duration
60	device.waitForLinks()
61	
62	local maxLinkRate = txDev:getLinkStatus().speed
63	local results = {}
64	
65	-- Warming up
66	print ("Output file is: "..args.out)
67	print ("Start Warm-Up")
68	runMeasure(txDev, rxDev, frameSize, 1, maxLinkRate)
69	runMeasure(txDev, rxDev, frameSize, 1, 1000)
70	print ("Stop Warm-Up")
71	
72	local sortFunction = function(a,b)
73		return a.rate < b.rate
74	end
75	
76	local file = io.open(args.out, "w")
77	io.output(file)
78	io.write(getHeaderString().."\n")
79	io.close(file)
80	
81	print ("Start Measures")
82	print(getHeaderString())
83	table.insert(results, runMeasure(txDev, rxDev, frameSize, duration, maxLinkRate))
84	table.insert(results, runMeasure(txDev, rxDev, frameSize, duration, maxLinkRate/2))
85	table.insert(results, runMeasure(txDev, rxDev, frameSize, duration, 100))
86	table.sort(results, sortFunction)
87	
88	while mg.running() do
89		local chosen = nil
90		local chosenMeaning = 0
91		for i, r1 in ipairs(results) do
92			local r2 = results[i+1]
93			if r2 == nil then
94				break
95			end
96			local rateDiff = r2.rate - r1.rate
97			local dropRateRatio = (r2.dropRate + 0.00000001)/(r1.dropRate + 0.00000001)
98			if r2.dropRate < r1.dropRate then  
99				dropRateRatio = (r1.dropRate+ 0.00000001)/(r2.dropRate + 0.00000001)
100			end
101			-- Meaning rates next measures
102			-- The idea is to compute interesting results first and get more picky later.
103			local meaning = rateDiff / ((args.maxRateInterval * maxLinkRate) / 100 ) + math.log(dropRateRatio / args.targetDropRateRatio)/math.log(2)
104			if rateDiff > (args.maxRateInterval * maxLinkRate) / 100
105				or (dropRateRatio > args.targetDropRateRatio and (rateDiff) > (args.minRateInterval * maxLinkRate) / 100) then
106					if meaning > chosenMeaning then
107						chosenMeaning = meaning
108						chosen = i
109					end
110			end
111		end
112		if (chosen == nil) then
113			break
114		end
115		local nextRate = (results[chosen+1].rate + results[chosen].rate)/2
116		table.insert(results, runMeasure(txDev, rxDev, frameSize, duration, nextRate))
117		table.sort(results, sortFunction)
118		
119		local file = io.open(args.out, "w")
120		io.output(file)
121		io.write(getHeaderString().."\n")
122		for i, r1 in ipairs(results) do
123			io.write(getResultString(r1).."\n")
124		end
125		io.close(file)
126	end
127	
128	
129end
130
131function loadSlave(queue, frameSize, duration, bar)
132    bar:wait()
133
134	local mem = memory.createMemPool(function(buf)
135		buf:getEthernetPacket():fill{
136			ethSrc = queue,
137			ethDst = ETH_DST,
138			ethType = 0x1234
139		}
140	end)
141
142    local bufs = mem:bufArray()
143    local timer = timer:new(duration)
144	local total = 0;
145	while timer:running() do
146		bufs:alloc(frameSize)
147		total = total + queue:send(bufs)
148	end
149	return total
150end
151
152function counterSlave(queue, frameSize, duration, bar)
153    local bufs = memory.bufArray()
154	local total = 0;
155    bar:wait()
156
157    local timer = timer:new(duration + 1)
158    while timer:running() do
159		total = total + queue:tryRecv(bufs, 1000)
160		bufs:freeAll()
161    end
162    return total
163end
164
165