Skip to content

Commit f23b88d

Browse files
[add] Added redis-benchmark automation for local/remote runs (#53)
1 parent 01ea6c5 commit f23b88d

File tree

12 files changed

+277
-253
lines changed

12 files changed

+277
-253
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*.json
44
*.tar.gz
55
*.csv
6-
6+
*.txt
77

88
# Byte-compiled / optimized / DLL files
99
__pycache__/

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "redisbench-admin"
3-
version = "0.1.49"
3+
version = "0.1.50"
44
description = "Redis benchmark run helper. A wrapper around Redis and Redis Modules benchmark tools ( ftsb_redisearch, memtier_benchmark, redis-benchmark, aibench, etc... )."
55
authors = ["filipecosta90 <[email protected]>"]
66
readme = "README.md"

redisbench_admin/run/common.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import logging
2+
import re
3+
4+
from redisbench_admin.run.redis_benchmark.redis_benchmark import prepareRedisBenchmarkCommand
5+
from redisbench_admin.run.redisgraph_benchmark_go.redisgraph_benchmark_go import prepareRedisGraphBenchmarkGoCommand
6+
from redisbench_admin.utils.remote import executeRemoteCommands, getFileFromRemoteSetup
7+
8+
9+
def extract_benchmark_tool_settings(benchmark_config):
10+
benchmark_tool = None
11+
benchmark_min_tool_version = None
12+
benchmark_min_tool_version_major = None
13+
benchmark_min_tool_version_minor = None
14+
benchmark_min_tool_version_patch = None
15+
16+
for entry in benchmark_config["clientconfig"]:
17+
if 'tool' in entry:
18+
benchmark_tool = entry['tool']
19+
if 'min-tool-version' in entry:
20+
benchmark_min_tool_version = entry['min-tool-version']
21+
p = re.compile("(\d+)\.(\d+)\.(\d+)")
22+
m = p.match(benchmark_min_tool_version)
23+
if m is None:
24+
logging.error(
25+
"Unable to extract semversion from 'min-tool-version'. Will not enforce version")
26+
benchmark_min_tool_version = None
27+
else:
28+
benchmark_min_tool_version_major = m.group(1)
29+
benchmark_min_tool_version_minor = m.group(2)
30+
benchmark_min_tool_version_patch = m.group(3)
31+
return benchmark_min_tool_version, benchmark_min_tool_version_major, benchmark_min_tool_version_minor, benchmark_min_tool_version_patch, benchmark_tool
32+
33+
34+
def prepare_benchmark_parameters(benchmark_config, benchmark_tool, server_plaintext_port, server_private_ip,
35+
remote_results_file, isremote=False):
36+
for entry in benchmark_config["clientconfig"]:
37+
if 'parameters' in entry:
38+
if benchmark_tool == 'redis-benchmark':
39+
command_arr, command_str = prepareRedisBenchmarkCommand(
40+
"redis-benchmark",
41+
server_private_ip,
42+
server_plaintext_port,
43+
entry
44+
)
45+
redirect_file = ">{}".format(remote_results_file)
46+
command_arr.append(redirect_file)
47+
command_str = command_str + " " + redirect_file
48+
49+
if benchmark_tool == 'redisgraph-benchmark-go':
50+
command_arr = prepareRedisGraphBenchmarkGoCommand(
51+
"/tmp/redisgraph-benchmark-go",
52+
server_private_ip,
53+
server_plaintext_port,
54+
entry,
55+
remote_results_file,
56+
)
57+
command_str = " ".join(command_arr)
58+
return command_arr, command_str
59+
60+
61+
def runRemoteBenchmark(
62+
client_public_ip,
63+
username,
64+
private_key,
65+
remote_results_file,
66+
local_results_file,
67+
command
68+
):
69+
remote_run_result = False
70+
res = executeRemoteCommands(client_public_ip, username, private_key, [command])
71+
recv_exit_status, stdout, stderr = res[0]
72+
73+
if recv_exit_status != 0:
74+
logging.error("Exit status of remote command execution {}. Printing stdout and stderr".format(recv_exit_status))
75+
logging.error("remote process stdout: ".format(stdout))
76+
logging.error("remote process stderr: ".format(stderr))
77+
else:
78+
logging.info("Remote process exited normally. Exit code {}. Printing stdout.".format(recv_exit_status))
79+
logging.info("remote process stdout: ".format(stdout))
80+
logging.info("Extracting the benchmark results")
81+
remote_run_result = True
82+
getFileFromRemoteSetup(
83+
client_public_ip,
84+
username,
85+
private_key,
86+
local_results_file,
87+
remote_results_file,
88+
)
89+
return remote_run_result

redisbench_admin/run/redis_benchmark/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
import csv
22
import logging
3+
import re
34
import shlex
5+
import subprocess
46

7+
from redisbench_admin.utils.remote import executeRemoteCommands
58

6-
def redis_benchmark_from_stdout_csv_to_json(stdout, start_time, start_time_str):
9+
10+
def redis_benchmark_from_stdout_csv_to_json(csv_data, start_time, start_time_str, overloadTestName=None):
711
results_dict = {"Tests": {}, "StartTime": int(start_time.strftime("%s")),
812
"StartTimeHuman": start_time_str}
9-
csv_data = list(csv.reader(stdout.decode('ascii').splitlines(), delimiter=","))
13+
csv_data = list(csv.reader(csv_data.splitlines(), delimiter=","))
1014
header = csv_data[0]
1115
for row in csv_data[1:]:
1216
test_name = row[0]
17+
if overloadTestName is not None:
18+
test_name = overloadTestName
1319
results_dict["Tests"][test_name] = {}
1420
for pos, value in enumerate(row[1:]):
1521
results_dict["Tests"][test_name][header[pos + 1]] = value
@@ -21,38 +27,89 @@ def prepareRedisBenchmarkCommand(
2127
server_private_ip: object,
2228
server_plaintext_port: object,
2329
benchmark_config: object,
24-
) -> str:
30+
):
2531
"""
2632
Prepares redis-benchmark command parameters
2733
:param server_private_ip:
2834
:param server_plaintext_port:
2935
:param benchmark_config:
30-
:return: string containing the required command to run the benchmark given the configurations
36+
:return: [string] containing the required command to run the benchmark given the configurations
3137
"""
32-
queries_str = [executable_path]
33-
queries_str.extend(["-h", "{}".format(server_private_ip)])
34-
queries_str.extend(["-p", "{}".format(server_plaintext_port)])
38+
command_str = ""
39+
command_arr = [executable_path]
40+
command_arr.extend(["-h", "{}".format(server_private_ip)])
41+
command_arr.extend(["-p", "{}".format(server_plaintext_port)])
3542

3643
# we need the csv output
37-
queries_str.extend(["--csv", "-e"])
44+
command_arr.extend(["--csv", "-e"])
3845
last_append = None
3946
for k in benchmark_config["parameters"]:
4047
if "clients" in k:
41-
queries_str.extend(["-c", "{}".format(k["clients"])])
48+
command_arr.extend(["-c", "{}".format(k["clients"])])
4249
if "requests" in k:
43-
queries_str.extend(["-n", "{}".format(k["requests"])])
50+
command_arr.extend(["-n", "{}".format(k["requests"])])
4451
if "threads" in k:
45-
queries_str.extend(["--threads", "{}".format(k["threads"])])
52+
command_arr.extend(["--threads", "{}".format(k["threads"])])
4653
if "pipeline" in k:
47-
queries_str.extend(["-P", "{}".format(k["pipeline"])])
54+
command_arr.extend(["-P", "{}".format(k["pipeline"])])
4855
# if we have the command keywork then it needs to be at the end of args
4956
if "command" in k:
57+
last_str = k["command"]
5058
last_append = shlex.split(k["command"])
59+
command_str = " ".join(command_arr)
5160
if last_append is not None:
52-
queries_str.extend(last_append)
61+
command_arr.extend(last_append)
62+
command_str = command_str + " " + last_str
5363
logging.info(
54-
"Running the benchmark with the following parameters: {}".format(
55-
" ".join(queries_str)
64+
"Running the benchmark with the following parameters:\n\tArgs array: {}\n\tArgs str: {}".format(
65+
command_arr, command_str
5666
)
5767
)
58-
return queries_str
68+
return command_arr, command_str
69+
70+
71+
def ensure_redis_benchmark_version_from_input(benchmark_min_tool_version, benchmark_min_tool_version_major,
72+
benchmark_min_tool_version_minor, benchmark_min_tool_version_patch,
73+
benchmark_tool, stdout):
74+
version_output = stdout.decode('ascii').split("\n")[0]
75+
logging.info(
76+
"Detected benchmark config tool {} with version {}".format(benchmark_tool, version_output))
77+
p = re.compile("redis-benchmark (\d+)\.(\d+)\.(\d+) ")
78+
m = p.match(version_output)
79+
if m is None:
80+
raise Exception(
81+
"Unable to detect benchmark tool version, and the benchmark requires a min version: {}".format(
82+
benchmark_min_tool_version))
83+
major = m.group(1)
84+
minor = m.group(2)
85+
patch = m.group(3)
86+
if major < benchmark_min_tool_version_major or (
87+
major == benchmark_min_tool_version_major and minor < benchmark_min_tool_version_minor) or (
88+
major == benchmark_min_tool_version_major and minor == benchmark_min_tool_version_minor and patch < benchmark_min_tool_version_patch):
89+
raise Exception(
90+
"Detected benchmark version that is inferior than the minimum required. {} < {}".format(
91+
version_output, benchmark_min_tool_version))
92+
93+
94+
def redis_benchmark_ensure_min_version_local(benchmark_tool, benchmark_min_tool_version,
95+
benchmark_min_tool_version_major,
96+
benchmark_min_tool_version_minor, benchmark_min_tool_version_patch):
97+
benchmark_client_process = subprocess.Popen(args=[benchmark_tool, "--version"],
98+
stdout=subprocess.PIPE,
99+
stderr=subprocess.STDOUT)
100+
(stdout, sterr) = benchmark_client_process.communicate()
101+
ensure_redis_benchmark_version_from_input(benchmark_min_tool_version, benchmark_min_tool_version_major,
102+
benchmark_min_tool_version_minor, benchmark_min_tool_version_patch,
103+
benchmark_tool, stdout)
104+
105+
106+
def redis_benchmark_ensure_min_version_remote(benchmark_tool, benchmark_min_tool_version,
107+
benchmark_min_tool_version_major,
108+
benchmark_min_tool_version_minor, benchmark_min_tool_version_patch):
109+
benchmark_client_process = subprocess.Popen(args=[benchmark_tool, "--version"],
110+
stdout=subprocess.PIPE,
111+
stderr=subprocess.STDOUT)
112+
(stdout, sterr) = benchmark_client_process.communicate()
113+
ensure_redis_benchmark_version_from_input(benchmark_min_tool_version, benchmark_min_tool_version_major,
114+
benchmark_min_tool_version_minor, benchmark_min_tool_version_patch,
115+
benchmark_tool, stdout)

redisbench_admin/run/redisgraph_benchmark_go/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import logging
2+
3+
4+
def prepareRedisGraphBenchmarkGoCommand(
5+
executable_path: str,
6+
server_private_ip: object,
7+
server_plaintext_port: object,
8+
benchmark_config: object,
9+
results_file: object,
10+
):
11+
"""
12+
Prepares redisgraph-benchmark-go command parameters
13+
:param server_private_ip:
14+
:param server_plaintext_port:
15+
:param benchmark_config:
16+
:param results_file:
17+
:return: string containing the required command to run the benchmark given the configurations
18+
"""
19+
queries_str = [executable_path]
20+
for k in benchmark_config["parameters"]:
21+
if "graph" in k:
22+
queries_str.extend(["-graph-key", "'{}'".format(k["graph"])])
23+
if "clients" in k:
24+
queries_str.extend(["-c", "{}".format(k["clients"])])
25+
if "requests" in k:
26+
queries_str.extend(["-n", "{}".format(k["requests"])])
27+
if "rps" in k:
28+
queries_str.extend(["-rps", "{}".format(k["rps"])])
29+
if "queries" in k:
30+
for kk in k["queries"]:
31+
query = kk["q"]
32+
queries_str.extend(["-query", "'{}'".format(query)])
33+
if "ratio" in kk:
34+
queries_str.extend(["-query-ratio", "{}".format(kk["ratio"])])
35+
queries_str.extend(["-h", "{}".format(server_private_ip)])
36+
queries_str.extend(["-p", "{}".format(server_plaintext_port)])
37+
queries_str.extend(["-json-out-file", "{}".format(results_file)])
38+
logging.info(
39+
"Running the benchmark with the following parameters: {}".format(
40+
" ".join(queries_str)
41+
)
42+
)
43+
return queries_str

redisbench_admin/run/run.py

-30
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import logging
2-
import re
3-
import subprocess
4-
51
from cpuinfo import cpuinfo
62

73

@@ -21,29 +17,3 @@ def run_command_logic(args):
2117
benchmark_machine_1 = {"machine_info": benchmark_machine_info}
2218
benchmark_infra["benchmark-machines"]["benchmark-machine-1"] = benchmark_machine_1
2319
benchmark_infra["total-benchmark-machines"] += 1
24-
25-
26-
def redis_benchmark_ensure_min_version(benchmark_tool, benchmark_min_tool_version, benchmark_min_tool_version_major,
27-
benchmark_min_tool_version_minor, benchmark_min_tool_version_patch):
28-
benchmark_client_process = subprocess.Popen(args=[benchmark_tool, "--version"],
29-
stdout=subprocess.PIPE,
30-
stderr=subprocess.STDOUT)
31-
(stdout, sterr) = benchmark_client_process.communicate()
32-
version_output = stdout.decode('ascii').split("\n")[0]
33-
logging.info(
34-
"Detected benchmark config tool {} with version {}".format(benchmark_tool, version_output))
35-
p = re.compile("redis-benchmark (\d+)\.(\d+)\.(\d+) ")
36-
m = p.match(version_output)
37-
if m is None:
38-
raise Exception(
39-
"Unable to detect benchmark tool version, and the benchmark requires a min version: {}".format(
40-
benchmark_min_tool_version))
41-
major = m.group(1)
42-
minor = m.group(2)
43-
patch = m.group(3)
44-
if major < benchmark_min_tool_version_major or (
45-
major == benchmark_min_tool_version_major and minor < benchmark_min_tool_version_minor) or (
46-
major == benchmark_min_tool_version_major and minor == benchmark_min_tool_version_minor and patch < benchmark_min_tool_version_patch):
47-
raise Exception(
48-
"Detected benchmark version that is inferior than the minimum required. {} < {}".format(
49-
version_output, benchmark_min_tool_version))

0 commit comments

Comments
 (0)