1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-05 09:20:04 +00:00

[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
hardcoding
hardly
hardware
hb
hc
helpfully
@ -750,6 +751,7 @@ subs
subtool
subtools
successes
sudo
sueta
suggest
summarization
@ -826,6 +828,7 @@ upgrade
upload
upstream
upward
useless
uuid
val
verbatim

View File

@ -49,12 +49,14 @@ void main(List<String> args) {
List<List<Map<String, num>>> runResults = [];
List<GCInfo> gcInfos = [];
Warnings warnings = new Warnings();
for (String snapshot in snapshots) {
List<Map<String, num>> snapshotResults = [];
runResults.add(snapshotResults);
for (int iteration = 0; iteration < iterations; iteration++) {
Map<String, num> benchmarkRun =
_benchmark(aotRuntime, core, snapshot, [], arguments);
Map<String, num> benchmarkRun = _benchmark(
aotRuntime, core, snapshot, [], arguments,
warnings: warnings);
if (checkFileSize != null) {
File f = new File(checkFileSize);
if (f.existsSync()) {
@ -79,6 +81,15 @@ void main(List<String> args) {
}
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() {
@ -170,7 +181,7 @@ late final RegExp _extractNumbers =
Map<String, num> _benchmark(String aotRuntime, int core, String snapshot,
List<String> extraVmArguments, List<String> arguments,
{bool silent = false}) {
{bool silent = false, Warnings? warnings}) {
if (!silent) stdout.write(".");
ProcessResult processResult = Process.runSync("perf", [
"stat",
@ -239,6 +250,7 @@ Map<String, num> _benchmark(String aotRuntime, int core, String snapshot,
result[caption] = value;
if (scaling != null) {
print("WARNING: $caption is scaled at $scaling!");
warnings?.scalingInEffect = true;
}
}
}
@ -369,3 +381,7 @@ class GCInfo {
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);
}