Skip to content

Commit 1e289fc

Browse files
authored
adding hotspots and cleaning up requirements.txt (#60)
* add hotspot * eof * install git * move pip
1 parent 1daa9b0 commit 1e289fc

File tree

5 files changed

+205
-107
lines changed

5 files changed

+205
-107
lines changed

.github/workflows/build.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,32 @@ jobs:
2323
with:
2424
name: perfspect
2525
path: dist/perfspect*.tgz
26+
27+
build-hotspot:
28+
runs-on: ubuntu-20.04
29+
container:
30+
image: centos:7
31+
steps:
32+
- uses: actions/checkout@v3
33+
- name: install dependencies
34+
run: |
35+
yum update -y
36+
yum install -y make python3 gcc cmake gcc-c++ java-1.8.0-openjdk-devel.x86_64 git
37+
python3 -m pip install --upgrade pip
38+
curl -LJO https://raw.githubusercontent.com/brendangregg/FlameGraph/master/flamegraph.pl
39+
curl -LJO https://raw.githubusercontent.com/brendangregg/FlameGraph/master/difffolded.pl
40+
curl -LJO https://raw.githubusercontent.com/brendangregg/FlameGraph/master/stackcollapse-perf.pl
41+
chmod +x *.pl
42+
git clone https://github.com/jvm-profiling-tools/perf-map-agent.git
43+
cd perf-map-agent
44+
cmake .
45+
make
46+
- name: build
47+
run: |
48+
pip3 install -r requirements.txt
49+
pyinstaller -F hotspot.py -n hotspot --bootloader-ignore-signals --add-data "perf-map-agent/out/*:." --add-data "flamegraph.pl:." --add-data "difffolded.pl:." --add-data "stackcollapse-perf.pl:." --runtime-tmpdir . --exclude-module readline
50+
- name: upload artifact
51+
uses: actions/upload-artifact@v3
52+
with:
53+
name: hotspot
54+
path: dist/hotspot

_version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.3.8
1+
1.3.9

hotspot.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env python3
2+
3+
###########################################################################################################
4+
# Copyright (C) 2021-2023 Intel Corporation
5+
# SPDX-License-Identifier: BSD-3-Clause
6+
###########################################################################################################
7+
8+
import logging
9+
import os
10+
import platform
11+
import shlex
12+
import shutil
13+
import subprocess
14+
import sys
15+
16+
from argparse import ArgumentParser
17+
from src.common import configure_logging, crash
18+
from src.perf_helpers import get_perf_list
19+
20+
21+
def fix_path(script):
22+
return os.path.join(
23+
getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__))),
24+
script,
25+
)
26+
27+
28+
def attach_perf_map_agent():
29+
# look for java processes
30+
try:
31+
pids = (
32+
subprocess.check_output(shlex.split("pgrep java"), encoding="UTF-8")
33+
.strip()
34+
.split("\n")
35+
)
36+
except subprocess.CalledProcessError:
37+
return
38+
39+
if len(pids) > 0 and pids[0] != "":
40+
logging.info("detected java processes: " + str(pids))
41+
42+
# setup tmp folder for storing perf-map-agent
43+
if not os.path.exists("/tmp/perfspect"):
44+
os.mkdir("/tmp/perfspect")
45+
shutil.copy(fix_path("attach-main.jar"), "/tmp/perfspect")
46+
shutil.copy(fix_path("libperfmap.so"), "/tmp/perfspect")
47+
os.chmod("/tmp/perfspect/attach-main.jar", 0o666)
48+
os.chmod("/tmp/perfspect/libperfmap.so", 0o666)
49+
50+
for pid in pids:
51+
uid = subprocess.check_output(
52+
shlex.split("awk '/^Uid:/{print $2}' /proc/" + pid + "/status"),
53+
encoding="UTF-8",
54+
)
55+
gid = subprocess.check_output(
56+
shlex.split("awk '/^Gid:/{print $2}' /proc/" + pid + "/status"),
57+
encoding="UTF-8",
58+
)
59+
JAVA_HOME = subprocess.check_output(
60+
shlex.split('sed "s:bin/java::"'),
61+
input=subprocess.check_output(
62+
shlex.split("readlink -f /usr/bin/java"), encoding="UTF-8"
63+
),
64+
encoding="UTF-8",
65+
).strip()
66+
current_dir = os.getcwd()
67+
try:
68+
os.chdir("/tmp/perfspect/")
69+
subprocess.check_call(
70+
shlex.split(
71+
f"sudo -u \\#{uid} -g \\#{gid} {JAVA_HOME}bin/java -cp /tmp/perfspect/attach-main.jar:{JAVA_HOME}lib/tools.jar net.virtualvoid.perf.AttachOnce {pid}"
72+
),
73+
encoding="UTF-8", # type: ignore
74+
)
75+
logging.info("Successfully attached perf-map-agent to: " + pid)
76+
except subprocess.CalledProcessError:
77+
logging.info("Failed to attach perf-map-agent to: " + pid)
78+
os.chdir(current_dir)
79+
80+
81+
if __name__ == "__main__":
82+
configure_logging(".")
83+
84+
parser = ArgumentParser(
85+
description="hotspot: PMU based flamegraphs for hotspot analysis"
86+
)
87+
parser.add_argument(
88+
"-t",
89+
"--timeout",
90+
required=True,
91+
type=int,
92+
help="collection time",
93+
)
94+
args = parser.parse_args()
95+
if os.geteuid() != 0:
96+
crash("Must run as root, please re-run")
97+
if platform.system() != "Linux":
98+
crash("PerfSpect currently supports Linux only")
99+
get_perf_list()
100+
101+
events = ["instructions", "cycles", "branch-misses", "cache-misses"]
102+
103+
logging.info("collecting...")
104+
105+
attach_perf_map_agent()
106+
107+
subprocess.run(
108+
shlex.split(
109+
"sudo perf record -a -g -F 99 -e "
110+
+ ",".join(events)
111+
+ " sleep "
112+
+ str(args.timeout)
113+
)
114+
)
115+
116+
logging.info("postprocessing...")
117+
118+
script = subprocess.run(
119+
shlex.split("perf script"),
120+
stdout=subprocess.PIPE,
121+
)
122+
cycles_collapse = ""
123+
with open("cycles.col", "w") as c:
124+
cycles_collapse = subprocess.run(
125+
shlex.split(fix_path("stackcollapse-perf.pl") + ' --event-filter="cycles"'),
126+
input=script.stdout,
127+
stdout=c,
128+
)
129+
for event, subtitle, differential in [
130+
["branch-misses", "What is being stalled by poor prefetching", False],
131+
["cache-misses", "What is being stalled by poor caching", False],
132+
["instructions", "CPI: blue = vectorized, red = stalled", True],
133+
]:
134+
with open(event + ".svg", "w") as f:
135+
collapse = ""
136+
with open(event + ".col", "w") as e:
137+
collapse = subprocess.run(
138+
shlex.split(
139+
fix_path("stackcollapse-perf.pl")
140+
+ ' --event-filter="'
141+
+ event
142+
+ '"'
143+
),
144+
input=script.stdout,
145+
stdout=e,
146+
)
147+
if differential:
148+
with open("diff.col", "w") as e:
149+
collapse = subprocess.run(
150+
shlex.split(
151+
fix_path("difffolded.pl") + " " + event + ".col cycles.col"
152+
),
153+
stdout=e,
154+
)
155+
with open("diff.col" if differential else event + ".col", "r") as e:
156+
flamegraph = subprocess.run(
157+
shlex.split(
158+
fix_path("flamegraph.pl")
159+
+ ' --title="'
160+
+ event
161+
+ '" --subtitle="'
162+
+ subtitle
163+
+ '"'
164+
),
165+
stdin=e,
166+
stdout=f,
167+
)
168+
os.remove(event + ".col")
169+
if differential:
170+
os.remove("diff.col")
171+
os.chmod(event + ".svg", 0o666)
172+
logging.info("generated " + event + ".svg")
173+
174+
os.remove("cycles.col")

instruction-mix.py

Lines changed: 0 additions & 99 deletions
This file was deleted.

requirements.txt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
black
22
flake8
3-
iced-x86
43
pytype
54
simpleeval
65
pandas
7-
plotly
8-
psutil
96
pyinstaller
10-
pytest
11-
python-dateutil
12-
XlsxWriter
13-
yattag
7+
pytest

0 commit comments

Comments
 (0)