Skip to content

Commit eaa6368

Browse files
Added Top entries in text form; added Output graph image in PNG format (#124)
* perf:record artifacts: added Top entries in text form; added Output graph image in PNG format * Bumping version from 0.2.0 to 0.2.1
1 parent 9998272 commit eaa6368

File tree

4 files changed

+123
-8
lines changed

4 files changed

+123
-8
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "redisbench-admin"
3-
version = "0.2.0"
3+
version = "0.2.1"
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/profilers/perf.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@
1010
import subprocess
1111
import time
1212

13+
from redisbench_admin.profilers.pprof import (
14+
PPROF_FORMAT_TEXT,
15+
run_pprof,
16+
PPROF_FORMAT_PNG,
17+
)
1318
from redisbench_admin.profilers.profilers import STACKCOLLAPSE_PATH, FLAMEGRAPH_PATH
19+
from redisbench_admin.utils.utils import whereis
1420

1521

1622
class Perf:
@@ -50,6 +56,8 @@ def __init__(self):
5056
self.profile_start_time = None
5157
self.profile_end_time = None
5258

59+
self.pprof_bin = whereis("pprof")
60+
5361
def retrieve_perf_version(self):
5462
try:
5563
self.version = subprocess.Popen(
@@ -114,7 +122,7 @@ def _is_alive(self, process):
114122
return True
115123
return False
116124

117-
def stop_profile(self):
125+
def stop_profile(self, **kwargs):
118126
"""
119127
@return: returns True if profiler stop, False if unsuccessful
120128
"""
@@ -233,15 +241,48 @@ def stack_collapse(self, filename=None):
233241
logging.error("Unable to open {0}".format(self.trace_file))
234242
return result
235243

236-
def generate_outputs(self, use_case, details=""):
237-
result = False
244+
def generate_outputs(self, use_case, **kwargs):
238245
outputs = {}
246+
binary = kwargs.get("binary")
247+
details = kwargs.get("details")
248+
if details is None:
249+
details = ""
250+
result = True
239251
# generate flame graph
240-
result, flame_graph_output = self.generate_flame_graph(
252+
artifact_result, flame_graph_output = self.generate_flame_graph(
241253
"Flame Graph: " + use_case, details
242254
)
243-
if result is True:
255+
if artifact_result is True:
244256
outputs["Flame Graph"] = flame_graph_output
257+
result &= artifact_result
258+
259+
if self.pprof_bin is None:
260+
logging.error(
261+
"Unable to detect pprof. Some of the capabilities will be disabled"
262+
)
263+
else:
264+
logging.info("Generating pprof text output")
265+
pprof_text_output = self.output + ".pprof.txt"
266+
artifact_result, pprof_artifact_text_output = run_pprof(
267+
self.pprof_bin,
268+
PPROF_FORMAT_TEXT,
269+
pprof_text_output,
270+
binary,
271+
self.output,
272+
)
273+
result &= artifact_result
274+
275+
if artifact_result is True:
276+
outputs["Top entries in text form"] = pprof_artifact_text_output
277+
logging.info("Generating pprof png output")
278+
pprof_png_output = self.output + ".pprof.png"
279+
artifact_result, pprof_artifact_png_output = run_pprof(
280+
self.pprof_bin, PPROF_FORMAT_PNG, pprof_png_output, binary, self.output
281+
)
282+
if artifact_result is True:
283+
outputs["Output graph image in PNG format"] = pprof_artifact_png_output
284+
result &= artifact_result
285+
245286
return result, outputs
246287

247288
def generate_flame_graph(self, title="Flame Graph", subtitle="", filename=None):
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# BSD 3-Clause License
2+
#
3+
# Copyright (c) 2021., Redis Labs Modules
4+
# All rights reserved.
5+
#
6+
7+
import logging
8+
import os
9+
import subprocess
10+
11+
PPROF_FORMAT_TEXT = "-text"
12+
PPROF_FORMAT_PS = "-ps"
13+
PPROF_FORMAT_PNG = "-png"
14+
15+
16+
def generate_pprof_cmd_args(
17+
pprof_bin,
18+
format,
19+
output,
20+
main_binary,
21+
profile,
22+
edge_fraction=0.01,
23+
node_fraction=0.01,
24+
):
25+
cmd = [
26+
pprof_bin,
27+
format,
28+
"-edgefraction",
29+
"{}".format(edge_fraction),
30+
"-nodefraction",
31+
"{}".format(node_fraction),
32+
"-output",
33+
"{}".format(output),
34+
main_binary,
35+
profile,
36+
]
37+
return cmd
38+
39+
40+
def run_pprof(
41+
pprof_bin,
42+
format,
43+
output,
44+
main_binary,
45+
profile,
46+
edge_fraction=0.01,
47+
node_fraction=0.01,
48+
):
49+
status = False
50+
result_artifact = None
51+
args = generate_pprof_cmd_args(
52+
pprof_bin, format, output, main_binary, profile, edge_fraction, node_fraction
53+
)
54+
try:
55+
logging.info("Running pprof {} with args {}".format(pprof_bin, args))
56+
pprof_process = subprocess.Popen(args=args)
57+
pprof_return_code = pprof_process.wait()
58+
if pprof_return_code <= 0:
59+
status = True
60+
result_artifact = os.path.abspath(output)
61+
except OSError as e:
62+
logging.error(
63+
"Unable to run {} format {}. Error {}".format(
64+
pprof_bin, format, e.__str__()
65+
)
66+
)
67+
return status, result_artifact

redisbench_admin/run_local/run_local.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,18 @@ def run_local_command_logic(args):
222222
)
223223
profiler_obj.stop_profile()
224224

225-
# Generate Flame Graph SVG.
225+
# Generate:
226+
# - artifact with Flame Graph SVG
227+
# - artifact with output graph image in PNG format
228+
# - artifact with top entries in text form
226229
(
227230
profile_res,
228231
profile_res_artifacts_map,
229-
) = profiler_obj.generate_outputs(test_name, collection_summary_str)
232+
) = profiler_obj.generate_outputs(
233+
test_name,
234+
details=collection_summary_str,
235+
binary=local_module_file,
236+
)
230237
if profile_res is True:
231238
logging.info(
232239
"Profiler {} for pid {} ran successfully and generated {} artifacts.".format(

0 commit comments

Comments
 (0)