blob: 7b42b93e0383f0153364316900e50e54b9105d50 [file] [log] [blame]
// 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:convert';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart' hide Timeline;
import 'package:vm_service_protos/vm_service_protos.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
int fib(n) {
if (n < 0) return 0;
if (n == 0) return 1;
return fib(n - 1) + fib(n - 2);
}
void testeeDo() {
print('Testee doing something.');
fib(21);
print('Testee did something.');
}
int computeTimeOriginNanos(List<TracePacket> packets) {
final packetsWithPerfSamples =
packets.where((packet) => packet.hasPerfSample()).toList();
if (packetsWithPerfSamples.isEmpty) {
return 0;
}
int smallest = packetsWithPerfSamples.first.timestamp.toInt();
for (int i = 0; i < packetsWithPerfSamples.length; i++) {
if (packetsWithPerfSamples[i].timestamp < smallest) {
smallest = packetsWithPerfSamples[i].timestamp.toInt();
}
}
return smallest;
}
int computeTimeExtentNanos(List<TracePacket> packets, int timeOrigin) {
final packetsWithPerfSamples =
packets.where((packet) => packet.hasPerfSample()).toList();
if (packetsWithPerfSamples.isEmpty) {
return 0;
}
int largestExtent = packetsWithPerfSamples[0].timestamp.toInt() - timeOrigin;
for (var i = 0; i < packetsWithPerfSamples.length; i++) {
final int duration =
packetsWithPerfSamples[i].timestamp.toInt() - timeOrigin;
if (duration > largestExtent) {
largestExtent = duration;
}
}
return largestExtent;
}
Iterable<PerfSample> extractPerfSamplesFromTracePackets(
List<TracePacket> packets,
) {
return packets
.where((packet) => packet.hasPerfSample())
.map((packet) => packet.perfSample);
}
final tests = <IsolateTest>[
hasStoppedAtExit,
(VmService service, IsolateRef isolateRef) async {
final result = await service.getPerfettoCpuSamples(isolateRef.id!);
expect(result.type, 'PerfettoCpuSamples');
expect(result.samplePeriod, isPositive);
expect(result.maxStackDepth, isPositive);
expect(result.sampleCount, isPositive);
expect(result.timeOriginMicros, isPositive);
expect(result.timeExtentMicros, isPositive);
expect(result.pid, isNotNull);
final trace = Trace.fromBuffer(base64Decode(result.samples!));
final packets = trace.packet;
int frameCount = 0;
int callstackCount = 0;
int perfSampleCount = 0;
for (final packet in packets) {
if (packet.hasInternedData()) {
frameCount += packet.internedData.frames.length;
callstackCount += packet.internedData.callstacks.length;
}
if (packet.hasPerfSample()) {
perfSampleCount += 1;
}
}
expect(frameCount, isPositive);
expect(callstackCount, isPositive);
expect(perfSampleCount, callstackCount);
// Calculate the time window of events.
final timeOriginNanos = computeTimeOriginNanos(packets);
final timeExtentNanos = computeTimeExtentNanos(packets, timeOriginNanos);
print(
'Requesting CPU samples within the filter window of '
'timeOriginNanos=$timeOriginNanos and timeExtentNanos=$timeExtentNanos',
);
// Query for the samples within the time window.
final filteredResult = await service.getPerfettoCpuSamples(
isolateRef.id!,
timeOriginMicros: timeOriginNanos ~/ 1000,
timeExtentMicros: timeExtentNanos ~/ 1000,
);
final filteredTrace =
Trace.fromBuffer(base64Decode(filteredResult.samples!));
final filteredTraceTimeOriginNanos =
computeTimeOriginNanos(filteredTrace.packet);
final filteredTraceTimeExtentNanos = computeTimeExtentNanos(
filteredTrace.packet,
filteredTraceTimeOriginNanos,
);
print(
'The returned CPU samples span a time window of '
'timeOriginNanos=$filteredTraceTimeOriginNanos and '
'timeExtentNanos=$filteredTraceTimeExtentNanos',
);
// Verify that we have the same number of [PerfSample]s.
expect(
extractPerfSamplesFromTracePackets(filteredTrace.packet).length,
extractPerfSamplesFromTracePackets(packets).length,
);
},
];
void main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'get_perfetto_cpu_samples_rpc_test.dart',
testeeBefore: testeeDo,
pauseOnExit: true,
extraArgs: [
'--profiler=true',
// Crank up the sampling rate to make sure we get samples.
'--profile_period=100',
],
);