Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding script to generate (stacked) server instances on a single host #206

Merged
merged 32 commits into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9ba9ead
adding script to generate (stacked) server instances on a single host
Nov 30, 2018
a946a4d
fix missing prefix for bring-up.sh
Nov 30, 2018
5bfd160
fix some bugs wrt file/dir creation
Dec 1, 2018
84bf421
adding client script
Dec 1, 2018
ef6d849
add config option for key/val size (which adjusts hash_power value)
Dec 12, 2018
c02b8d4
adding bash script to generate server config groups
Dec 12, 2018
6e5daa0
Merge branch 'master' into scripts
Dec 14, 2018
e4e9c53
making config file path relative/local to bring-up.sh
Dec 15, 2018
409f010
using memcache style timestamp to work with rpcperf properly (which a…
Dec 15, 2018
9f7621c
update server-side config generator with prefill options and minor fixes
Dec 18, 2018
e046389
Merge branch 'master' of github.com:twitter/pelikan into scripts
Dec 18, 2018
9f79189
update client_config.py to match (server) prefilling pattern
Dec 18, 2018
91abd18
update client config parameters per Brian's suggestion
Dec 19, 2018
2c4ca06
improve client config; add comment; add waterfall chart output; add l…
Dec 19, 2018
95f6822
flattern log dir config for stacked server jobs
Dec 20, 2018
ac89b1a
add script to launch a single test
Dec 20, 2018
102623c
make changes needed to launch runtest.sh from the client host
Dec 20, 2018
7e121a5
uncomment client_run
Dec 20, 2018
96c4e96
Merge branch 'master' into scripts
Jan 14, 2019
1579a8e
make binary & server_ip required parameters
Jan 15, 2019
77adec2
fix typo
Jan 15, 2019
53da822
make rpc-perf binary location configurable too
Jan 15, 2019
aa35a96
adapt client config for new rpc-perf which has different config syntax
Jan 15, 2019
ab47258
further parameterization
Jan 15, 2019
2a0d4e7
misnomer corrected
Jan 15, 2019
a51bfc6
good day for typo
Jan 15, 2019
3e09291
more one word change
Jan 15, 2019
f99cce8
restoring waterfall now that rpc-perf (prerelease) has the feature ad…
Jan 17, 2019
d3549b2
Merge branch 'master' into scripts
Jan 17, 2019
efd291c
Merge branch 'master' into scripts
Jan 29, 2019
8bd14db
add stats log related config to server
Jan 29, 2019
e0cd439
increase timing wheel size to allow 10 second timeout
Jan 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions scripts/load_testing/client_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import argparse
import os

INSTANCES = 3
PREFIX = 'test'
THREADS = 1
CONNECTIONS = 100
RATE = 10000
GET_RATIO = 0.9
SET_RATIO = 1 - GET_RATIO
SIZE = 4
PELIKAN_SERVER_PORT = 12300
PELIKAN_SERVER_IP = '10.25.2.44'
RPCPERF_BINARY = '/root/Twitter/rpc-perf/target/release/rpc-perf'

def generate_config(prefix, threads, connections, rate, size):
# create rpcperf.toml
rate_get = int(rate * GET_RATIO)
rate_set = int(rate * SET_RATIO)
config_str = """\
[general]
threads = {threads}
tcp-nodelay = true
connections = {connections}
windows = 600
thinkingfish marked this conversation as resolved.
Show resolved Hide resolved
duration = 60
request-timeout = 200
connect-timeout = 50
thinkingfish marked this conversation as resolved.
Show resolved Hide resolved

thinkingfish marked this conversation as resolved.
Show resolved Hide resolved
[[workload]]
name = "get"
method = "get"
rate = {rate_get}
[[workload.parameter]]
style = "random"
size = {size}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be key size?

This comment was marked as spam.

This comment was marked as spam.

regenerate = true

[[workload]]
name = "set"
method = "set"
rate = {rate_set}
[[workload.parameter]]
style = "random"
size = {size}
regenerate = true
[[workload.parameter]]
style = "random"
size = {size}
regenerate = false
""".format(threads=threads, connections=connections, rate_get=rate_get, rate_set=rate_set, size=size)
with open(os.path.join(prefix, 'rpcperf.toml'), 'w') as the_file:
the_file.write(config_str)

def generate_runscript(prefix, instances):
# create test.sh
fname = os.path.join(prefix, 'test.sh')
with open(fname, 'w') as the_file:
for i in range(instances):
server_port = PELIKAN_SERVER_PORT + i
the_file.write('{binary_file} --config {config_file}'.format(binary_file=RPCPERF_BINARY, config_file='rpcperf.toml'))
thinkingfish marked this conversation as resolved.
Show resolved Hide resolved
the_file.write(' --server {server_ip}:{server_port} &\n'.format(server_ip=PELIKAN_SERVER_IP, server_port=server_port))
thinkingfish marked this conversation as resolved.
Show resolved Hide resolved
os.chmod(fname, 0777)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="""
Generate all the client-side scripts/configs needed for a test run.
""")
parser.add_argument('--prefix', dest='prefix', type=str, default=PREFIX, help='folder that contains all the other files to be generated')
parser.add_argument('--instances', dest='instances', type=int, default=INSTANCES, help='number of instances')
parser.add_argument('--threads', dest='threads', type=int, default=THREADS, help='number of worker threads per rpc-perf')
parser.add_argument('--connections', dest='connections', type=int, default=CONNECTIONS, help='number of connections PER THREAD')
parser.add_argument('--rate', dest='rate', type=int, default=RATE, help='aggregated request rate')
parser.add_argument('--size', dest='size', type=int, default=SIZE, help='payload size')

args = parser.parse_args()

if not os.path.exists(args.prefix):
os.makedirs(args.prefix)

generate_config(args.prefix, args.threads, args.connections, args.rate, args.size)
generate_runscript(args.prefix, args.instances)
15 changes: 15 additions & 0 deletions scripts/load_testing/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

mem_configs=(4 8 16 32)
size_configs=(32 64 128 256 512 1024 2048)
instances=30

for size in "${size_configs[@]}"
do
for mem in "${mem_configs[@]}"
do
slab_mem=$((mem * 1024 * 1024 * 1024))
prefix=test_${size}_${mem}
python server_config.py --prefix="$prefix" --instances="$instances" --slab_mem "$slab_mem" --size "$size"
done
done
100 changes: 100 additions & 0 deletions scripts/load_testing/server_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import argparse
from math import ceil, floor, log
import os

INSTANCES = 3
PREFIX = 'test'
PELIKAN_ADMIN_PORT = 9900
PELIKAN_SERVER_PORT = 12300
PELIKAN_SERVER_IP = '10.25.2.45'
PELIKAN_SIZE = 64
PELIKAN_SLAB_MEM = 4294967296
PELIKAN_BINARY = '/root/Twitter/pelikan/_build/_bin/pelikan_twemcache'
THREAD_PER_SOCKET = 48
BIND_TO_CORES = False
BIND_TO_NODES = True

def generate_config(prefix, instances, hash_power, slab_mem):
# create top-level folders under prefix
config_path = os.path.join(prefix, 'config')
os.makedirs(config_path)
log_path = os.path.join(prefix, 'log')
os.makedirs(log_path)

# create twemcache config file(s)
for i in range(instances):
admin_port = PELIKAN_ADMIN_PORT + i
server_port = PELIKAN_SERVER_PORT + i
config_file = 'pelikan-{server_port}.config'.format(server_port=server_port)
config_str = """\
daemonize: yes
admin_port: {admin_port}
server_port: {server_port}

buf_init_size: 4096

buf_sock_poolsize: 16384

debug_log_level: 5
debug_log_file: log/{server_port}/twemcache.log
thinkingfish marked this conversation as resolved.
Show resolved Hide resolved
debug_log_nbuf: 1048576

klog_file: log/{server_port}/twemcache.cmd
klog_backup: log/{server_port}/twemcache.cmd.old
klog_sample: 100
klog_max: 1073741824

request_poolsize: 16384
response_poolsize: 32768

slab_evict_opt: 1
slab_prealloc: yes
slab_hash_power: {hash_power}
slab_mem: {slab_mem}
slab_size: 1048756
""".format(admin_port=admin_port, server_port=server_port, hash_power=hash_power, slab_mem=slab_mem)
try:
os.makedirs(os.path.join(log_path, str(server_port)))
except:
pass
with open(os.path.join(config_path, config_file),'w') as the_file:
the_file.write(config_str)

def generate_runscript(prefix, instances):
config_path = os.path.join(prefix, 'config')
# create bring-up.sh
fname = os.path.join(prefix, 'bring-up.sh')
with open(fname,'w') as the_file:
for i in range(instances):
config_file = os.path.join(config_path, 'pelikan-{server_port}.config'.format(server_port=PELIKAN_SERVER_PORT+i))
if BIND_TO_NODES:
the_file.write('sudo numactl --cpunodebind={numa_node} --preferred={numa_node} '.format(
numa_node=i%2))
elif BIND_TO_CORES:
the_file.write('sudo numactl --physcpubind={physical_thread},{logical_thread} '.format(
physical_thread=i,
logical_thread=i+THREAD_PER_SOCKET))
the_file.write('{binary_file} {config_file}\n'.format(
binary_file=PELIKAN_BINARY,
config_file=config_file))
os.chmod(fname, 0777)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="""
Generate all the server-side scripts/configs needed for a test run.
""")
parser.add_argument('--prefix', dest='prefix', type=str, default=PREFIX, help='folder that contains all the other files to be generated')
parser.add_argument('--instances', dest='instances', type=int, default=INSTANCES, help='number of instances')
parser.add_argument('--size', dest='size', type=int, default=PELIKAN_SIZE, help='key+val total size')
parser.add_argument('--slab_mem', dest='slab_mem', type=int, default=PELIKAN_SLAB_MEM, help='total capacity of slab memory, in bytes')

args = parser.parse_args()

nkey = 1.0 * args.slab_mem / args.size
hash_power = int(ceil(log(nkey, 2)))

if not os.path.exists(args.prefix):
os.makedirs(args.prefix)

generate_config(args.prefix, args.instances, hash_power, args.slab_mem)
generate_runscript(args.prefix, args.instances)