| // Copyright (c) 2021, 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:developer'; |
| import 'package:observatory_2/models.dart' as M; |
| import 'package:observatory_2/service_io.dart'; |
| import 'package:observatory_2/sample_profile.dart'; |
| import 'package:test/test.dart'; |
| import 'service_test_common.dart'; |
| import 'test_helper.dart'; |
| |
| class Foo { |
| Foo() { |
| print('Foo'); |
| } |
| } |
| |
| class Bar { |
| Bar() { |
| print('Bar'); |
| } |
| } |
| |
| void test() { |
| debugger(); |
| // Toggled on for Foo. |
| debugger(); |
| debugger(); |
| // Traced allocation. |
| Foo(); |
| // Untraced allocation. |
| Bar(); |
| // Toggled on for Bar. |
| debugger(); |
| debugger(); |
| // Traced allocation. |
| Bar(); |
| debugger(); |
| } |
| |
| var tests = <IsolateTest>[ |
| hasStoppedAtBreakpoint, |
| |
| // Initial. |
| (Isolate isolate) async { |
| // Verify initial state of 'Foo'. |
| final fooClass = await getClassFromRootLib(isolate, 'Foo'); |
| expect(fooClass, isNotNull); |
| expect(fooClass.name, equals('Foo')); |
| print(fooClass.id); |
| expect(fooClass.traceAllocations, isFalse); |
| await fooClass.setTraceAllocations(true); |
| await fooClass.reload(); |
| expect(fooClass.traceAllocations, true); |
| }, |
| |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| // Extra debugger stop, continue to allow the allocation stubs to be switched |
| // over. This is a bug but low priority. |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| |
| // Allocation profile. |
| (Isolate isolate) async { |
| final fooClass = await getClassFromRootLib(isolate, 'Foo'); |
| await fooClass.reload(); |
| expect(fooClass.traceAllocations, true); |
| |
| final profileResponse = (await isolate.getAllocationTraces()) as ServiceMap; |
| expect(profileResponse, isNotNull); |
| expect(profileResponse['type'], 'CpuSamples'); |
| expect(profileResponse['samples'].length, 1); |
| expect(profileResponse['samples'][0]['identityHashCode'], isNotNull); |
| expect(profileResponse['samples'][0]['identityHashCode'] != 0, true); |
| await fooClass.setTraceAllocations(false); |
| await fooClass.reload(); |
| expect(fooClass.traceAllocations, isFalse); |
| |
| // Verify the allocation trace for the `Foo()` allocation. |
| final cpuProfile = SampleProfile(); |
| await cpuProfile.load(isolate, profileResponse); |
| cpuProfile.buildCodeCallerAndCallees(); |
| cpuProfile.buildFunctionCallerAndCallees(); |
| final tree = cpuProfile.loadCodeTree(M.ProfileTreeDirection.exclusive); |
| var node = tree.root; |
| final expected = [ |
| 'Root', |
| '[Unoptimized] test', |
| '[Unoptimized] test', |
| '[Unoptimized] _ServiceTesteeRunner.run', |
| ]; |
| for (var i = 0; i < expected.length; i++) { |
| expect(node.profileCode.code.name, equals(expected[i])); |
| // Depth first traversal. |
| if (node.children.length == 0) { |
| node = null; |
| } else { |
| node = node.children[0]; |
| } |
| expect(node, isNotNull); |
| } |
| }, |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| (Isolate isolate) async { |
| // Trace Bar. |
| final barClass = await getClassFromRootLib(isolate, 'Bar'); |
| await barClass.reload(); |
| expect(barClass.traceAllocations, false); |
| await barClass.setTraceAllocations(true); |
| await barClass.reload(); |
| expect(barClass.traceAllocations, true); |
| }, |
| |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| // Extra debugger stop, continue to allow the allocation stubs to be switched |
| // over. This is a bug but low priority. |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| |
| (Isolate isolate) async { |
| // Ensure the allocation of `Bar()` was recorded. |
| final profileResponse = (await isolate.getAllocationTraces()) as ServiceMap; |
| expect(profileResponse['samples'].length, 2); |
| }, |
| ]; |
| |
| main(args) async => runIsolateTests(args, tests, testeeConcurrent: test); |