Created
September 17, 2012 18:30
-
-
Save zeen/3738934 to your computer and use it in GitHub Desktop.
A basic XMPP benchmark script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- | |
-- XMPP server benchmark tool | |
-- | |
options = { | |
username = "waqas"; | |
hostname = "example.com"; | |
resource = "x"; | |
password = " "; | |
connect_host = "localhost"; | |
connect_port = 5222; | |
payload = "<message to='[email protected]/x'/>"; | |
--payload = "<iq type='result' id='' to='[email protected]/x'/>"; | |
--payload = "<iq type='get' id=''><ping xmlns='urn:xmpp:ping'/></iq>"; | |
--payload = "<presence/>"; | |
iterations = 10; | |
payloads_per_iteration = 9000; | |
} | |
-- | |
local function read_tag(conn) | |
local s = ""; | |
while true do | |
local ch = assert(conn:receive(1)); | |
s = s..ch; | |
if ch == ">" then | |
if s:match("^<%?.-%?>$") then -- <?xml?> | |
s = ""; | |
return read_tag(conn); | |
else | |
assert(s:match("^<.->$")); | |
return s; | |
end | |
end | |
end | |
end | |
local function read_stanza(conn) | |
local s = assert(conn:receive(1)); | |
assert(s == "<"); | |
local sx = s; | |
while true do | |
local ch = assert(conn:receive(1)); | |
s = s..ch; | |
sx = sx..ch; | |
if ch == ">" then | |
sx = sx:gsub("<[^<]+/>$", ""); -- get rid of empty tags | |
sx = sx:gsub("<[^/][^<]+>[^<]*</[^<]+>$", ""); -- get rid of open-close pairs | |
if sx == "" then | |
return s; | |
end | |
end | |
end | |
end | |
local function send(conn, data) | |
local n = assert(conn:send(data)); | |
assert(n == #data); | |
end | |
function b64(data) | |
return ((data:gsub('.', function(x) | |
local r,b='',x:byte() | |
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end | |
return r; | |
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) | |
if (#x < 6) then return '' end | |
local c=0 | |
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end | |
return ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'):sub(c+1,c+1) | |
end)..({ '', '==', '=' })[#data%3+1]) | |
end | |
-- open connection | |
local socket = require "socket"; | |
local client = socket:tcp(); | |
assert(client:connect(options.connect_host, options.connect_port)); | |
-- send and receive login | |
local xml1 = [[<stream:stream to=']]..options.hostname..[[' version='1.0' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>]] | |
..[[<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>]]..b64("\0"..options.username.."\0"..options.password)..[[</auth>]]; | |
send(client, xml1); | |
print(read_tag(client)); -- <stream:stream> | |
print(read_stanza(client)); -- <stream:features> | |
print(); | |
print(read_stanza(client)); -- <success> | |
print(); | |
-- send and receive bind | |
local xml2 = [[<stream:stream to=']]..options.hostname..[[' version='1.0' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>]] | |
..[[<iq type='set' id=''><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>]]..options.resource..[[</resource></bind></iq>]]; | |
send(client, xml2); | |
print(read_tag(client)); -- <stream:stream> | |
print(read_stanza(client)); -- <stream:features> | |
print(); | |
print(read_stanza(client)); -- <bind> | |
print(); | |
-- send a message to measure response size | |
local single_write_payload = options.payload; | |
send(client, single_write_payload); | |
local single_read_payload = read_stanza(client); | |
print("Send: "..single_write_payload); | |
print("Recv: "..single_read_payload); | |
print(); | |
print("For 1 payload, write: "..#single_write_payload.." bytes, read: "..#single_read_payload.." bytes"); | |
-- build full payload for iteration | |
local count = options.payloads_per_iteration; | |
local write_payload = single_write_payload:rep(count); | |
local read_payload = single_read_payload:rep(count); | |
local read_size = #single_read_payload*count; | |
print("For "..count.." payloads, write: "..#write_payload.." bytes, read: "..#read_payload.." bytes"); | |
print(); | |
-- do iterations | |
local t_start = socket.gettime(); | |
local min = math.huge; | |
for i=1,options.iterations do | |
local t = socket.gettime(); | |
send(client, write_payload); | |
local response = assert(client:receive(read_size)); | |
local td = socket.gettime() - t; | |
assert(response == read_payload); | |
min = math.min(min, td); | |
print("Time: "..td.."s, "..math.floor(count/td).." stanzas/s"); | |
end | |
local td_all = socket.gettime() - t_start; | |
print(); | |
print("Fastest time: "..min.."s, "..math.floor(count/min).." stanzas/s"); | |
print("Total: "..td_all.."s, "..math.floor(count*options.iterations/td_all).." stanzas/s") | |
print(); | |
-- close | |
send(client, [[</stream:stream>]]); | |
local result = assert(client:receive("*a")); | |
assert(result == [[</stream:stream>]]); | |
print(result); | |
client:close(); | |
-- The End |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment