blob: a648344bee4608cbac2e1dd26b94cea82be1892b [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.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:unittest/unittest.dart';
import '../../test/integration/integration_tests.dart';
void printMemoryResults(String id, String description, List<int> sizes) {
int minMemory = sizes.fold(sizes.first, min);
int maxMemory = sizes.fold(sizes.first, max);
String now = new DateTime.now().toUtc().toIso8601String();
print('$now ========== $id');
print('memory: $sizes');
print('min_memory: $minMemory');
print('max_memory: $maxMemory');
print(description.trim());
print('--------------------');
print('');
print('');
}
/**
* Base class for analysis server memory usage tests.
*/
class AnalysisServerMemoryUsageTest
extends AbstractAnalysisServerIntegrationTest {
static const int vmServicePort = 12345;
int getMemoryUsage() {
ProcessResult result = _run('curl', <String>[
'localhost:$vmServicePort/_getAllocationProfile\?isolateId=isolates/root\&gc=full'
]);
Map json = JSON.decode(result.stdout);
Map heaps = json['result']['heaps'];
int newSpace = heaps['new']['used'];
int oldSpace = heaps['old']['used'];
return newSpace + oldSpace;
}
/**
* Send the server an 'analysis.setAnalysisRoots' command directing it to
* analyze [sourceDirectory].
*/
Future setAnalysisRoot() =>
sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
/**
* The server is automatically started before every test.
*/
@override
Future setUp() {
onAnalysisErrors.listen((AnalysisErrorsParams params) {
currentAnalysisErrors[params.file] = params.errors;
});
onServerError.listen((ServerErrorParams params) {
// A server error should never happen during an integration test.
fail('${params.message}\n${params.stackTrace}');
});
Completer serverConnected = new Completer();
onServerConnected.listen((_) {
expect(serverConnected.isCompleted, isFalse);
serverConnected.complete();
});
return startServer(servicesPort: vmServicePort).then((_) {
server.listenToOutput(dispatchNotification);
server.exitCode.then((_) {
skipShutdown = true;
});
return serverConnected.future;
});
}
/**
* After every test, the server is stopped.
*/
Future shutdown() async => await shutdownIfNeeded();
/**
* Enable [ServerService.STATUS] notifications so that [analysisFinished]
* can be used.
*/
Future subscribeToStatusNotifications() async {
await sendServerSetSubscriptions([ServerService.STATUS]);
}
/**
* Synchronously run the given [executable] with the given [arguments]. Return
* the result of running the process.
*/
ProcessResult _run(String executable, List<String> arguments) {
return Process.runSync(executable, arguments,
stderrEncoding: UTF8, stdoutEncoding: UTF8);
}
/**
* 1. Start Analysis Server.
* 2. Set the analysis [roots].
* 3. Wait for analysis to complete.
* 4. Record the heap size after analysis is finished.
* 5. Shutdown.
* 6. Go to (1).
*/
static Future<List<int>> start_waitInitialAnalysis_shutdown(
{List<String> roots, int numOfRepeats}) async {
expect(roots, isNotNull, reason: 'roots');
expect(numOfRepeats, isNotNull, reason: 'numOfRepeats');
// Repeat.
List<int> sizes = <int>[];
for (int i = 0; i < numOfRepeats; i++) {
AnalysisServerMemoryUsageTest test = new AnalysisServerMemoryUsageTest();
// Initialize Analysis Server.
await test.setUp();
await test.subscribeToStatusNotifications();
// Set roots and analyze.
await test.sendAnalysisSetAnalysisRoots(roots, []);
await test.analysisFinished;
sizes.add(test.getMemoryUsage());
// Stop the server.
await test.shutdown();
}
return sizes;
}
}