blob: edb45cc8a54a506e052b62f1995811b614a05cd2 [file] [log] [blame]
// Copyright (c) 2016, 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
part of repositories;
class SampleProfileLoadingProgressEvent
implements M.SampleProfileLoadingProgressEvent {
final SampleProfileLoadingProgress progress;
SampleProfileLoadingProgressEvent(this.progress);
}
class SampleProfileLoadingProgress extends M.SampleProfileLoadingProgress {
StreamController<SampleProfileLoadingProgressEvent> _onProgress =
StreamController<SampleProfileLoadingProgressEvent>.broadcast();
Stream<SampleProfileLoadingProgressEvent> get onProgress =>
_onProgress.stream;
final S.ServiceObjectOwner owner;
final S.Class? cls;
final M.SampleProfileTag tag;
final bool clear;
final M.SampleProfileType type;
M.SampleProfileLoadingStatus _status = M.SampleProfileLoadingStatus.fetching;
double _progress = 0.0;
final _fetchingTime = Stopwatch();
final _loadingTime = Stopwatch();
SampleProfile? _profile;
M.SampleProfileLoadingStatus get status => _status;
double get progress => _progress;
Duration get fetchingTime => _fetchingTime.elapsed;
Duration get loadingTime => _loadingTime.elapsed;
SampleProfile get profile => _profile!;
SampleProfileLoadingProgress(this.owner, this.tag, this.clear,
{this.type: M.SampleProfileType.cpu, this.cls}) {
_run();
}
Future _run() async {
_fetchingTime.start();
try {
if (clear && (type == M.SampleProfileType.cpu)) {
await owner.invokeRpc('clearCpuSamples', {});
}
var response;
if (type == M.SampleProfileType.cpu) {
response = cls != null
? await cls!.getAllocationSamples()
: await owner.invokeRpc('getCpuSamples', {'_code': true});
} else if (type == M.SampleProfileType.memory) {
assert(owner is M.VM);
response = await owner
.invokeRpc('_getNativeAllocationSamples', {'_code': true});
} else {
throw Exception('Unknown M.SampleProfileType: $type');
}
_fetchingTime.stop();
_loadingTime.start();
_status = M.SampleProfileLoadingStatus.loading;
_triggerOnProgress();
SampleProfile profile = SampleProfile();
Stream<double> progress =
profile.loadProgress(owner, response as S.ServiceMap);
progress.listen((value) {
_progress = value;
_triggerOnProgress();
});
await progress.drain();
profile.tagOrder = tag;
profile.buildFunctionCallerAndCallees();
_profile = profile;
_loadingTime.stop();
_status = M.SampleProfileLoadingStatus.loaded;
_triggerOnProgress();
} catch (e) {
if (e is S.ServerRpcException) {
if (e.code == S.ServerRpcException.kFeatureDisabled) {
_status = M.SampleProfileLoadingStatus.disabled;
_triggerOnProgress();
}
}
rethrow;
} finally {
_onProgress.close();
}
}
void _triggerOnProgress() {
_onProgress.add(SampleProfileLoadingProgressEvent(this));
}
void reuse(M.SampleProfileTag t) {
_profile!.tagOrder = t;
final onProgress =
StreamController<SampleProfileLoadingProgressEvent>.broadcast();
Timer.run(() {
onProgress.add(SampleProfileLoadingProgressEvent(this));
onProgress.close();
});
_onProgress = onProgress;
}
}
class IsolateSampleProfileRepository
implements M.IsolateSampleProfileRepository {
SampleProfileLoadingProgress? _last;
Stream<SampleProfileLoadingProgressEvent> get(
M.IsolateRef i, M.SampleProfileTag t,
{bool clear: false, bool forceFetch: false}) {
assert(clear != null);
assert(forceFetch != null);
S.Isolate isolate = i as S.Isolate;
assert(isolate != null);
if ((_last != null) && !clear && !forceFetch && (_last!.owner == isolate)) {
_last!.reuse(t);
} else {
_last = SampleProfileLoadingProgress(isolate, t, clear);
}
return _last!.onProgress;
}
}
class ClassSampleProfileRepository implements M.ClassSampleProfileRepository {
Stream<SampleProfileLoadingProgressEvent> get(
covariant M.Isolate i, M.ClassRef c, M.SampleProfileTag t,
{bool clear: false, bool forceFetch: false}) {
S.Isolate isolate = i as S.Isolate;
S.Class cls = c as S.Class;
assert(isolate != null);
assert(cls != null);
return SampleProfileLoadingProgress(isolate, t, false, cls: cls).onProgress;
}
Future enable(M.IsolateRef i, M.ClassRef c) {
S.Class cls = c as S.Class;
assert(cls != null);
return cls.setTraceAllocations(true);
}
Future disable(M.IsolateRef i, M.ClassRef c) {
S.Class cls = c as S.Class;
assert(cls != null);
return cls.setTraceAllocations(false);
}
}
class NativeMemorySampleProfileRepository
implements M.NativeMemorySampleProfileRepository {
SampleProfileLoadingProgress? _last;
Stream<SampleProfileLoadingProgressEvent> get(M.VM vm, M.SampleProfileTag t,
{bool forceFetch: false, bool clear: false}) {
assert(forceFetch != null);
S.VM owner = vm as S.VM;
assert(owner != null);
if ((_last != null) && (_last!.profile != null) && !forceFetch) {
_last!.reuse(t);
} else {
_last = SampleProfileLoadingProgress(owner, t, false,
type: M.SampleProfileType.memory);
}
return _last!.onProgress;
}
}