mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 17:40:04 +00:00
[CFE] Allow counting method calls when instrumenting
When instrumenting one can use "--count" to instrument counting method calls instead of instrumenting to create a flame graph. From that I can for instance see that `Reference.node` is called 6+ mio times when compiling compile.dart. Example run: out/ReleaseX64/dart pkg/front_end/tool/flame/instrumenter.dart pkg/front_end/tool/_fasta/compile.dart --count out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart.dill.instrumented.dill pkg/front_end/tool/_fasta/compile.dart Change-Id: I583f4b53a474c3777bb059ea89d932607b7c23ad Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/298100 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
parent
1574e860c8
commit
e5c2dd28c7
26
pkg/front_end/tool/flame/instrumenter.dart
Executable file → Normal file
26
pkg/front_end/tool/flame/instrumenter.dart
Executable file → Normal file
|
@ -26,8 +26,11 @@ Future<void> main(List<String> arguments) async {
|
|||
Future<void> _main(List<String> inputArguments, Directory tmpDir) async {
|
||||
List<String> candidates = [];
|
||||
List<String> arguments = [];
|
||||
bool doCount = false;
|
||||
for (String arg in inputArguments) {
|
||||
if (arg.startsWith("--candidates=")) {
|
||||
if (arg == "--count") {
|
||||
doCount = true;
|
||||
} else if (arg.startsWith("--candidates=")) {
|
||||
candidates.add(arg.substring("--candidates=".length));
|
||||
} else {
|
||||
arguments.add(arg);
|
||||
|
@ -46,10 +49,14 @@ Future<void> _main(List<String> inputArguments, Directory tmpDir) async {
|
|||
|
||||
print("Compiling the instrumentation library.");
|
||||
Uri instrumentationLibDill = tmpDir.uri.resolve("instrumenter.dill");
|
||||
String libFilename = "instrumenter_lib.dart";
|
||||
if (doCount) {
|
||||
libFilename = "instrumenter_lib_counter.dart";
|
||||
}
|
||||
await fasta_compile.main([
|
||||
"--omit-platform",
|
||||
"-o=${instrumentationLibDill.toFilePath()}",
|
||||
Platform.script.resolve("instrumenter_lib.dart").toFilePath()
|
||||
Platform.script.resolve(libFilename).toFilePath()
|
||||
]);
|
||||
if (!File.fromUri(instrumentationLibDill).existsSync()) {
|
||||
throw "Instrumentation library didn't compile as expected.";
|
||||
|
@ -117,11 +124,15 @@ void addIfWanted(List<Procedure> output, List<Procedure> input,
|
|||
}
|
||||
}
|
||||
|
||||
String getName(Procedure p) {
|
||||
String getName(Procedure p, {bool renameSetter = false}) {
|
||||
String name = p.name.text;
|
||||
if (renameSetter && p.isSetter) {
|
||||
name = "set:$name";
|
||||
}
|
||||
if (p.parent is Class) {
|
||||
return "${(p.parent as Class).name}.${p.name.text}";
|
||||
return "${(p.parent as Class).name}.$name";
|
||||
} else {
|
||||
return p.name.text;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,8 +173,9 @@ void initializeAndReport(
|
|||
instrumenterReport,
|
||||
new Arguments([
|
||||
new ListLiteral(procedures
|
||||
.map((p) => new StringLiteral(
|
||||
"${p.fileUri.pathSegments.last}|${getName(p)}"))
|
||||
.map(
|
||||
(p) => new StringLiteral("${p.fileUri.pathSegments.last}|"
|
||||
"${getName(p, renameSetter: true)}"))
|
||||
.toList()),
|
||||
new BoolLiteral(reportCandidates),
|
||||
])))),
|
||||
|
|
73
pkg/front_end/tool/flame/instrumenter_lib_counter.dart
Normal file
73
pkg/front_end/tool/flame/instrumenter_lib_counter.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2023, 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:typed_data";
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
Uint32List counts = new Uint32List(0);
|
||||
|
||||
void initialize(int count) {
|
||||
counts = new Uint32List(count);
|
||||
stopwatch.start();
|
||||
}
|
||||
|
||||
@pragma("vm:prefer-inline")
|
||||
void enter(int i) {
|
||||
counts[i]++;
|
||||
}
|
||||
|
||||
@pragma("vm:prefer-inline")
|
||||
void exit(int i) {}
|
||||
|
||||
void report(List<String> names, bool reportCandidates) {
|
||||
List<NameWithCount> data = [];
|
||||
for (int i = 0; i < counts.length; i++) {
|
||||
int count = counts[i];
|
||||
if (count < 10000) continue;
|
||||
data.add(new NameWithCount(names[i], count));
|
||||
}
|
||||
data.sort((a, b) => a.count - b.count);
|
||||
for (NameWithCount element in data) {
|
||||
print("${_formatInt(element.count, 11)}: ${element.name}");
|
||||
}
|
||||
}
|
||||
|
||||
class NameWithCount {
|
||||
final String name;
|
||||
final int count;
|
||||
|
||||
NameWithCount(this.name, this.count);
|
||||
}
|
||||
|
||||
String _formatInt(int input, int minLength) {
|
||||
bool negative = false;
|
||||
if (input < 0) {
|
||||
negative = true;
|
||||
input = -input;
|
||||
}
|
||||
String asString = "$input";
|
||||
int length = asString.length;
|
||||
int countSeparators = (length - 1) ~/ 3;
|
||||
int outLength = length + countSeparators;
|
||||
if (negative) outLength++;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (outLength < minLength) {
|
||||
sb.write(" " * (minLength - outLength));
|
||||
}
|
||||
|
||||
if (negative) sb.write("-");
|
||||
int end = length - (countSeparators * 3);
|
||||
sb.write(asString.substring(0, end));
|
||||
int begin = end;
|
||||
end += 3;
|
||||
while (end <= length) {
|
||||
sb.write(",");
|
||||
sb.write(asString.substring(begin, end));
|
||||
begin = end;
|
||||
end += 3;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
Loading…
Reference in a new issue