[CFE] Add perf event lister tool; more visible warning for benchmarker when scaling is in effect

I do some benchmarking with our benchmarker tool which uses "perf stat"
under the hood.

"perf stat" uses hardware counters, but we have a limited amount of
those. The benchmarker tool asks for 3 event types that will use 3
hardware counters. If there aren't 3 available it will do "scaling" and
only measure what it's asked some percentage of the time so it can still
measure all of the stuff it's asked.

This should be fine. My computer has 4 hardware counters. I think.
Only today I still experienced scaling.
And previously I asked for 4 event types because I had 4 hardware
counters, but then suddenly 1 went missing.

As it turns out another process was using hardware counters.
This CL includes a tool that - at least seeems to - be able to find
other processes using perf events (although it might not be events that
use hardware counters), thus possibly allowing you to kill that or those
process(es). I did, and I now have 4 hardware counters again.

I also made scaling more visible if it happens when using the benchmark
tool. Before it was hidden between other output, not it's also printed
at the end, together with a hint to use the new tool to attempt to fix
it.

Change-Id: Ia51db04a4f25d1d82c3d32b3901cded7d980e7f5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352525
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Jens Johansen 2024-02-15 10:30:09 +00:00 committed by Commit Queue
parent dc586994da
commit f8e58737eb
3 changed files with 96 additions and 3 deletions

View file

@ -375,6 +375,7 @@ ha
hackish hackish
hardcoding hardcoding
hardly hardly
hardware
hb hb
hc hc
helpfully helpfully
@ -750,6 +751,7 @@ subs
subtool subtool
subtools subtools
successes successes
sudo
sueta sueta
suggest suggest
summarization summarization
@ -826,6 +828,7 @@ upgrade
upload upload
upstream upstream
upward upward
useless
uuid uuid
val val
verbatim verbatim

View file

@ -49,12 +49,14 @@ void main(List<String> args) {
List<List<Map<String, num>>> runResults = []; List<List<Map<String, num>>> runResults = [];
List<GCInfo> gcInfos = []; List<GCInfo> gcInfos = [];
Warnings warnings = new Warnings();
for (String snapshot in snapshots) { for (String snapshot in snapshots) {
List<Map<String, num>> snapshotResults = []; List<Map<String, num>> snapshotResults = [];
runResults.add(snapshotResults); runResults.add(snapshotResults);
for (int iteration = 0; iteration < iterations; iteration++) { for (int iteration = 0; iteration < iterations; iteration++) {
Map<String, num> benchmarkRun = Map<String, num> benchmarkRun = _benchmark(
_benchmark(aotRuntime, core, snapshot, [], arguments); aotRuntime, core, snapshot, [], arguments,
warnings: warnings);
if (checkFileSize != null) { if (checkFileSize != null) {
File f = new File(checkFileSize); File f = new File(checkFileSize);
if (f.existsSync()) { if (f.existsSync()) {
@ -79,6 +81,15 @@ void main(List<String> args) {
} }
printGcDiff(gcInfos.first, gcInfos[i]); printGcDiff(gcInfos.first, gcInfos[i]);
} }
if (warnings.scalingInEffect) {
print("Be aware the the above was with scaling in effect.");
print("As such the results are likely useless.");
print("Possibly some other process is using the hardware counters.");
print("Running this tool");
print("sudo out/ReleaseX64/dart pkg/front_end/tool/perf_event_tool.dart");
print("will attempt to give you such information.");
}
} }
void _help() { void _help() {
@ -170,7 +181,7 @@ late final RegExp _extractNumbers =
Map<String, num> _benchmark(String aotRuntime, int core, String snapshot, Map<String, num> _benchmark(String aotRuntime, int core, String snapshot,
List<String> extraVmArguments, List<String> arguments, List<String> extraVmArguments, List<String> arguments,
{bool silent = false}) { {bool silent = false, Warnings? warnings}) {
if (!silent) stdout.write("."); if (!silent) stdout.write(".");
ProcessResult processResult = Process.runSync("perf", [ ProcessResult processResult = Process.runSync("perf", [
"stat", "stat",
@ -239,6 +250,7 @@ Map<String, num> _benchmark(String aotRuntime, int core, String snapshot,
result[caption] = value; result[caption] = value;
if (scaling != null) { if (scaling != null) {
print("WARNING: $caption is scaled at $scaling!"); print("WARNING: $caption is scaled at $scaling!");
warnings?.scalingInEffect = true;
} }
} }
} }
@ -369,3 +381,7 @@ class GCInfo {
GCInfo(this.combinedTime, this.countWhat); GCInfo(this.combinedTime, this.countWhat);
} }
class Warnings {
bool scalingInEffect = false;
}

View file

@ -0,0 +1,74 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:io";
const bool debug = false;
/// Tool to find and display any process using perf_events which as a
/// consequence might use one of the hardware counters, leaving fewer for
/// `perf stat` stuff.
/// Likely has to be run as root.
void main() {
try {
mainImpl();
} catch (e) {
print("Got the error '$e'.");
print("");
print("┌───────────────────────────────────────────────────┐");
print("│ Note that this tool likely has to be run as root. │");
print("└───────────────────────────────────────────────────┘");
print("");
rethrow;
}
}
void mainImpl() {
if (!Platform.isLinux) {
throw "This tool only works in Linux.";
}
bool foundSomething = false;
Directory dir = new Directory("/proc/");
for (FileSystemEntity pidDir in dir.listSync(recursive: false)) {
if (pidDir is! Directory) continue;
Uri pidUri = pidDir.uri;
String possiblePid = pidUri.pathSegments[pidUri.pathSegments.length - 2];
int? candidatePid = int.tryParse(possiblePid);
if (candidatePid == null) continue;
Directory fdDir = new Directory.fromUri(pidDir.uri.resolve("fd/"));
int count = 0;
for (FileSystemEntity entry in fdDir.listSync()) {
if (debug) {
print("$entry");
}
if (entry is Link) {
String target = entry.targetSync();
if (debug) {
print(" => target: $target");
}
if (target.contains("perf_event")) {
count++;
}
}
}
if (count > 0) {
print("Found $count perf event file descriptors for "
"process with pid $candidatePid:");
runPsForPid(candidatePid);
print("");
foundSomething = true;
}
}
if (!foundSomething) {
print("Found no open perf file descriptors.");
return;
}
}
void runPsForPid(int pid) {
ProcessResult psRun = Process.runSync("ps", ["-p", "$pid", "u"]);
stdout.write(psRun.stdout);
stderr.write(psRun.stderr);
}