+Bench scripts

This commit is contained in:
quackerd 2021-02-20 04:53:55 -05:00
parent 06b93ddf1c
commit d1e43dcf2f
Signed by: d
GPG Key ID: F73412644EDE357A
9 changed files with 317 additions and 89 deletions

View File

@ -24,9 +24,9 @@
constexpr static unsigned int MBUF_MAX_COUNT = 65536;
constexpr static unsigned int MBUF_CACHE_SIZE = 512;
constexpr static unsigned int RX_RING_SIZE = 4096;
constexpr static unsigned int TX_RING_SIZE = 4096;
constexpr static unsigned int BURST_SIZE = 8;
constexpr static unsigned int RX_RING_SIZE = 1024;
constexpr static unsigned int TX_RING_SIZE = 1024;
constexpr static unsigned int BURST_SIZE = 32;
constexpr static unsigned int MAX_SLAVES = 32;
static const struct rte_eth_conf port_conf_default {
@ -126,7 +126,8 @@ rx_add_timestamp(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
options.s_last_datapt->clt_hw_rx);
} else {
rte_exit(EXIT_FAILURE,
"rx_add_timestamp: packet %p not tagged - hw ts not available - %d.\n",
"rx_add_timestamp: packet %p not tagged - hw ts not "
"available - %d.\n",
(void *)pkts[i], ret);
}
} else {
@ -682,7 +683,7 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
static void
dump_options()
{
fprintf(stdout,
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO,
"Configuration:\n"
" verbosity = +%d\n"
" run time = %d\n"
@ -697,6 +698,17 @@ dump_options()
options.warmup_time, options.output, options.rage_quit_time,
options.cpu_mask, options.ia_gen_str, options.target_qps,
options.s_host_spec.ip);
for (auto slave : options.slaves) {
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO,
" slave = 0x%x@%x:%x:%x:%x:%x:%x\n", slave->ip,
slave->mac_addr.addr_bytes[0],
slave->mac_addr.addr_bytes[1],
slave->mac_addr.addr_bytes[2],
slave->mac_addr.addr_bytes[3],
slave->mac_addr.addr_bytes[4],
slave->mac_addr.addr_bytes[5]);
}
}
static void
@ -759,8 +771,7 @@ main(int argc, char *argv[])
break;
case 'S':
ns = new struct net_spec;
if (str_to_netspec(
optarg, &options.server_spec) != 0) {
if (str_to_netspec(optarg, ns) != 0) {
rte_exit(EXIT_FAILURE,
"invalid client net spec\n");
}
@ -918,6 +929,7 @@ main(int argc, char *argv[])
qps += options.s_slave_qps.load();
// dump stats
log_file << qps << std::endl;
for (auto it : options.s_data) {
if (it->valid) {
log_file << it->clt_sw_rx << ',' << it->clt_sw_tx << ','
@ -929,9 +941,7 @@ main(int argc, char *argv[])
}
log_file.close();
fprintf(stdout,
"Processed %d packets in %d seconds. Total QPS (incl. slaves): %d\n",
qps, options.run_time, qps);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "Total QPS = %d\n", qps);
// clean up
rte_eth_dev_stop(portid);

View File

@ -20,8 +20,8 @@
constexpr static unsigned int MBUF_MAX_COUNT = 65536;
constexpr static unsigned int MBUF_CACHE_SIZE = 512;
constexpr static unsigned int RX_RING_SIZE = 4096;
constexpr static unsigned int TX_RING_SIZE = 4096;
constexpr static unsigned int RX_RING_SIZE = 1024;
constexpr static unsigned int TX_RING_SIZE = 1024;
constexpr static unsigned int BURST_SIZE = 32;
constexpr static size_t MEMPOOL_NAME_BUF_LEN = 64;
@ -731,14 +731,18 @@ main(int argc, char *argv[])
}
}
options.mlg->start();
if (options.mlg_enabled)
options.mlg->start();
while (true) {
usleep(S2US);
uint64_t bps = options.mlg->get_bps();
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG,
"main: MLG bps = %ld ~= %ldM\n", bps, bps / 1024 / 1024);
if (options.mlg_enabled) {
uint64_t bps = options.mlg->get_bps();
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG,
"main: MLG bps = %ld ~= %ldM\n", bps, bps / 1024 / 1024);
}
}
options.mlg->stop();
if (options.mlg_enabled)
options.mlg->stop();
for (int i = 0; i < options.num_threads; i++) {
struct thread_info *tinfo = options.s_thr_info.at(i);

View File

@ -21,9 +21,9 @@
constexpr static unsigned int MBUF_MAX_COUNT = 65536;
constexpr static unsigned int MBUF_CACHE_SIZE = 512;
constexpr static unsigned int RX_RING_SIZE = 4096;
constexpr static unsigned int TX_RING_SIZE = 4096;
constexpr static unsigned int BURST_SIZE = 8;
constexpr static unsigned int RX_RING_SIZE = 1024;
constexpr static unsigned int TX_RING_SIZE = 1024;
constexpr static unsigned int BURST_SIZE = 32;
static const struct rte_eth_conf port_conf_default {
};
@ -795,8 +795,7 @@ main(int argc, char *argv[])
}
if (options.slave_mode != 1) {
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "main: total QPS = %d\n",
qps);
fprintf(stdout, "main: total QPS = %d\n", qps);
}
// clean up

4
scripts/compile.sh Executable file → Normal file
View File

@ -1,7 +1,7 @@
#!/bin/sh
test_dir="/numam.d"
root=".."
servers="skylake2.rcs.uwaterloo.ca skylake3.rcs.uwaterloo.ca skylake6.rcs.uwaterloo.ca"
servers="skylake2.rcs.uwaterloo.ca skylake3.rcs.uwaterloo.ca skylake6.rcs.uwaterloo.ca skylake7.rcs.uwaterloo.ca skylake8.rcs.uwaterloo.ca"
rsync_flags="-vchr"
ssh_args="-o StrictHostKeyChecking=no -p77"
@ -22,7 +22,7 @@ compile() {
ssh $(echo $ssh_args $user@$1) "sudo chmod 777 $test_dir"
rsync $(echo $rsync_flags) -e 'ssh -p 77' $root/ $user@$1:$test_dir/
echo "Compiling..."
ssh $(echo $ssh_args $user@$1) "sudo mkdir -p $test_dir/build; cd $test_dir/build; sudo rm -rf *; sudo cmake ../; sudo make clean all -j8" &
ssh $(echo $ssh_args $user@$1) "sudo pkg install -y hwloc2 cmake; sudo mkdir -p $test_dir/build; cd $test_dir/build; sudo rm -rf *; sudo cmake ../; sudo make clean all -j8" &
wait
echo "$1 Done."
echo ""

37
scripts/compile_dpdk.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/sh
dpdk_dir="/dpdk"
root=".."
servers="skylake2.rcs.uwaterloo.ca skylake3.rcs.uwaterloo.ca skylake6.rcs.uwaterloo.ca skylake7.rcs.uwaterloo.ca skylake8.rcs.uwaterloo.ca"
rsync_flags="-vchr"
ssh_args="-o StrictHostKeyChecking=no -p77"
user=$1
iface="ixl0"
if [ -z $user ]
then
user=$(whoami)
fi
echo "USER: $user"
compile() {
# separate these functions because we might change kernel (reboot) without needing to recompile
echo "====================$1===================="
#ssh $(echo $ssh_args $user@$1) "sudo reboot"
ssh $(echo $ssh_args $user@$1) "sudo sh -c \"mkdir -p $dpdk_dir; cd $dpdk_dir; git clone https://git.quacker.org/d/numam-dpdk; cd numam-dpdk; git reset --hard; git clean -f; rm -rf build; meson -Denable_kmods=true build; cd build; ninja install\""
wait
echo "$1 Done."
echo ""
}
i=0
for server in $servers
do
i=$(expr $i + 1)
compile "$server" &
done
wait

127
scripts/graph.py Executable file
View File

@ -0,0 +1,127 @@
#!/usr/bin/env python3.6
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import ticker
import numpy as np
import sys
import re
import os
import json
import libpar as par
import getopt
import math
import concurrent.futures as CF
def process_dir(rootdir):
ret = []
print("Processing directory " + rootdir + " ...")
for subdir in os.listdir(rootdir):
each_dir = os.path.join(rootdir, subdir)
if os.path.isfile(each_dir) and each_dir.endswith(".txt"):
output = None
try:
with open(each_dir, 'r') as f:
output = f.read()
parser = par.khat_parser()
parser.parse(output)
print("Processed raw data - " + each_dir)
ret.append(parser)
except:
print("Unrecognized format - " + subdir)
print("")
return ret
marker_map = ["o", "P", "s", "v", "*", "+", "^", "1", "2", "d", "X"]
color_map = ["xkcd:black", "xkcd:red", "xkcd:blue", "xkcd:green", "xkcd:cyan", "xkcd:yellow"]
parser_idx_labels = ["srv_hw", "srv_sw", "clt_hw", "clt_sw"]
def add_curve(eax, label : str, qps_arr : [], lat_arr : [], marker : str, color : str):
df_dict = {}
df_dict['qps'] = qps_arr
df_dict['lat'] = lat_arr
df = pd.DataFrame(df_dict)
df = df.sort_values('qps')
eax.plot('qps', 'lat', data = df, label=label, marker=marker, color=color, markersize=8)
# adds curves (avg and 99th percentile) for a specific parser idx
def add_curves(rax, label : str, parsers : [], parser_idx : int, marker : str, color : str):
qps_arr = []
avg_arr = []
p99_arr = []
for parser in parsers:
qps_arr.append(parser.qps)
each_lat_arr = []
each_lat_arr.extend(parser.get_stat_arr(parser_idx))
avg_arr.append(np.mean(each_lat_arr))
p99_arr.append(np.percentile(each_lat_arr, 99))
add_curve(rax[0], label, qps_arr, avg_arr, marker, color)
add_curve(rax[1], label, qps_arr, p99_arr, marker, color)
# generate the graphs for a parser index
def generate_graph(aff_to_parser : {}, parser_idx : int, fn : str):
marker_idx = 0
color_idx = 0
fig, rax = plt.subplots(2, 1)
rax[0].set_yscale("log")
rax[0].set_title("Average")
rax[0].set_xlabel("QPS")
rax[0].set_ylabel("Latency (ns)")
rax[0].xaxis.get_major_formatter().set_scientific(False)
rax[0].yaxis.set_minor_formatter(ticker.ScalarFormatter())
rax[1].set_yscale("log")
rax[1].set_title("99th percentile")
rax[1].set_xlabel("QPS")
rax[1].set_ylabel("Latency (ns)")
rax[1].xaxis.get_major_formatter().set_scientific(False)
rax[1].yaxis.set_minor_formatter(ticker.ScalarFormatter())
print("Generating graph => " + fn + "...")
for aff in aff_to_parser:
# each affinity gets a different marker type
marker_type = marker_map[marker_idx]
color_type = color_map[color_idx]
marker_idx += 1
color_idx += 1
print(" Processing affinity " + aff + "...")
add_curves(rax, aff, aff_to_parser[aff], parser_idx, marker_type, color_type)
rax[0].legend()
rax[1].legend()
fig.set_size_inches(23.4, 16.5)
plt.savefig(fn, dpi=300)
plt.close()
def main():
datdir = None
options = getopt.getopt(sys.argv[1:], 'd:')[0]
for opt, arg in options:
if opt in ('-d'):
datdir = arg
if datdir == None:
raise Exception("Must specify -d parameter")
dat = {}
for subdir in os.listdir(datdir):
each_dir = os.path.join(datdir, subdir)
if not os.path.isfile(each_dir):
dat[subdir] = process_dir(each_dir)
for i in range(len(parser_idx_labels)):
generate_graph(dat, i, datdir + "/" + parser_idx_labels[i])
if __name__ == "__main__":
main()

View File

@ -12,12 +12,31 @@ class khat_parser:
self.c_hrx = 0
self.c_stx = 0
self.c_srx = 0
self.qps = 0
def __init__(self):
self.datapt = []
self.srv_hwlat = []
self.srv_swlat = []
self.clt_hwlat = []
self.clt_swlat = []
self.lat_idx_arr = []
self.lat_idx_arr.append(self.srv_hwlat)
self.lat_idx_arr.append(self.srv_swlat)
self.lat_idx_arr.append(self.clt_hwlat)
self.lat_idx_arr.append(self.clt_swlat)
def get_stat_arr(self, idx : int):
return self.lat_idx_arr[idx]
def parse(self, output : str):
first = True
for line in output.splitlines():
# the first line is qps
if (first):
self.qps = int(line)
first = False
continue
cells = line.split(',')
if len(cells) != 8:
raise Exception("Invalid line:" + line)
@ -31,6 +50,10 @@ class khat_parser:
pt.s_hrx = int(cells[6])
pt.s_htx = int(cells[7])
self.datapt.append(pt)
self.srv_hwlat.append(pt.s_htx - pt.s_hrx)
self.srv_swlat.append(pt.s_stx - pt.s_srx)
self.clt_hwlat.append(pt.c_hrx - pt.c_htx)
self.clt_swlat.append(pt.c_srx - pt.c_stx)
class mutilate_data:

View File

@ -91,7 +91,7 @@ def scan_stderr(p, exclude = None):
err = err.decode()
err = err.strip()
# print(err)
#print(err)
if len(err) == 0:
continue
@ -140,7 +140,6 @@ def errthr_stop():
global errthr_objs
global errthr_sigstop
errthr_sigstop = True
# print("waiting!")
for thr in errthr_objs:
thr.join()
errthr_objs.clear()

View File

@ -13,8 +13,8 @@ import libpar as par
import libtc as tc
step_inc_pct = 100
init_step = 20000 #
start_step = 10000
init_step = 200000 #
start_step = 200000
term_qps = 85000000000
term_pct = 1
@ -28,22 +28,20 @@ root_dir = os.path.join(file_dir,"..")
sample_filename = "sample.txt"
affinity = [
"0x4", # core 2
"0x400", # core 10
"0x100000", # core 20
"0x1000000", # core 24
"0x40000000", # core 30
"0x10000000000" # core 40
"0xAA", # all first socket
"0xAA000000", # all 2nd socket
]
master = ["skylake3.rcs.uwaterloo.ca"]
master_mac = ["3c:15:fb:c9:f3:4b"]
master = ["skylake2.rcs.uwaterloo.ca"]
master_spec = ["192.168.123.10@3c:15:fb:c9:f3:36"]
master_cpumask = "0x4" # 1 thread
server = ["skylake2.rcs.uwaterloo.ca"]
server_mac = ["3c:15:fb:c9:f3:36"]
server = ["skylake3.rcs.uwaterloo.ca"]
server_spec = ["192.168.123.9@3c:15:fb:c9:f3:4b"]
clients = []
client_mac = []
clients = ["skylake6.rcs.uwaterloo.ca", "skylake7.rcs.uwaterloo.ca", "skylake8.rcs.uwaterloo.ca"]
client_spec = ["192.168.123.11@3c:15:fb:62:9b:2f", "192.168.123.12@3c:15:fb:c9:f3:44", "192.168.123.13@3c:15:fb:62:9c:be"]
client_cpumask = "0xAAAAAAAAAAAA"
rage_quit = 1000 #1s
warmup = 5
@ -52,6 +50,7 @@ cooldown = 0
cacheline = 0
SSH_PARAM = "-o StrictHostKeyChecking=no -p77"
SSH_USER = "oscar"
master_qps = 100
hostfile = None
lockstat = False
@ -60,68 +59,82 @@ client_only = False
def stop_all():
# stop clients
tc.log_print("Stopping clients...")
tc.remote_exec(clients, "sudo killall -9 rat", check=False)
tc.remote_exec(clients, "sudo killall -9 rat; sudo killall -9 cat; sudo killall -9 khat", check=False)
if not client_only:
# stop server
tc.log_print("Stopping server...")
tc.remote_exec(server, "sudo killall -9 khat", check=False)
tc.remote_exec(server, "sudo killall -9 rat; sudo killall -9 cat; sudo killall -9 khat", check=False)
# stop master
tc.log_print("Stopping master...")
tc.remote_exec(master, "sudo killall -9 cat", check=False)
tc.remote_exec(master, "sudo killall -9 rat; sudo killall -9 cat; sudo killall -9 khat", check=False)
def get_client_str(clt):
ret = " "
for client in clt:
ret += " -a " + client + " "
def get_client_str():
ret = ""
for client in client_spec:
ret += " -S " + client + " "
return ret
def run_exp(sc, ld):
def calc_client_ld(ld : int):
return 0 if ld == 0 else ((ld - master_qps) / len(clients))
def run_exp(affinity : str, ld : int):
while True:
if client_only:
ssrv = None
else:
# start server
tc.log_print("Starting server...")
server_cmd = "sudo " + test_dir + "/khat -- -A " + sc
server_cmd = "sudo " + test_dir + "/khat --log-level lib.eal:err -- -A " + affinity + \
" -H " + server_spec[0]
tc.log_print(server_cmd)
ssrv = tc.remote_exec(server, server_cmd, blocking=False)
# start clients
# tc.log_print("Starting clients...")
# client_cmd = tc.get_cpuset_core(client_threads) + " " + test_dir + "/pingpong/build/dismember -A"
# tc.log_print(client_cmd)
# sclt = tc.remote_exec(ssh_clients, client_cmd, blocking=False)
tc.log_print("Starting clients...")
sclt = []
for i in range(len(clients)):
client_cmd = "sudo " + test_dir + "/rat --log-level lib.eal:err -- -S -A " + client_cpumask + \
" -i exponential " + \
" -q " + str(calc_client_ld(ld)) + \
" -H " + client_spec[i] + \
" -s " + server_spec[0] + \
" -r " + str(rage_quit)
tc.log_print(client_cmd)
sclt.append(tc.remote_exec([clients[i]], client_cmd, blocking=False)[0])
time.sleep(3)
time.sleep(1)
# start master
tc.log_print("Starting master...")
master_cmd = "sudo " + test_dir + "/cat -- " + \
" -s " + server_mac[0] + \
master_cmd = "sudo " + test_dir + "/cat --log-level lib.eal:err -- " + \
" -s " + server_spec[0] + \
" -o " + test_dir + "/" + sample_filename + \
" -t " + str(duration) + \
" -T " + str(warmup) + \
" -i fixed:0.001" + \
" -i exponential" + \
" -q " + str(master_qps) + \
" -r " + str(rage_quit) + \
" -A 0x4"
" -A " + master_cpumask + \
" -H " + master_spec[0] + \
get_client_str()
tc.log_print(master_cmd)
sp = tc.remote_exec(master, master_cmd, blocking=False)
p = sp[0]
# launch stderr monitoring thread
tc.errthr_create(sp, exclude=[".*EAL.*"])
tc.errthr_create(ssrv, exclude=[".*EAL.*"])
exclude = None
tc.errthr_create(sp, exclude)
tc.errthr_create(ssrv, exclude)
tc.errthr_create(sclt, exclude)
tc.errthr_start()
success = False
cur = 0
while True:
# either failed or timeout
# we use failure detection to save time for long durations
if tc.errthr_get_failed() or cur >= int(warmup + duration) + 5 :
if tc.errthr_get_failed() or cur >= int(warmup + duration) * 2 :
break
if p.poll() != None:
@ -140,14 +153,30 @@ def run_exp(sc, ld):
return
def keep_results():
scpcmd = "scp -P77 oscar@" + master[0] + ":" + test_dir + "/" + sample_filename + " " + tc.get_odir() + "/sample.txt"
target_scp_fn = tc.get_odir() + "/sample.txt"
scpcmd = "scp -P77 oscar@" + master[0] + ":" + test_dir + "/" + sample_filename + " " + target_scp_fn
tc.log_print(scpcmd)
sp.check_call(scpcmd, shell=True)
with open(tc.get_odir() + "/sample.txt", 'r') as f:
tc.log_print("Total requests: " + str(len(f.readlines())))
parser = par.khat_parser()
with open(target_scp_fn, "r") as f:
parser.parse(f.read())
return
target_fn = tc.get_odir() + "/" + str(parser.qps) + ".txt"
mvcmd = "mv " + target_scp_fn + " " + target_fn
tc.log_print(mvcmd)
sp.check_call(mvcmd, shell=True)
tc.log_print("=== Latency Summary:")
tc.log_print("=== Server HW:")
tc.log_print(par.mutilate_data.build_mut_output(parser.srv_hwlat, [parser.qps]) + "\n")
tc.log_print("=== Server SW:")
tc.log_print(par.mutilate_data.build_mut_output(parser.srv_swlat, [parser.qps]) + "\n")
tc.log_print("=== Client HW:")
tc.log_print(par.mutilate_data.build_mut_output(parser.clt_hwlat, [parser.qps]) + "\n")
tc.log_print("=== Client SW:")
tc.log_print(par.mutilate_data.build_mut_output(parser.clt_swlat, [parser.qps]) + "\n")
return parser.qps
def main():
global hostfile
@ -185,9 +214,9 @@ def main():
for i in range(0, len(affinity)):
eaff = affinity[i]
# step_mul = 100
# last_load = 0
# cur_load = start_step
step_mul = 100
last_load = 0
cur_load = start_step
tc.begin(eaff)
@ -196,31 +225,31 @@ def main():
keep_results()
stop_all()
# while True:
# tc.log_print("============ Sched: " + str(ename) + " Flag: " + format(esched, '#04x') + " Load: " + str(cur_load) + " ============")
while True:
tc.log_print("============ Affinity: " + str(eaff) + " Load: " + str(cur_load) + " ============")
# output, sout, serr = run_exp(esched, cur_load, lockstat)
run_exp(eaff, cur_load)
# qps = keep_results(output, sout, serr)
qps = keep_results()
# pct = int((qps - last_load) / init_step * 100)
# tc.log_print("last_load: " + str(last_load) + " this_load: " + str(qps) + " inc_pct: " + str(pct) + "%")
pct = int((qps - last_load) / init_step * 100)
tc.log_print("last_load: " + str(last_load) + " this_load: " + str(qps) + " inc_pct: " + str(pct) + "%")
# if cur_load > term_qps:
# tc.log_print("qps more than " + str(term_qps) + "%. Done.")
# break
if cur_load > term_qps:
tc.log_print("qps more than " + str(term_qps) + "%. Done.")
break
# if pct <= term_pct:
# tc.log_print("inc_pct less than TERM_PCT " + str(term_pct) + "%. Done.")
# break
if pct <= term_pct:
tc.log_print("inc_pct less than TERM_PCT " + str(term_pct) + "%. Done.")
break
# if pct <= inc_pct:
# step_mul += step_inc_pct
# tc.log_print("inc_pct less than INC_PCT " + str(inc_pct) + "%. Increasing step multiplier to " + str(step_mul) + "%")
if pct <= inc_pct:
step_mul += step_inc_pct
tc.log_print("inc_pct less than INC_PCT " + str(inc_pct) + "%. Increasing step multiplier to " + str(step_mul) + "%")
# last_load = qps
# cur_load += int(init_step * step_mul / 100)
# tc.log_print("")
last_load = qps
cur_load += int(init_step * step_mul / 100)
tc.log_print("")
tc.end()