Skip to content

Instantly share code, notes, and snippets.

@zeen
Created September 17, 2012 18:30
Show Gist options
  • Save zeen/3738934 to your computer and use it in GitHub Desktop.
Save zeen/3738934 to your computer and use it in GitHub Desktop.
A basic XMPP benchmark script
--
-- XMPP server benchmark tool
--
options = {
username = "waqas";
hostname = "example.com";
resource = "x";
password = " ";
connect_host = "localhost";
connect_port = 5222;
payload = "<message to='waqas@example.com/x'/>";
--payload = "<iq type='result' id='' to='waqas@example.com/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