Add cmdline params

de64
Vitaliy Filippov 2024-04-19 13:32:01 +03:00
parent 88a7423453
commit ef246e1892
2 changed files with 98 additions and 54 deletions

View File

@ -1,24 +1,23 @@
#!/usr/bin/nodejs #!/usr/bin/nodejs
// "Stupid" gossip algorithm simulation tool // "Stupid" gossip algorithm simulation tool
const gossip = 4; // how many nodes to gossip with every tick function test_simple(options)
const msgcap = 9; // how many nodes to gossip about every tick
const total = 1000; // total nodes
const total_updated = 1000; // total nodes to update if testing update. if 0 then test joining
const initial_nodes = 5; // initial nodes in sync to test joining (when total_updated == 0)
function test()
{ {
options.total ||= 100;
options.gossip ||= 4;
options.msgcap ||= 5;
options.update ||= 0;
options.initial ||= 5;
let messages_sent = 0; let messages_sent = 0;
let tick = 1; let tick = 1;
const known = {}; const known = {};
const lists = {}; const lists = {};
const listsv2 = {}; const listsv2 = {};
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
known[i] = {}; known[i] = {};
lists[i] = []; lists[i] = [];
for (let j = 1; j <= (total_updated ? total : initial_nodes); j++) for (let j = 1; j <= (options.update ? options.total : options.initial); j++)
{ {
known[i][j] = 1; // meta version 1 known[i][j] = 1; // meta version 1
lists[i].push(j); lists[i].push(j);
@ -27,28 +26,28 @@ function test()
} }
let cmp_lists; let cmp_lists;
let cmp_n; let cmp_n;
if (total_updated) if (options.update)
{ {
// We want to update <total_updated> nodes metadata to version 2 // We want to update <options.update> nodes metadata to version 2
for (let i = 1; i <= total_updated; i++) for (let i = 1; i <= options.update; i++)
{ {
known[i][i] = 2; known[i][i] = 2;
listsv2[i].push(i); listsv2[i].push(i);
} }
cmp_lists = listsv2; cmp_lists = listsv2;
cmp_n = total_updated; cmp_n = options.update;
} }
else else
{ {
// We want <total-initial_nodes> to join <initial_nodes> // We want <options.total-options.initial> to join <options.initial>
for (let i = 1; i <= initial_nodes; i++) for (let i = 1; i <= options.initial; i++)
{ {
if (!known[i][i]) if (!known[i][i])
{ {
known[i][i] = 1; known[i][i] = 1;
lists[i].push(i); lists[i].push(i);
} }
for (let alive = initial_nodes+1; alive <= total; alive++) for (let alive = options.initial+1; alive <= options.total; alive++)
{ {
if (!known[i][alive]) if (!known[i][alive])
{ {
@ -58,10 +57,10 @@ function test()
} }
} }
cmp_lists = lists; cmp_lists = lists;
cmp_n = total; cmp_n = options.total;
} }
let in_sync = 0; let in_sync = 0;
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
if (cmp_lists[i].length == cmp_n) if (cmp_lists[i].length == cmp_n)
{ {
@ -69,19 +68,19 @@ function test()
} }
} }
let avg_known = 0; let avg_known = 0;
while (in_sync < total) while (in_sync < options.total)
{ {
console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known); console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known);
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
const known_i = lists[i]; const known_i = lists[i];
const send_to = []; const send_to = [];
for (let j = 0; j < gossip; j++) for (let j = 0; j < options.gossip; j++)
{ {
send_to.push(known_i[0|(Math.random()*known_i.length)]); send_to.push(known_i[0|(Math.random()*known_i.length)]);
} }
const send_what = []; const send_what = [];
for (let j = 0; j < msgcap; j++) for (let j = 0; j < options.msgcap; j++)
{ {
// FIXME: Exclude duplicates, exclude <send_to> // FIXME: Exclude duplicates, exclude <send_to>
send_what.push(known_i[0|(Math.random()*known_i.length)]); send_what.push(known_i[0|(Math.random()*known_i.length)]);
@ -105,15 +104,37 @@ function test()
messages_sent += send_what.length*send_to.length; messages_sent += send_what.length*send_to.length;
} }
avg_known = 0; avg_known = 0;
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
avg_known += cmp_lists[i].length; avg_known += cmp_lists[i].length;
} }
avg_known /= total; avg_known /= options.total;
tick++; tick++;
} }
console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known); console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known);
console.log(messages_sent+' messages sent'); console.log(messages_sent+' messages sent');
} }
test(); const options = {};
for (let i = 2; i < process.argv.length; i++)
{
if (process.argv[i] === '-h' || process.argv[i] === '--help')
{
console.error('USAGE: '+process.argv[0]+' '+process.argv[1]+` [OPTIONS]
--gossip 4 how many nodes to gossip with every tick
--msgcap 5 how many nodes to gossip about every tick
--total 1000 total nodes
--update 0 total nodes to update if testing update. if 0 then test joining
--initial 5 initial nodes in sync to test joining (when --update is 0)`);
process.exit();
}
else if (process.argv[i].substr(0, 2) == '--')
{
options[process.argv[i].substr(2)] = 0|process.argv[i+1];
i++;
}
}
test_simple(options);

View File

@ -1,15 +1,6 @@
#!/usr/bin/nodejs #!/usr/bin/nodejs
// https://github.com/hashicorp/memberlist simulation tool // https://github.com/hashicorp/memberlist simulation tool
const gossip = 4; // how many nodes to gossip with every tick
const msgcap = 9; // how many "alive" messages fits in a single packet (meta size/UDP packet size in memberlist)
const max_ticks = 100000; // execution limit
const max_queue = 1024; // queue size limit
const total = 1000; // total nodes
const retransmit = 18; // by default log(total)*4 in memberlist
const total_updated = 1000; // total nodes to update if testing update. if 0 then test joining
const initial_nodes = 5; // initial nodes in sync to test joining (when total_updated == 0)
class LimQ class LimQ
{ {
constructor(retransmit, maxlen) constructor(retransmit, maxlen)
@ -53,46 +44,53 @@ class LimQ
} }
} }
function test() function test_memberlist(options)
{ {
options.gossip ||= 4;
options.msgcap ||= 5;
options.max_ticks ||= 100000;
options.total ||= 100;
options.retransmit ||= 12;
options.update ||= 0;
options.initial ||= 5;
let tick = 0; let tick = 0;
let messages_sent = 0; let messages_sent = 0;
const queue = {}; const queue = {};
const known = {}; // { node: { other_node: meta_version } } const known = {}; // { node: { other_node: meta_version } }
const lists = {}; const lists = {};
const listsv2 = {}; const listsv2 = {};
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
known[i] = {}; known[i] = {};
lists[i] = []; lists[i] = [];
for (let j = 1; j <= (total_updated ? total : initial_nodes); j++) for (let j = 1; j <= (options.update ? options.total : options.initial); j++)
{ {
known[i][j] = 1; // meta version 1 known[i][j] = 1; // meta version 1
lists[i].push(j); lists[i].push(j);
} }
listsv2[i] = []; listsv2[i] = [];
queue[i] = new LimQ(retransmit, max_queue); queue[i] = new LimQ(options.retransmit, options.max_queue);
} }
let cmp_lists; let cmp_lists;
let cmp_n; let cmp_n;
if (total_updated) if (options.update)
{ {
// We want to update <total_updated> nodes metadata to version 2 // We want to update <options.update> nodes metadata to version 2
for (let i = 1; i <= total_updated; i++) for (let i = 1; i <= options.update; i++)
{ {
known[i][i] = 2; known[i][i] = 2;
listsv2[i].push(i); listsv2[i].push(i);
queue[i].push(i); queue[i].push(i);
} }
cmp_lists = listsv2; cmp_lists = listsv2;
cmp_n = total_updated; cmp_n = options.update;
} }
else else
{ {
// We want <total-initial_nodes> to join <initial_nodes> // We want <options.total-options.initial> to join <options.initial>
for (let i = 1; i <= initial_nodes; i++) for (let i = 1; i <= options.initial; i++)
{ {
for (let alive = initial_nodes+1; alive <= total; alive++) for (let alive = options.initial+1; alive <= options.total; alive++)
{ {
known[i][alive] = 1; known[i][alive] = 1;
lists[i].push(alive); lists[i].push(alive);
@ -100,10 +98,10 @@ function test()
} }
} }
cmp_lists = lists; cmp_lists = lists;
cmp_n = total; cmp_n = options.total;
} }
let in_sync = 0; let in_sync = 0;
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
if (cmp_lists[i].length == cmp_n) if (cmp_lists[i].length == cmp_n)
{ {
@ -111,16 +109,16 @@ function test()
} }
} }
let avg_known = 0; let avg_known = 0;
while (in_sync < total && tick < max_ticks) while (in_sync < options.total && tick < options.max_ticks)
{ {
console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known); console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known);
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
const known_i = lists[i]; const known_i = lists[i];
for (let g = 0; g < gossip; g++) for (let g = 0; g < options.gossip; g++)
{ {
const to = known_i[0|(Math.random()*known_i.length)]; const to = known_i[0|(Math.random()*known_i.length)];
let send_what = queue[i].shift(msgcap); let send_what = queue[i].shift(options.msgcap);
messages_sent += send_what.length; messages_sent += send_what.length;
for (const alive of send_what) for (const alive of send_what)
{ {
@ -140,15 +138,40 @@ function test()
} }
} }
avg_known = 0; avg_known = 0;
for (let i = 1; i <= total; i++) for (let i = 1; i <= options.total; i++)
{ {
avg_known += cmp_lists[i].length; avg_known += cmp_lists[i].length;
} }
avg_known /= total; avg_known /= options.total;
tick++; tick++;
} }
console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known); console.log('tick '+tick+': '+in_sync+' in sync, avg '+avg_known);
console.log(messages_sent+' messages sent'); console.log(messages_sent+' messages sent');
} }
test(); const options = {};
for (let i = 2; i < process.argv.length; i++)
{
if (process.argv[i] === '-h' || process.argv[i] === '--help')
{
console.error('USAGE: '+process.argv[0]+' '+process.argv[1]+` [OPTIONS]
--gossip 4 how many nodes to gossip with every tick
--msgcap 5 how many "alive" messages fits in a single packet (meta size/UDP packet size in memberlist)
--max_ticks 100000 execution limit
--max_queue 1024 queue size limit
--total 100 total nodes
--retransmit 12 retransmission count. by default log(total)*4 in memberlist
--update 0 total nodes to update if testing update. if 0 then test joining
--initial 5 initial nodes in sync to test joining (when --update is 0)`);
process.exit();
}
else if (process.argv[i].substr(0, 2) == '--')
{
options[process.argv[i].substr(2)] = 0|process.argv[i+1];
i++;
}
}
test_memberlist(options);