blob: 50c3f7452fcc375c392fb0c856bfa9ed15aab49e [file] [log] [blame]
// Copyright (c) 2018, 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.
// ignore_for_file: uri_has_not_been_generated,undefined_identifier
/// Common platform independent benchmark infrastructure that can run
/// both on the VM and when compiled to JavaScript.
library common;
import 'dart:convert' show jsonDecode, jsonEncode;
import 'dart:typed_data';
import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:protobuf/protobuf.dart';
import 'generated/benchmarks.pb.dart';
import 'generated/datasets/google_message1/proto2/benchmark_message1_proto2.pb.dart'
as p2;
import 'generated/datasets/google_message1/proto3/benchmark_message1_proto3.pb.dart'
as p3;
import 'generated/datasets/google_message2/benchmark_message2.pb.dart';
const datasetsDir =
const String.fromEnvironment('datasets_dir', defaultValue: 'datasets');
final datasetFiles = [
'$datasetsDir/google_message1/proto3/dataset.google_message1_proto3.pb',
'$datasetsDir/google_message1/proto2/dataset.google_message1_proto2.pb',
'$datasetsDir/google_message2/dataset.google_message2.pb'
];
/// Represents a dataset, a list of protobufs payloads, used for benchmarking.
/// All payloads are instances of the same message.
/// Datasets are loaded from BenchmarkDataset proto (see benchmark.proto).
class Dataset {
final String name;
/// Functions that can deserialize all payloads in this dataset.
final Factories factories;
/// List of packed payloads, which can be deserialized using [factories].
final List<Uint8List> packed = <Uint8List>[];
/// Messages deserialized from [packed] and then serialized back into JSON.
/// Used for JSON serialization benchmarks.
final List<String> asJson = <String>[];
/// Messages deserialized from [packed] and then serialized back into proto3
/// JSON object. Used for proto3 JSON serialization benchmarks.
final List<Object> asProto3JsonObject = <Object>[];
/// Messages deserialized from [packed] and then serialized back into proto3
/// JSON string. Used for proto3 JSON serialization benchmarks.
final List<String> asProto3JsonString = <String>[];
/// Messages deserialized from [packed]. Used in serialization benchmarks.
final List<GeneratedMessage> unpacked = <GeneratedMessage>[];
/// Create [Dataset] from a `BenchmarkDataset` proto.
factory Dataset.fromBinary(Uint8List binary) {
final dataSet = BenchmarkDataset.fromBuffer(binary);
final factories = Factories.forMessage(dataSet.messageName);
final ds = Dataset._(dataSet.name, factories);
for (var payload in dataSet.payload) {
final bytes = Uint8List.fromList(payload);
final msg = factories.fromBuffer(bytes);
ds.packed.add(bytes);
ds.unpacked.add(msg);
ds.asJson.add(msg.writeToJson());
final proto3Json = msg.toProto3Json();
ds.asProto3JsonObject.add(proto3Json);
ds.asProto3JsonString.add(jsonEncode(proto3Json));
}
return ds;
}
Dataset._(this.name, this.factories);
}
typedef FromBufferFactory = dynamic Function(List<int> binary);
typedef FromJsonFactory = dynamic Function(String json);
typedef FromProto3JsonStringFactory = dynamic Function(String json);
typedef FromProto3JsonObjectFactory = dynamic Function(Object json);
class Factories {
final FromBufferFactory fromBuffer;
final FromJsonFactory fromJson;
final FromProto3JsonStringFactory fromProto3JsonString;
final FromProto3JsonObjectFactory fromProto3JsonObject;
static Factories forMessage(String name) =>
_factories[name] ?? (throw 'Unsupported message: $name');
/// Mapping between `BenchmarkDataset.messageName` and corresponding
/// deserialization factories.
static final _factories = {
'benchmarks.proto2.GoogleMessage1': Factories._(
fromBuffer: (List<int> binary) => p2.GoogleMessage1.fromBuffer(binary),
fromJson: (String json) => p2.GoogleMessage1.fromJson(json),
fromProto3JsonString: (String json) =>
p2.GoogleMessage1.create()..mergeFromProto3Json(jsonDecode(json)),
fromProto3JsonObject: (Object json) =>
p2.GoogleMessage1.create()..mergeFromProto3Json(json)),
'benchmarks.proto3.GoogleMessage1': Factories._(
fromBuffer: (List<int> binary) => p3.GoogleMessage1.fromBuffer(binary),
fromJson: (String json) => p3.GoogleMessage1.fromJson(json),
fromProto3JsonString: (String json) =>
p3.GoogleMessage1.create()..mergeFromProto3Json(jsonDecode(json)),
fromProto3JsonObject: (Object json) =>
p3.GoogleMessage1.create()..mergeFromProto3Json(json)),
'benchmarks.proto2.GoogleMessage2': Factories._(
fromBuffer: (List<int> binary) => GoogleMessage2.fromBuffer(binary),
fromJson: (String json) => GoogleMessage2.fromJson(json),
fromProto3JsonString: (String json) =>
GoogleMessage2.create()..mergeFromProto3Json(jsonDecode(json)),
fromProto3JsonObject: (Object json) =>
GoogleMessage2.create()..mergeFromProto3Json(json)),
};
Factories._(
{required this.fromBuffer,
required this.fromJson,
required this.fromProto3JsonString,
required this.fromProto3JsonObject});
}
/// Base for all protobuf benchmarks.
abstract class _ProtobufBenchmark extends BenchmarkBase {
final List<Dataset> datasets;
_ProtobufBenchmark(this.datasets, String name) : super(name);
}
/// Binary deserialization benchmark.
class FromBinaryBenchmark extends _ProtobufBenchmark {
FromBinaryBenchmark(datasets) : super(datasets, 'FromBinary');
@override
void run() {
for (var i = 0; i < datasets.length; i++) {
final ds = datasets[i];
final f = ds.factories.fromBuffer;
for (var j = 0; j < ds.packed.length; j++) {
f(ds.packed[j]);
}
}
}
}
/// Binary serialization benchmark.
class ToBinaryBenchmark extends _ProtobufBenchmark {
ToBinaryBenchmark(datasets) : super(datasets, 'ToBinary');
@override
void run() {
for (final ds in datasets) {
for (final unpacked in ds.unpacked) {
unpacked.writeToBuffer();
}
}
}
}
/// JSON deserialization benchmark.
class FromJsonBenchmark extends _ProtobufBenchmark {
FromJsonBenchmark(datasets) : super(datasets, 'FromJson');
@override
void run() {
for (final ds in datasets) {
final f = ds.factories.fromJson;
for (final jsonStr in ds.asJson) {
f(jsonStr);
}
}
}
}
/// JSON serialization benchmark.
class ToJsonBenchmark extends _ProtobufBenchmark {
ToJsonBenchmark(datasets) : super(datasets, 'ToJson');
@override
void run() {
for (final ds in datasets) {
for (final unpacked in ds.unpacked) {
unpacked.writeToJson();
}
}
}
}
/// proto3 JSON deserialization benchmark: from JSON string to message.
class FromProto3JsonStringBenchmark extends _ProtobufBenchmark {
FromProto3JsonStringBenchmark(datasets)
: super(datasets, 'FromProto3JsonString');
@override
void run() {
for (final ds in datasets) {
final f = ds.factories.fromProto3JsonString;
for (final jsonStr in ds.asProto3JsonString) {
f(jsonStr);
}
}
}
}
/// proto3 JSON serialization benchmark: from message to JSON string.
class ToProto3JsonStringBenchmark extends _ProtobufBenchmark {
ToProto3JsonStringBenchmark(datasets) : super(datasets, 'ToProto3JsonString');
@override
void run() {
for (final ds in datasets) {
for (final unpacked in ds.unpacked) {
jsonEncode(unpacked.toProto3Json());
}
}
}
}
/// proto3 JSON deserialization benchmark: from JSON object to message.
class FromProto3JsonObjectBenchmark extends _ProtobufBenchmark {
FromProto3JsonObjectBenchmark(datasets)
: super(datasets, 'FromProto3JsonObject');
@override
void run() {
for (final ds in datasets) {
final f = ds.factories.fromProto3JsonObject;
for (final jsonObj in ds.asProto3JsonObject) {
f(jsonObj);
}
}
}
}
/// proto3 JSON serialization benchmark: from message to JSON object.
class ToProto3JsonObjectBenchmark extends _ProtobufBenchmark {
ToProto3JsonObjectBenchmark(datasets) : super(datasets, 'ToProto3JsonObject');
@override
void run() {
for (final ds in datasets) {
for (final unpacked in ds.unpacked) {
unpacked.toProto3Json();
}
}
}
}
/// HashCode computation benchmark.
class HashCodeBenchmark extends _ProtobufBenchmark {
HashCodeBenchmark(datasets) : super(datasets, 'HashCode');
@override
void run() {
for (final dataset in datasets) {
for (final unpacked in dataset.unpacked) {
unpacked.hashCode;
}
}
}
}
void run(List<Dataset> datasets) {
FromBinaryBenchmark(datasets).report();
ToBinaryBenchmark(datasets).report();
FromJsonBenchmark(datasets).report();
ToJsonBenchmark(datasets).report();
FromProto3JsonStringBenchmark(datasets).report();
ToProto3JsonStringBenchmark(datasets).report();
FromProto3JsonObjectBenchmark(datasets).report();
ToProto3JsonObjectBenchmark(datasets).report();
HashCodeBenchmark(datasets).report();
}