[dart2js] Defer loading of codegen results.

This was landed a while ago as https://dart-review.googlesource.com/c/sdk/+/254600. However, this had to be rolled back because at the time this increased memory usage for the emitter phase. This change prevented GC from cleaning up the byte arrays of the codegen serialized files which resulted in an increased max heap.

However, now that we map (rather than copy) files into memory, there is no overhead to keeping a reference to the codegen serialization files.

Thanks to recent improvements in the efficiency of deferred serialization this change seems to improve max memory usage by up to 1.2GB for the emitter phase. Avoiding caching results also helps in this regard, usage of the results is fairly localized.

Change-Id: I4d401a877cb74cbb36b511eb598a759fe300fd5d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316180
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Nate Biggs 2023-07-26 02:23:40 +00:00 committed by Commit Queue
parent ba005169c5
commit 4f03bd0c30
2 changed files with 25 additions and 15 deletions

View file

@ -2297,6 +2297,9 @@ class DeserializedCodegenResults extends CodegenResults {
@override
CodegenResult getCodegenResults(MemberEntity member) {
return _map[member]!;
// We only access these results once as it is picked up by the work queue
// so it is safe to remove and free up space in the map. With deferred
// deserialization this will also free the Deferrable holder.
return _map.remove(member)!;
}
}

View file

@ -26,6 +26,7 @@ import '../js_model/js_strategy.dart';
import '../js_model/locals.dart';
import '../options.dart';
import '../util/sink_adapter.dart';
import 'deferrable.dart';
import 'serialization.dart';
class _StringInterner implements ir.StringInterner, StringInterner {
@ -299,7 +300,7 @@ class SerializationTask extends CompilerTask {
sink.writeMemberMap(
results,
(MemberEntity member, CodegenResult result) =>
result.writeToDataSink(sink));
sink.writeDeferrable(() => result.writeToDataSink(sink)));
sink.close();
});
}
@ -313,7 +314,7 @@ class SerializationTask extends CompilerTask {
SourceLookup sourceLookup) async {
int shards = _options.codegenShards!;
JClosedWorld closedWorld = globalTypeInferenceResults.closedWorld;
Map<MemberEntity, CodegenResult> results = {};
Map<MemberEntity, Deferrable<CodegenResult>> results = {};
for (int shard = 0; shard < shards; shard++) {
Uri uri = Uri.parse(
'${_options.dataInputUriForStage(Dart2JSStage.codegenSharded)}$shard');
@ -329,7 +330,20 @@ class SerializationTask extends CompilerTask {
});
}
return DeserializedCodegenResults(
globalTypeInferenceResults, codegenInputs, results);
globalTypeInferenceResults, codegenInputs, DeferrableValueMap(results));
}
static CodegenResult _readCodegenResult(
DataSourceReader source, JClosedWorld closedWorld) {
List<ModularName> modularNames = [];
List<ModularExpression> modularExpressions = [];
CodegenReader reader =
CodegenReaderImpl(closedWorld, modularNames, modularExpressions);
source.registerCodegenReader(reader);
CodegenResult result = CodegenResult.readFromDataSource(
source, modularNames, modularExpressions);
source.deregisterCodegenReader(reader);
return result;
}
void _deserializeCodegenInput(
@ -338,7 +352,7 @@ class SerializationTask extends CompilerTask {
Uri uri,
api.Input<List<int>> dataInput,
DataSourceIndices importedIndices,
Map<MemberEntity, CodegenResult> results,
Map<MemberEntity, Deferrable<CodegenResult>> results,
bool useDeferredSourceReads,
SourceLookup sourceLookup) {
DataSourceReader source = DataSourceReader(
@ -349,17 +363,10 @@ class SerializationTask extends CompilerTask {
useDeferredStrategy: useDeferredSourceReads);
backendStrategy.prepareCodegenReader(source);
source.registerSourceLookup(sourceLookup);
Map<MemberEntity, CodegenResult> codegenResults =
Map<MemberEntity, Deferrable<CodegenResult>> codegenResults =
source.readMemberMap((MemberEntity member) {
List<ModularName> modularNames = [];
List<ModularExpression> modularExpressions = [];
CodegenReader reader =
CodegenReaderImpl(closedWorld, modularNames, modularExpressions);
source.registerCodegenReader(reader);
CodegenResult result = CodegenResult.readFromDataSource(
source, modularNames, modularExpressions);
source.deregisterCodegenReader(reader);
return result;
return source.readDeferrableWithArg(_readCodegenResult, closedWorld,
cacheData: false);
});
_reporter.log('Read ${codegenResults.length} members from ${uri}');
results.addAll(codegenResults);