Skip to content

Commit

Permalink
[CFE] Add benchmarking possibility to the incremental compiler
Browse files Browse the repository at this point in the history
This CL allows the incremental compiler to pass a benchmarker and
perform benchmarking in the same way as is possible via `fasta compile`.
It's enabled by setting an environment variable, on linux this can be
done with

```
export DART_CFE_ENABLE_INCREMENTAL_COMPILER_BENCHMARKING=true
```

on Windows it would likely be something like

```
set DART_CFE_ENABLE_INCREMENTAL_COMPILER_BENCHMARKING=true
```

When set, benchmarking data is recorded and after a `computeDelta`
call the recorded data is printed.

Currently, visualization via the html document requires wrapping of
the output between

```
{"benchmarkers": [
```

and

```
]}
```

Change-Id: I78f1298ebc17c47a172abdf00c48dac388197d3b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237693
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
  • Loading branch information
jensjoha authored and Commit Bot committed Mar 21, 2022
1 parent c4eb880 commit e68cf05
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 15 deletions.
2 changes: 1 addition & 1 deletion pkg/front_end/lib/src/fasta/dill/dill_target.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class DillTarget extends TargetImplementation {
benchmarker?.enterPhase(BenchmarkPhases.dill_finalizeExports);
loader.finalizeExports(
suppressFinalizationErrors: suppressFinalizationErrors);
benchmarker?.enterPhase(BenchmarkPhases.unknown);
benchmarker?.enterPhase(BenchmarkPhases.unknownDillTarget);
}
isLoaded = true;
}
Expand Down
68 changes: 62 additions & 6 deletions pkg/front_end/lib/src/fasta/incremental_compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ library fasta.incremental_compiler;

import 'dart:async' show Completer;

import 'dart:convert' show JsonEncoder;

import 'package:_fe_analyzer_shared/src/scanner/abstract_scanner.dart'
show ScannerConfiguration;

import 'package:front_end/src/fasta/kernel/benchmarker.dart'
show BenchmarkPhases, Benchmarker;

import 'package:kernel/binary/ast_from_binary.dart'
show
BinaryBuilderWithMetadata,
Expand Down Expand Up @@ -124,7 +129,8 @@ import 'source/source_class_builder.dart' show SourceClassBuilder;

import 'util/error_reporter_file_copier.dart' show saveAsGzip;

import 'util/experiment_environment_getter.dart' show getExperimentEnvironment;
import 'util/experiment_environment_getter.dart'
show enableIncrementalCompilerBenchmarking, getExperimentEnvironment;

import 'util/textual_outline.dart' show textualOutline;

Expand Down Expand Up @@ -174,6 +180,10 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
final IncrementalSerializer? _incrementalSerializer;
final _ComponentProblems _componentProblems = new _ComponentProblems();

// This will be set if the right environment variable is set
// (enableIncrementalCompilerBenchmarking).
Benchmarker? _benchmarker;

RecorderForTesting? get recorderForTesting => null;

static final Uri debugExprUri =
Expand Down Expand Up @@ -247,7 +257,9 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
void _enableExperimentsBasedOnEnvironment({Set<String>? enabledExperiments}) {
// Note that these are all experimental. Use at your own risk.
enabledExperiments ??= getExperimentEnvironment();
// Currently there's no live experiments.
if (enabledExperiments.contains(enableIncrementalCompilerBenchmarking)) {
_benchmarker = new Benchmarker();
}
}

@override
Expand Down Expand Up @@ -276,13 +288,17 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
}
_computeDeltaRunOnce = true;
IncrementalKernelTarget? lastGoodKernelTarget = _lastGoodKernelTarget;
_benchmarker?.reset();

// Initial setup: Load platform, initialize from dill or component etc.
_benchmarker?.enterPhase(BenchmarkPhases.incremental_setupPackages);
UriTranslator uriTranslator = await _setupPackagesAndUriTranslator(c);
_benchmarker?.enterPhase(BenchmarkPhases.incremental_ensurePlatform);
IncrementalCompilerData data =
await _ensurePlatformAndInitialize(uriTranslator, c);

// Figure out what to keep and what to throw away.
_benchmarker?.enterPhase(BenchmarkPhases.incremental_invalidate);
Set<Uri?> invalidatedUris = this._invalidatedUris.toSet();
_invalidateNotKeptUserBuilders(invalidatedUris);
ReusageResult? reusedResult = _computeReusedLibraries(
Expand All @@ -305,15 +321,20 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
}

// Experimental invalidation initialization (e.g. figure out if we can).
_benchmarker
?.enterPhase(BenchmarkPhases.incremental_experimentalInvalidation);
ExperimentalInvalidation? experimentalInvalidation =
await _initializeExperimentalInvalidation(reusedResult, c);
recorderForTesting?.recordRebuildBodiesCount(
experimentalInvalidation?.missingSources.length ?? 0);

_benchmarker
?.enterPhase(BenchmarkPhases.incremental_invalidatePrecompiledMacros);
_invalidatePrecompiledMacros(c.options, reusedResult.notReusedLibraries);

// Cleanup: After (potentially) removing builders we have stuff to cleanup
// to not leak, and we might need to re-create the dill target.
_benchmarker?.enterPhase(BenchmarkPhases.incremental_cleanup);
_cleanupRemovedBuilders(
lastGoodKernelTarget, reusedResult, uriTranslator);
_recreateDillTargetIfPackageWasUpdated(uriTranslator, c);
Expand All @@ -330,6 +351,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator {

// For modular compilation we can be asked to load components and track
// which libraries we actually use for the compilation. Set that up now.
_benchmarker
?.enterPhase(BenchmarkPhases.incremental_loadEnsureLoadedComponents);
_loadEnsureLoadedComponents(reusedLibraries);
if (trackNeededDillLibraries) {
_resetTrackingOfUsedLibraries(hierarchy);
Expand All @@ -340,6 +363,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
// builders needs to be patched up.
IncrementalKernelTarget currentKernelTarget;
while (true) {
_benchmarker?.enterPhase(BenchmarkPhases.incremental_setupInLoop);
currentKernelTarget = _setupNewKernelTarget(c, uriTranslator, hierarchy,
reusedLibraries, experimentalInvalidation, entryPoints!.first);
Map<LibraryBuilder, List<LibraryBuilder>>? rebuildBodiesMap =
Expand All @@ -350,12 +374,16 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
// TODO(johnniwinther,jensj): Ensure that the internal state of the
// incremental compiler is consistent across 1 or more macro
// precompilations.
_benchmarker?.enterPhase(BenchmarkPhases.incremental_precompileMacros);
NeededPrecompilations? neededPrecompilations =
await currentKernelTarget.computeNeededPrecompilations();
_benchmarker?.enterPhase(BenchmarkPhases.incremental_precompileMacros);
if (enableMacros &&
await precompileMacros(neededPrecompilations, c.options)) {
continue;
}
_benchmarker?.enterPhase(
BenchmarkPhases.incremental_experimentalInvalidationPatchUpScopes);
_experimentalInvalidationPatchUpScopes(
experimentalInvalidation, rebuildBodiesMap);
rebuildBodiesMap = null;
Expand All @@ -380,6 +408,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
componentWithDill = buildResult.component;
}
buildResult.macroApplications?.close();

_benchmarker?.enterPhase(BenchmarkPhases.incremental_hierarchy);
hierarchy ??= currentKernelTarget.loader.hierarchy;
if (currentKernelTarget.classHierarchyChanges != null) {
hierarchy.applyTreeChanges(
Expand All @@ -393,6 +423,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator {

Set<Library>? neededDillLibraries;
if (trackNeededDillLibraries) {
_benchmarker
?.enterPhase(BenchmarkPhases.incremental_performDillUsageTracking);
// Perform actual dill usage tracking.
neededDillLibraries =
_performDillUsageTracking(currentKernelTarget, hierarchy);
Expand All @@ -403,6 +435,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
// TODO(jensj,johnniwinther): Given the code below, [componentWithDill] is
// assumed always to be non-null.
if (componentWithDill != null) {
_benchmarker
?.enterPhase(BenchmarkPhases.incremental_releaseAncillaryResources);
this._invalidatedUris.clear();
_hasToCheckPackageUris = false;
lastGoodKernelTarget?.loader.releaseAncillaryResources();
Expand All @@ -411,11 +445,19 @@ class IncrementalCompiler implements IncrementalKernelGenerator {

// Compute which libraries to output and which (previous) errors/warnings
// we have to reissue. In the process do some cleanup too.
_benchmarker
?.enterPhase(BenchmarkPhases.incremental_releaseAncillaryResources);
List<Library> compiledLibraries =
new List<Library>.of(currentKernelTarget.loader.libraries);
Map<Uri, Source> uriToSource = componentWithDill!.uriToSource;

_benchmarker?.enterPhase(BenchmarkPhases
.incremental_experimentalCompilationPostCompilePatchup);
_experimentalCompilationPostCompilePatchup(
experimentalInvalidation, compiledLibraries, uriToSource);

_benchmarker?.enterPhase(BenchmarkPhases
.incremental_calculateOutputLibrariesAndIssueLibraryProblems);
List<Library> outputLibraries =
_calculateOutputLibrariesAndIssueLibraryProblems(
currentKernelTarget,
Expand All @@ -439,10 +481,13 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
_dillLoadedData!.loader.currentSourceLoader =
currentKernelTarget.loader;
} else {
_benchmarker?.enterPhase(
BenchmarkPhases.incremental_convertSourceLibraryBuildersToDill);
_previousSourceBuilders = _convertSourceLibraryBuildersToDill(
currentKernelTarget, experimentalInvalidation);
}

_benchmarker?.enterPhase(BenchmarkPhases.incremental_end);
experimentalInvalidation = null;

// Output result.
Expand All @@ -465,6 +510,15 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
currentlyCompilingLocal.complete();

_lastGoodKernelTarget = currentKernelTarget;

_benchmarker?.stop();

if (_benchmarker != null) {
// Report.
JsonEncoder encoder = new JsonEncoder.withIndent(" ");
print(encoder.convert(_benchmarker));
}

return new IncrementalCompilerResult(result,
classHierarchy: currentKernelTarget.loader.hierarchy,
coreTypes: currentKernelTarget.loader.coreTypes,
Expand Down Expand Up @@ -1027,8 +1081,9 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
// The package file was changed.
// Make sure the dill loader is on the same page.
DillTarget oldDillLoadedData = _dillLoadedData!;
DillTarget newDillLoadedData = _dillLoadedData =
new DillTarget(_ticker, uriTranslator, c.options.target);
DillTarget newDillLoadedData = _dillLoadedData = new DillTarget(
_ticker, uriTranslator, c.options.target,
benchmarker: _benchmarker);
for (DillLibraryBuilder library
in oldDillLoadedData.loader.libraryBuilders) {
newDillLoadedData.loader.registerLibraryBuilder(library);
Expand Down Expand Up @@ -1286,8 +1341,9 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
UriTranslator uriTranslator, CompilerContext context) async {
IncrementalCompilerData data = new IncrementalCompilerData();
if (_dillLoadedData == null) {
DillTarget dillLoadedData = _dillLoadedData =
new DillTarget(_ticker, uriTranslator, context.options.target);
DillTarget dillLoadedData = _dillLoadedData = new DillTarget(
_ticker, uriTranslator, context.options.target,
benchmarker: _benchmarker);
int bytesLength = await _initializationStrategy.initialize(
dillLoadedData,
uriTranslator,
Expand Down
54 changes: 53 additions & 1 deletion pkg/front_end/lib/src/fasta/kernel/benchmarker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,37 @@ class Benchmarker {

BenchmarkPhases _currentPhase = BenchmarkPhases.implicitInitialization;
BenchmarkSubdivides? _subdivide;
int _subdivideLayer = 0;

void reset() {
_totalStopwatch.start();
_totalStopwatch.reset();
_phaseStopwatch.start();
_phaseStopwatch.reset();
_subdivideStopwatch.start();
_subdivideStopwatch.reset();
for (int i = 0; i < _phaseTimings.length; i++) {
assert(BenchmarkPhases.values[i].index == i);
_phaseTimings[i] = new PhaseTiming(BenchmarkPhases.values[i]);
}
_currentPhase = BenchmarkPhases.implicitInitialization;
_subdivide = null;
_subdivideLayer = 0;
}

void beginSubdivide(final BenchmarkSubdivides phase) {
_subdivideLayer++;
if (_subdivideLayer != 1) return;
BenchmarkSubdivides? subdivide = _subdivide;
if (subdivide != null) throw "Can't subdivide a subdivide";
assert(subdivide == null);
_subdivideStopwatch.reset();
_subdivide = phase;
}

void endSubdivide() {
_subdivideLayer--;
assert(_subdivideLayer >= 0);
if (_subdivideLayer != 0) return;
BenchmarkSubdivides? subdivide = _subdivide;
if (subdivide == null) throw "Can't end a nonexistent subdivide";
_phaseTimings[_currentPhase.index]
Expand Down Expand Up @@ -173,10 +195,36 @@ enum BenchmarkPhases {
omitPlatform,
writeComponent,
benchmarkAstVisit,

incremental_setupPackages,
incremental_ensurePlatform,
incremental_invalidate,
incremental_experimentalInvalidation,
incremental_invalidatePrecompiledMacros,
incremental_cleanup,
incremental_loadEnsureLoadedComponents,
incremental_setupInLoop,
incremental_precompileMacros,
incremental_experimentalInvalidationPatchUpScopes,
incremental_hierarchy,
incremental_performDillUsageTracking,
incremental_releaseAncillaryResources,
incremental_experimentalCompilationPostCompilePatchup,
incremental_calculateOutputLibrariesAndIssueLibraryProblems,
incremental_convertSourceLibraryBuildersToDill,
incremental_end,

precompileMacros,

// add more here
//
end,
unknown,
unknownDillTarget,
unknownComputeNeededPrecompilations,
unknownBuildOutlines,
unknownBuildComponent,
unknownGenerateKernelInternal,
}

enum BenchmarkSubdivides {
Expand All @@ -198,4 +246,8 @@ enum BenchmarkSubdivides {

buildOutlineExpressions,
delayedActionPerformer,

computeMacroApplications_macroExecutorProvider,
macroApplications_macroExecutorLoadMacro,
macroApplications_macroExecutorInstantiateMacro,
}
7 changes: 4 additions & 3 deletions pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@ class KernelTarget extends TargetImplementation {
benchmarker?.enterPhase(BenchmarkPhases.outline_computeMacroDeclarations);
NeededPrecompilations? result = loader.computeMacroDeclarations();

benchmarker?.enterPhase(BenchmarkPhases.unknown);
benchmarker
?.enterPhase(BenchmarkPhases.unknownComputeNeededPrecompilations);
return result;
}, () => loader.currentUriForCrashReporting);
}
Expand Down Expand Up @@ -608,7 +609,7 @@ class KernelTarget extends TargetImplementation {
installAllComponentProblems(loader.allComponentProblems);
loader.allComponentProblems.clear();

benchmarker?.enterPhase(BenchmarkPhases.unknown);
benchmarker?.enterPhase(BenchmarkPhases.unknownBuildOutlines);

// For whatever reason sourceClassBuilders is kept alive for some amount
// of time, meaning that all source library builders will be kept alive
Expand Down Expand Up @@ -689,7 +690,7 @@ class KernelTarget extends TargetImplementation {
benchmarker?.enterPhase(BenchmarkPhases.body_installAllComponentProblems);
installAllComponentProblems(loader.allComponentProblems);

benchmarker?.enterPhase(BenchmarkPhases.unknown);
benchmarker?.enterPhase(BenchmarkPhases.unknownBuildComponent);

// For whatever reason sourceClasses is kept alive for some amount
// of time, meaning that all source library builders will be kept alive
Expand Down
11 changes: 10 additions & 1 deletion pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import 'package:_fe_analyzer_shared/src/macros/executor/introspection_impls.dart
as macro;
import 'package:_fe_analyzer_shared/src/macros/executor/remote_instance.dart'
as macro;
import 'package:front_end/src/fasta/kernel/benchmarker.dart'
show BenchmarkSubdivides, Benchmarker;
import 'package:kernel/ast.dart' show DartType;
import 'package:kernel/src/types.dart';
import 'package:kernel/type_environment.dart' show SubtypeCheckMode;
Expand Down Expand Up @@ -127,7 +129,8 @@ class MacroApplications {
macro.MacroExecutor macroExecutor,
Map<Uri, Uri> precompiledMacroUris,
Map<SourceLibraryBuilder, LibraryMacroApplicationData> libraryData,
MacroApplicationDataForTesting? dataForTesting) async {
MacroApplicationDataForTesting? dataForTesting,
Benchmarker? benchmarker) async {
Map<ClassBuilder, macro.MacroClassIdentifier> classIdCache = {};

Map<MacroApplication, macro.MacroInstanceIdentifier> instanceIdCache = {};
Expand All @@ -140,17 +143,23 @@ class MacroApplications {
String macroClassName = application.classBuilder.name;
Uri? precompiledMacroUri = precompiledMacroUris[libraryUri];
try {
benchmarker?.beginSubdivide(
BenchmarkSubdivides.macroApplications_macroExecutorLoadMacro);
macro.MacroClassIdentifier macroClassIdentifier =
classIdCache[application.classBuilder] ??=
await macroExecutor.loadMacro(libraryUri, macroClassName,
precompiledKernelUri: precompiledMacroUri);
benchmarker?.endSubdivide();
try {
benchmarker?.beginSubdivide(BenchmarkSubdivides
.macroApplications_macroExecutorInstantiateMacro);
application.instanceIdentifier = instanceIdCache[application] ??=
await macroExecutor.instantiateMacro(
macroClassIdentifier,
application.constructorName,
// TODO(johnniwinther): Support macro arguments.
new macro.Arguments([], {}));
benchmarker?.endSubdivide();
} catch (e) {
throw "Error instantiating macro `${application}`: $e";
}
Expand Down
Loading

0 comments on commit e68cf05

Please sign in to comment.