Commit 52e493a8 authored by Florian Fischer's avatar Florian Fischer
Browse files

bench/perf: move perf code from server to perf and add root support

parent 1fd79948
Pipeline #73371 passed with stage
in 1 minute and 33 seconds
# Copyright 2021 Florian Fischer
"""Perf related variables"""
"""Perf related variables and code"""
import logging
import subprocess
log = logging.getLogger(__name__)
PERF_EXE = 'perf'
......@@ -17,3 +22,51 @@ PERF_STAT_CMD = f'{PERF_EXE} stat -e {{events}} record -o {{output}} -p {{pid}}'
PERF_RECORD_OUTPUT = '{run}_perf_record.data'
PERF_STAT_OUTPUT = '{run}_perf_stat.data'
def record(server_pid,
run,
bench_dir,
remote_cmd=None,
root=False) -> subprocess.Popen:
"""Start a perf process recording the server with the passed pid"""
record_out = bench_dir / PERF_RECORD_OUTPUT.format(run=run)
record_cmd = PERF_RECORD_CMD.format(pid=server_pid, output=record_out)
if root:
record_cmd = f'sudo {record_cmd}'
if remote_cmd:
record_cmd = f'{remote_cmd} {record_cmd}'
log.debug('start perf record process using: %s', record_cmd)
return subprocess.Popen(record_cmd.split())
def record_stats(server_pid,
counters,
run,
bench_dir,
remote_cmd=None,
root=False) -> subprocess.Popen:
"""Start a perf process recording the server's stats with the passed pid"""
if counters is not None:
if len(counters) == 0:
counters = DDD_EVENTS
else:
counters = ','.join(counters)
stat_out = bench_dir / PERF_STAT_OUTPUT.format(run=run)
stat_cmd = PERF_STAT_CMD.format(pid=server_pid,
events=counters,
output=stat_out)
if root:
stat_cmd = f'sudo {stat_cmd}'
if remote_cmd:
stat_cmd = f'{remote_cmd} {stat_cmd}'
log.debug('start perf stat process using: %s', stat_cmd)
return subprocess.Popen(stat_cmd.split())
......@@ -7,7 +7,6 @@ import subprocess
from .globalvars import KILL_CMD, TERMINATION_TIME
from .util import cmd_run, prepare_env
from . import perf
log = logging.getLogger(__name__)
......@@ -27,16 +26,12 @@ class Server(subprocess.Popen):
env=None,
measure_cmd=None,
remote_cmd=None,
perf_counters=None,
perf_record=False,
host=None):
self.name = name
self.cmd = cmd
self.bin = cmd.split()[0]
self.remote_cmd = remote_cmd
self.server_pid = 0
self.perf_record_popen = None
self.perf_stat_popen = None
if measure_cmd:
self.cmd = f'{measure_cmd} {cmd}'
......@@ -70,37 +65,6 @@ class Server(subprocess.Popen):
env=server_env,
text=True) # type: ignore
if perf_record:
perf_record_out = bench_dir / perf.PERF_RECORD_OUTPUT.format(
run=run)
perf_record_cmd = perf.PERF_RECORD_CMD.format(
pid=self.get_server_pid(), output=perf_record_out)
if remote_cmd:
perf_record_cmd = f'{remote_cmd} {perf_record_cmd}'
log.debug('start perf record process using: %s', perf_record_cmd)
self.perf_record_popen = subprocess.Popen(perf_record_cmd.split())
if perf_counters is not None:
if len(perf_counters) == 0:
perf_counters = perf.DDD_EVENTS
else:
perf_counters = ','.join(perf_counters)
perf_stat_out = bench_dir / perf.PERF_STAT_OUTPUT.format(run=run)
perf_stat_cmd = perf.PERF_STAT_CMD.format(
pid=self.get_server_pid(),
events=perf_counters,
output=perf_stat_out)
if remote_cmd:
perf_stat_cmd = f'{remote_cmd} {perf_stat_cmd}'
log.debug('start perf stat process using: %s', perf_stat_cmd)
self.perf_stat_popen = subprocess.Popen(perf_stat_cmd.split())
def get_server_pid(self) -> int:
"""Retrieve the pid of the server"""
if self.server_pid:
......@@ -177,9 +141,3 @@ class Server(subprocess.Popen):
self.fout.close()
self.ferr.close()
if self.perf_record_popen:
self.perf_record_popen.wait()
if self.perf_stat_popen:
self.perf_stat_popen.wait()
......@@ -19,6 +19,7 @@ from bench.globalvars import HOSTNAME, ROOT_DIR, TERMINATION_TIME
from bench.server import Server
from bench.server_cmds import SERVER_CMDS
from bench.util import cmd_run
import bench.perf as perf
ARTIFACT_DESC = subprocess.check_output(
'git describe --dirty --always'.split(), cwd=ROOT_DIR, text=True)[:-1]
......@@ -139,15 +140,32 @@ def bench(server_cmds) -> EvalResult:
env=SERVER_ENV,
measure_cmd=measure_cmd,
remote_cmd=remote_cmd,
host=HOST,
perf_record=args.perf_record,
perf_counters=args.perf_stat)
host=HOST)
sleep(STARTUP_TIME)
if server.poll() is not None:
log.error('server cmd returned early')
continue
print(args)
perf_popens = []
if args.perf_record:
perf_popens.append(
perf.record(server.get_server_pid(),
run,
bench_dir,
remote_cmd=remote_cmd,
root=args.root_perf))
if args.perf_stat is not None:
perf_popens.append(
perf.record_stats(server.get_server_pid(),
args.perf_stat,
run,
bench_dir,
remote_cmd=remote_cmd,
root=args.root_perf))
for i, (cons, size) in enumerate(ARGS):
# clear line to the right and reset cursor to the first column
print(f'{i + 1}. (c {cons} s {size}) of {len(ARGS)}\u001b[K\r',
......@@ -198,6 +216,11 @@ def bench(server_cmds) -> EvalResult:
sleep(CLIENT_SEPARATION_TIME)
server.shutdown()
# await possible perf commands
for popen in perf_popens:
popen.wait()
return results
......@@ -259,6 +282,9 @@ if __name__ == '__main__':
parser.add_argument('--perf-record',
help='use perf to record the servers profile',
action='store_true')
parser.add_argument('--root-perf',
help='run perf with root privileges',
action='store_true')
parser.add_argument('implementations',
help='server implementations to benchmark',
nargs='*')
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment