blob: 1c5cc44f01ca3a901f1b3e942579e2ef4267bc41 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. 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 'package:args/args.dart';
import 'package:fidl_fidl_examples_echo/fidl.dart';
import 'package:lib.app.dart/app.dart';
import 'package:fidl_fuchsia_sys/fidl.dart';
import 'package:fuchsia/fuchsia.dart';
typedef PerfTest = Future<int> Function(String server, int number);
StartupContext _context;
const List<String> kDefaultServers = [
'echo2_server_cpp',
'echo2_server_rust',
'echo2_server_go',
'fuchsia-pkg://fuchsia.com/echo_dart#meta/echo_server_dart.cmx',
'fuchsia-pkg://fuchsia.com/echo_server_async_dart#meta/echo_server_async_dart.cmx'
];
const List<int> kDefaultCalls = [1000, 10000];
const String kMessage = 'hello';
Future<int> runTest(String server, void ready(Echo echo, void complete())) {
final EchoProxy echo = new EchoProxy();
final ComponentControllerProxy controller = new ComponentControllerProxy();
final Services services = new Services();
final LaunchInfo launchInfo = new LaunchInfo(
url: server,
arguments: <String>['-q'],
directoryRequest: services.request());
_context.launcher.createComponent(launchInfo, controller.ctrl.request());
echo.ctrl.bind(services.connectToServiceByName<Echo>(Echo.$serviceName));
final Completer<int> completer = new Completer<int>();
// Notice if the echo server or its controller goes away.
echo.ctrl.onConnectionError = () {
final message = '$server unexpectedly closed the connection';
print(message);
completer.completeError(message);
};
controller.ctrl.onConnectionError = () {
final message = '$server controller connection unexpectedly closed';
print(message);
completer.completeError(message);
};
// Wait until the echo server is up and replying to messages.
echo.echoString(kMessage, (String response) {
final Stopwatch stopwatch = new Stopwatch()..start();
void done() {
stopwatch.stop();
void complete() {
if (!completer.isCompleted) {
completer.complete(stopwatch.elapsedMicroseconds);
}
}
// Stop the echo server.
echo.ctrl.onConnectionError = null;
echo.ctrl.close();
controller.ctrl.onConnectionError = complete;
controller.ctrl.onClose = complete;
controller
..kill()
..onTerminated = (unusedReturnCode, unusedTerminationReason) {
// Now we're done...
complete();
controller.ctrl.close();
};
}
try {
ready(echo, done);
// ignore: avoid_catches_without_on_clauses
} catch (ex, stack) {
print('Exception testing $server: $ex');
print(stack);
completer.completeError(ex);
}
});
return completer.future;
}
Future<int> testSerialPerf(String server, int number) async {
return runTest(server, (Echo echo, void complete()) {
int remaining = number;
void callServer() {
echo.echoString(kMessage, (String _) {
remaining--;
if (remaining == 0) {
complete();
} else {
callServer();
}
});
}
callServer();
});
}
Future<int> testParallelPerf(String server, int number) async {
return runTest(server, (Echo echo, void complete()) {
int remaining = number;
for (int i = 0; i < number; i++) {
echo.echoString(kMessage, (String _) {
remaining--;
if (remaining == 0) {
complete();
}
});
}
});
}
void main(List<String> argv) async {
final parser = new ArgParser()
..addMultiOption('server', abbr: 's', defaultsTo: kDefaultServers)
..addMultiOption('num-calls',
abbr: 'n', defaultsTo: kDefaultCalls.map((i) => i.toString()))
..addFlag('parallel', abbr: 'p');
final ArgResults args = parser.parse(argv);
final List<String> servers = args['server'];
final List<int> numCalls = [];
for (final String str in args['num-calls']) {
numCalls.add(int.parse(str));
}
final PerfTest perfTest =
args['parallel'] ? testParallelPerf : testSerialPerf;
_context = new StartupContext.fromStartupInfo();
// Map of server to map of count to total microseconds.
final Map<String, Map<int, int>> results = {};
try {
for (final int count in numCalls) {
for (final String server in servers) {
if (!results.containsKey(server)) {
results[server] = {};
}
print('Making $count calls to $server...');
final microseconds = await perfTest(server, count);
results[server][count] = microseconds;
}
}
// ignore: avoid_catches_without_on_clauses
} catch (ex, stack) {
print('Exception running tests: $ex');
print(stack);
}
print('server,${numCalls.join(',')}');
for (final String server in results.keys) {
StringBuffer line = new StringBuffer(server);
for (final int count in numCalls) {
final int microseconds = results[server][count] ?? 0;
line.write(',${(microseconds / count)}');
}
print(line);
}
exit(0);
}