Skip to content

Commit d54d178

Browse files
Merge pull request #19 from ashrafMahgoub/master
Fix -pid bug + Update README
2 parents 31c0b0e + 5b941a8 commit d54d178

File tree

7 files changed

+82
-84
lines changed

7 files changed

+82
-84
lines changed

README.md

+35-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
[![Build](https://github.com/intel/PerfSpect/actions/workflows/build.yml/badge.svg)](https://github.com/intel/PerfSpect/actions/workflows/build.yml)
2-
[![License](https://img.shields.io/badge/License-BSD--3-blue)](https://github.com/intel/PerfSpect/blob/master/LICENSE)
1+
# PerfSpect · [![Build](https://github.com/intel/PerfSpect/actions/workflows/build.yml/badge.svg)](https://github.com/intel/PerfSpect/actions/workflows/build.yml)[![License](https://img.shields.io/badge/License-BSD--3-blue)](https://github.com/intel/PerfSpect/blob/master/LICENSE)
32

4-
# PerfSpect
3+
[Quick Start](#quick-start-requires-perf-installed) | [Requirements](#requirements) | [Build from source](#build-from-source) | [Collection](#collection) | [Post-processing](#post-processing) | [Caveats](#caveats) | [How to contribute](#how-to-contribute)
54

65
PerfSpect is a system performance characterization tool based on linux perf targeting Intel microarchitectures.
76
The tool has two parts
87

98
1. perf collection to collect underlying PMU (Performance Monitoring Unit) counters
109
2. post processing that generates csv output of performance metrics.
11-
### Quick start (requires perf installed)
10+
11+
## Quick start (requires perf installed)
1212
```
1313
wget -qO- https://github.com/intel/PerfSpect/releases/latest/download/perfspect.tgz | tar xvz
1414
cd perfspect
@@ -19,7 +19,31 @@ sudo ./perf-postprocess -r results/perfstat.csv --html perfstat.html
1919
![PerfSpect BS](images/basic_stats.JPG "perfspect-bs")
2020
![perfspect-demo1](https://user-images.githubusercontent.com/5321018/205159259-3654fa12-74d6-4cb5-8194-ea1b66aadb25.gif)
2121

22-
## Building binaries from source code
22+
## Requirements
23+
### Packages:
24+
- **perf** - PerfSpect uses the Linux perf tool to collect PMU counters
25+
- **lscgroup** - Perfspect needs lscgroup from the cgroup-tools (libcgroup on RHEL/CentOS) package when collecting data for containers
26+
27+
### Supported kernels
28+
29+
| Xeon Generation | Minimum Kernel |
30+
| - | - |
31+
| Broadwell | kernel 4.15 |
32+
| Skylake | kernel 4.15 |
33+
| Cascadelake | kernel 4.15 |
34+
| Icelake | kernel 5.9 |
35+
| Sapphire Rapids | kernel 5.12 |
36+
37+
### Supported Operating Systems:
38+
- Ubuntu 16.04 and newer
39+
- centos 7 and newer
40+
- Amazon Linux 2
41+
- RHEL 9
42+
- Debian 11
43+
44+
*Note: PerfSpect may work on other Linux distributions, but has not been thoroughly tested*
45+
46+
## Build from source
2347

2448
Requires recent python and golang.
2549

@@ -30,7 +54,7 @@ make
3054

3155
On successful build, binaries will be created in "dist" folder
3256

33-
### 1. Perf collection:
57+
## Collection:
3458

3559
```
3660
(sudo) ./perf-collect (options) -- Some options can be used only with root privileges
@@ -68,7 +92,7 @@ Options:
6892
Instance type: Options include - VM,BM
6993
```
7094

71-
#### Examples
95+
### Examples
7296

7397
1. sudo ./perf-collect (collect PMU counters using predefined architecture specific event file until collection is terminated)
7498
2. sudo ./perf-collect -m 10 -t 30 (sets event multiplexing interval to 10ms and collects PMU counters for 30 seconds using default architecture specific event file)
@@ -77,12 +101,12 @@ Options:
77101
5. sudo ./perf-collect --metadata (collect system info and PMU event info without running perf, uses default outputfile if -o option is not used)
78102
6. sudo ./perf-collect --cid "one or more container IDs from docker or kubernetes seperated by semicolon"
79103

80-
#### Notes
104+
### Notes
81105

82106
1. Intel CPUs (until Cascadelake) have 3 fixed PMUs (cpu-cycles, ref-cycles, instructions) and 4 programmable PMUs. The events are grouped in event files with this assumption. However, some of the counters may not be available on some CPUs. You can check the correctness of the event file with dryrun and check the output for anamolies. Typically output will have "not counted", "unsuppported" or zero values for cpu-cycles if number of available counters are less than events in a group.
83107
2. Globally pinned events can limit the number of counters available for perf event groups. On X86 systems NMI watchdog pins a fixed counter by default. NMI watchdog is disabled during perf collection if run as a sudo user. If NMI watchdog can't be disabled, event grouping will be forcefully disabled to let perf driver handle event multiplexing.
84108

85-
### 2. Perf Post Processing:
109+
## Post-processing:
86110

87111
```
88112
./perf-postprocess (options)
@@ -111,13 +135,13 @@ required arguments:
111135
Raw CSV output from perf-collect
112136
```
113137

114-
#### Examples
138+
### Examples
115139

116140
./perf-postprocess -r results/perfstat.csv (post processes perfstat.csv and creates metric_out.csv, metric_out.average.csv, metric_out.raw.csv)
117141

118142
./perf-postprocess -r results/perfstat.csv --html perfstat.html (creates a report for TMA analysis and system level metric charts.)
119143

120-
#### Notes
144+
### Notes
121145

122146
1. metric_out.csv : Time series dump of the metrics. The metrics are defined in events/metric.json
123147
2. metric_out.averags.csv: Average of metrics over the collection period

perf-collect.py

+25-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from __future__ import print_function
99
import os
10+
import platform
1011
import sys
1112
import subprocess # nosec
1213
import shlex # nosec
@@ -16,6 +17,14 @@
1617

1718
from subprocess import PIPE, run # nosec
1819

20+
SUPPORTED_ARCHITECTURES = [
21+
"Broadwell",
22+
"Skylake",
23+
"Cascadelake",
24+
"Icelake",
25+
"SapphireRapids",
26+
]
27+
1928

2029
# meta data gathering
2130
def write_metadata(
@@ -46,10 +55,7 @@ def write_metadata(
4655
modified.write("TSC Frequency(MHz)," + tsc_freq + ",\n")
4756
modified.write("CPU count," + str(perf_helpers.get_cpu_count()) + ",\n")
4857
modified.write("SOCKET count," + str(perf_helpers.get_socket_count()) + ",\n")
49-
if args.pid or args.cid:
50-
modified.write("HT count," + str(1) + ",\n")
51-
else:
52-
modified.write("HT count," + str(perf_helpers.get_ht_count()) + ",\n")
58+
modified.write("HT count," + str(perf_helpers.get_ht_count()) + ",\n")
5359
imc, cha, upi = perf_helpers.get_imc_cacheagent_count()
5460
modified.write("IMC count," + str(imc) + ",\n")
5561
modified.write("CHA count," + str(cha) + ",\n")
@@ -134,6 +140,9 @@ def is_safe_file(fname, substr):
134140

135141

136142
if __name__ == "__main__":
143+
if platform.system() != "Linux":
144+
raise SystemExit("PerfSpect currently supports Linux only")
145+
137146
script_path = os.path.dirname(os.path.realpath(__file__))
138147
# fix the pyinstaller path
139148
if "_MEI" in script_path:
@@ -257,17 +266,19 @@ def is_safe_file(fname, substr):
257266
raise SystemExit(
258267
"Input argument dump interval is too large or too small, range is [0.1 to 300s]!"
259268
)
269+
if args.cloud and args.cloud not in ("AWS", "aws", "OCI", "oci", "oracle"):
270+
parser.print_help()
271+
raise SystemExit("Invalid csp/cloud")
260272

261273
# select architecture default event file if not supplied
262274
procinfo = perf_helpers.get_cpuinfo()
263-
arch, cpuname = perf_helpers.check_architecture(procinfo)
275+
arch, cpuname = perf_helpers.get_arch_and_name(procinfo)
276+
if not arch:
277+
raise SystemExit(
278+
f"Unrecognized CPU architecture. Supported architectures: {', '.join(SUPPORTED_ARCHITECTURES)}"
279+
)
264280
eventfile = args.eventfile
265281
eventfilename = eventfile
266-
perf_helpers.check_os()
267-
if args.cloud and args.cloud not in ("AWS", "aws", "OCI", "oci", "oracle"):
268-
parser.print_help()
269-
raise SystemExit("Invalid csp/cloud")
270-
271282
if not eventfile:
272283
is_vm = args.cloudtype in ("VM", "vm")
273284
is_aws_vm = args.cloud in ("aws", "AWS", "amazon") and is_vm
@@ -295,10 +306,9 @@ def is_safe_file(fname, substr):
295306
eventfile = "spr.txt"
296307
if is_aws_vm:
297308
eventfile = "spr_aws.txt"
298-
else:
299-
raise SystemExit(
300-
"Unsupported architecture (currently supports IA -> Broadwell, Skylake, CascadeLake Icelake and SapphireRapids)"
301-
)
309+
310+
if not eventfile:
311+
raise SystemExit(f"Event file for arch ({arch}) not found.")
302312

303313
# Convert path of event file to relative path if being packaged by pyInstaller into a binary
304314
if getattr(sys, "frozen", False):
@@ -312,7 +322,7 @@ def is_safe_file(fname, substr):
312322
eventfile = script_path + "/events/" + eventfile
313323
eventfilename = eventfile
314324
else:
315-
raise SystemExit("Unknow application type")
325+
raise SystemExit("Unknown application type")
316326

317327
if not os.path.isfile(eventfile):
318328
parser.print_usage()

pmu-checker/go.mod

+6
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,11 @@ require (
66
github.com/pkg/errors v0.9.1
77
github.com/sirupsen/logrus v1.9.0
88
github.com/stretchr/testify v1.8.2
9+
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/pmezard/go-difflib v1.0.0 // indirect
914
golang.org/x/sys v0.5.0 // indirect
15+
gopkg.in/yaml.v3 v3.0.1 // indirect
1016
)

pmu-checker/go.sum

-9
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,21 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
55
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
66
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
77
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
8-
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
9-
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
108
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
119
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
1210
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1311
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
14-
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
1512
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
16-
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
17-
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
1813
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
1914
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2015
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
2116
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
2217
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
23-
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
24-
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2518
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
2619
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
2720
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
2821
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2922
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3023
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
31-
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
32-
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
3324
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
3425
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

release_notes

+1-16
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,6 @@
11
RELEASE NOTES
2-
PerfSpect
3-
4-
Xeon Micro-Architectures:
5-
- Broadwell (minimum kernel 4.15)
6-
- Skylake (minimum kernel 4.15)
7-
- Cascadelake (minimum kernel 4.15)
8-
- Icelake (minimum kernel 5.9)
9-
- Sapphire Rapids (minimum kernel 5.12)
102

11-
Operating Systems:
12-
- Ubuntu 16.04 and newer
13-
- centos 7 and newer
14-
- Amazon Linux 2
15-
- RHEL 9
16-
- Debian 11
17-
18-
Note: PerfSpect may work on other Linux distributions, but has not been thoroughly tested
3+
PerfSpect
194

205
* v1.2.0
216
PerfSpect supports BDX, SKX, CLX, ICX and SPR

src/perf_helpers.py

+12-30
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
###########################################################################################################
77

88
import os
9-
import sys
109
import re
1110
import fnmatch
1211
import time
@@ -210,29 +209,20 @@ def get_lscpu():
210209
return cpuinfo
211210

212211

213-
def not_suported():
214-
print(
215-
"Current architecture not supported!\nThis version only suports Broadwell/Skylake/Cascadelake/Icelake. Exiting!"
216-
)
217-
sys.exit()
218-
219-
220-
# Check if arch is broadwell/skyalke/cascadelake/icelake/sapphirerapids
221-
def check_architecture(procinfo):
212+
def get_arch_and_name(procinfo):
213+
arch = modelname = ""
222214
try:
223215
model = int(procinfo[0]["model"].strip())
224216
cpufamily = int(procinfo[0]["cpu family"].strip())
225217
stepping = int(procinfo[0]["stepping"].strip())
226218
vendor = str(procinfo[0]["vendor_id"].strip())
227219
modelname = procinfo[0]["model name"].strip()
228-
229220
except KeyError:
230221
# for non-Intel architectures
231222
cpuinfo = get_lscpu()
232223
modelname = str(cpuinfo["Model name"])
233224
stepping = str(cpuinfo["Stepping"])
234225
vendor = str(cpuinfo["Vendor ID"])
235-
236226
if vendor == "GenuineIntel":
237227
if model == 85 and cpufamily == 6 and stepping == 4:
238228
arch = "skylake"
@@ -244,11 +234,6 @@ def check_architecture(procinfo):
244234
arch = "icelake"
245235
elif model == 143 and cpufamily == 6 and stepping >= 3:
246236
arch = "sapphirerapids"
247-
else:
248-
not_suported()
249-
250-
else:
251-
not_suported()
252237
return arch, modelname
253238

254239

@@ -343,12 +328,17 @@ def get_epoch(start_time):
343328
# Requires cgroup-tools/libgroup-tools for ubuntu/centos
344329
def get_cgroups_from_cids(cids):
345330
cgroups = []
346-
p = subprocess.Popen( # nosec
347-
["lscgroup"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
348-
) # nosec
331+
try:
332+
p = subprocess.Popen( # nosec
333+
["lscgroup"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
334+
) # nosec
335+
except FileNotFoundError:
336+
raise SystemExit(
337+
"lscgroup not found; please install the lscgroup utility for container support"
338+
)
349339
out, err = p.communicate()
350340
if err:
351-
raise SystemExit("please install prerequisites(lscgroup)")
341+
raise SystemExit(f"error calling lscgroup: {err}")
352342
cgevent = "perf_event:"
353343
for cid in cids:
354344
match = [cid, cgevent]
@@ -357,7 +347,7 @@ def get_cgroups_from_cids(cids):
357347
if all(x in s.decode() for x in match):
358348
cgroups.append((s.decode().lstrip(cgevent)))
359349
if len(cgroups) == 0:
360-
raise SystemExit("invalid container ID " + cid)
350+
raise SystemExit(f"invalid container ID: {cid}")
361351
return cgroups
362352

363353

@@ -391,11 +381,3 @@ def fix_path_ownership(path, recursive=False):
391381
fix_path_ownership(dirpath)
392382
for filename in filenames:
393383
fix_path_ownership(os.path.join(dirpath, filename))
394-
395-
396-
def check_os():
397-
import platform
398-
399-
curr_os = platform.system()
400-
if curr_os != "Linux":
401-
raise SystemExit("PerfSpect currently supports Linux-based OS only")

src/prepare_perf_events.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ def prepare_perf_events(event_file, grouping, cpu_only):
165165
["perf", "list"], universal_newlines=True
166166
)
167167
except FileNotFoundError:
168-
raise SystemExit("perf not found; please install linux perf utility")
168+
raise SystemExit("perf not found; please install the Linux perf utility")
169169

170-
except subprocess.CalledProcessError:
171-
raise SystemExit("perf not found; please install linux perf utility")
170+
except subprocess.CalledProcessError as e:
171+
raise SystemExit(f"error calling Linux perf, error code: {e.returncode}")
172172

173173
unsupported_events = []
174174
for line in fin:

0 commit comments

Comments
 (0)