Skip to content

Commit

Permalink
separate out benchmark into 4 stages: create, serialize, deserialize,…
Browse files Browse the repository at this point in the history
… hash (#154)

As mentioned in #153. This gives us a better overall picture of where time is going, in the various modes.

Current results:
```
        SdkMapsJsonWireBenchmark-create:  904ms
      SdkMapsBufferWireBenchmark-create:  711ms
     SdkMapsBuilderWireBenchmark-create:  713ms
       LazyMapsJsonWireBenchmark-create:    0ms
     LazyMapsBufferWireBenchmark-create:    0ms
 LazyWrappersBufferWireBenchmark-create:  420ms
    BuilderMapsJsonWireBenchmark-create:  374ms
 BuilderMapsBuilderWireBenchmark-create:  379ms
        SdkMapsJsonWireBenchmark-serialize:  746ms, 7177227 bytes
      SdkMapsBufferWireBenchmark-serialize:  633ms, 5122684 bytes
     SdkMapsBuilderWireBenchmark-serialize:  667ms, 4859868 bytes
       LazyMapsJsonWireBenchmark-serialize: 1104ms, 7177227 bytes
     LazyMapsBufferWireBenchmark-serialize:  543ms, 5122684 bytes
 LazyWrappersBufferWireBenchmark-serialize:    0ms, 2111761 bytes
    BuilderMapsJsonWireBenchmark-serialize: 1028ms, 7177227 bytes
 BuilderMapsBuilderWireBenchmark-serialize:    0ms, 2111761 bytes
        SdkMapsJsonWireBenchmark-deserialize: 1249ms
      SdkMapsBufferWireBenchmark-deserialize:    0ms
     SdkMapsBuilderWireBenchmark-deserialize:    0ms
       LazyMapsJsonWireBenchmark-deserialize: 1298ms
     LazyMapsBufferWireBenchmark-deserialize:    0ms
 LazyWrappersBufferWireBenchmark-deserialize:    0ms
    BuilderMapsJsonWireBenchmark-deserialize: 1257ms
 BuilderMapsBuilderWireBenchmark-deserialize:    0ms
        SdkMapsJsonWireBenchmark-process:  151ms, hash 23186292
      SdkMapsBufferWireBenchmark-process:  249ms, hash 23186292
     SdkMapsBuilderWireBenchmark-process:  541ms, hash 23186292
       LazyMapsJsonWireBenchmark-process:  179ms, hash 23186292
     LazyMapsBufferWireBenchmark-process:  251ms, hash 23186292
 LazyWrappersBufferWireBenchmark-process:  367ms, hash 23186292
    BuilderMapsJsonWireBenchmark-process:  207ms, hash 23186292
 BuilderMapsBuilderWireBenchmark-process:  364ms, hash 23186292
        SdkMapsJsonWireBenchmark-total: 3050ms
      SdkMapsBufferWireBenchmark-total: 1593ms
     SdkMapsBuilderWireBenchmark-total: 1921ms
       LazyMapsJsonWireBenchmark-total: 2581ms
     LazyMapsBufferWireBenchmark-total:  794ms
 LazyWrappersBufferWireBenchmark-total:  787ms
    BuilderMapsJsonWireBenchmark-total: 2866ms
 BuilderMapsBuilderWireBenchmark-total:  743ms
```
  • Loading branch information
jakemac53 authored Dec 13, 2024
1 parent 587ff2a commit 4c4adc1
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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:typed_data';

import 'package:dart_model/src/json_buffer/json_buffer_builder.dart';

import 'serialization_benchmark.dart';
Expand All @@ -11,12 +13,12 @@ JsonBufferBuilder? runningBuffer;
/// Benchmark accumulating data directly into a [JsonBufferBuilder].
class BuilderMapsBuilderWireBenchmark extends SerializationBenchmark {
@override
void run() {
createData();

serialized = runningBuffer!.serialize();
Uint8List serialize(Map<String, Object?> data) {
assert(data == runningBuffer!.map);
return runningBuffer!.serialize();
}

@override
Map<String, Object?> createData() {
final buffer = runningBuffer = JsonBufferBuilder();
final map = buffer.map;
Expand Down Expand Up @@ -44,9 +46,8 @@ class BuilderMapsBuilderWireBenchmark extends SerializationBenchmark {
}

@override
void deserialize() {
deserialized = JsonBufferBuilder.deserialize(serialized!).map;
}
Map<String, Object?> deserialize(Uint8List serialized) =>
JsonBufferBuilder.deserialize(serialized).map;

Member _makeMember(String key) {
final intKey = key.length;
Expand Down
10 changes: 4 additions & 6 deletions pkgs/dart_model/benchmark/builder_maps_json_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import 'builder_maps_builder_wire_benchmark.dart';
/// serializing it to JSON.
class BuilderMapsJsonWireBenchmark extends BuilderMapsBuilderWireBenchmark {
@override
void run() {
serialized = json.fuse(utf8).encode(createData()) as Uint8List;
}
Uint8List serialize(Map<String, Object?> data) =>
json.fuse(utf8).encode(data) as Uint8List;

@override
void deserialize() {
deserialized = json.fuse(utf8).decode(serialized!) as Map<String, Object?>;
}
Map<String, Object?> deserialize(Uint8List serialized) =>
json.fuse(utf8).decode(serialized) as Map<String, Object?>;
}
13 changes: 7 additions & 6 deletions pkgs/dart_model/benchmark/lazy_maps_buffer_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
// 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:typed_data';

import 'json_buffer.dart';
import 'serialization_benchmark.dart';

/// Benchmark accumulating data into a [JsonBuffer] via [LazyMap].
class LazyMapsBufferWireBenchmark extends SerializationBenchmark {
@override
void run() {
serialized = JsonBuffer(createData()).serialize();
}
Uint8List serialize(Map<String, Object?> data) =>
JsonBuffer(data).serialize();

@override
LazyMap createData() {
return LazyMap(mapKeys, (key) {
final intKey = int.parse(key);
Expand Down Expand Up @@ -44,9 +46,8 @@ class LazyMapsBufferWireBenchmark extends SerializationBenchmark {
}

@override
void deserialize() {
deserialized = JsonBuffer.deserialize(serialized!).asMap;
}
Map<String, Object?> deserialize(Uint8List serialized) =>
JsonBuffer.deserialize(serialized).asMap;
}

/// An interface.
Expand Down
10 changes: 4 additions & 6 deletions pkgs/dart_model/benchmark/lazy_maps_json_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import 'lazy_maps_buffer_wire_benchmark.dart';
/// serializing it to JSON.
class LazyMapsJsonWireBenchmark extends LazyMapsBufferWireBenchmark {
@override
void run() {
serialized = json.fuse(utf8).encode(createData()) as Uint8List;
}
Uint8List serialize(Map<String, Object?> data) =>
json.fuse(utf8).encode(data) as Uint8List;

@override
void deserialize() {
deserialized = json.fuse(utf8).decode(serialized!) as Map<String, Object?>;
}
Map<String, Object?> deserialize(Uint8List serialized) =>
json.fuse(utf8).decode(serialized) as Map<String, Object?>;
}
22 changes: 11 additions & 11 deletions pkgs/dart_model/benchmark/lazy_wrappers_buffer_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';
import 'dart:typed_data';

import 'package:dart_model/src/json_buffer/json_buffer_builder.dart';

Expand All @@ -15,12 +16,12 @@ JsonBufferBuilder? runningBuffer;
/// extension type).
class LazyWrappersBufferWireBenchmark extends SerializationBenchmark {
@override
void run() {
createData();

serialized = runningBuffer!.serialize();
Uint8List serialize(Map<String, Object?> data) {
assert(data == runningBuffer!.map);
return runningBuffer!.serialize();
}

@override
Map<String, Object?> createData() {
final buffer = runningBuffer = JsonBufferBuilder();
final map = buffer.map;
Expand Down Expand Up @@ -62,13 +63,12 @@ class LazyWrappersBufferWireBenchmark extends SerializationBenchmark {
}

@override
void deserialize() {
deserialized = _LazyMap<Object?, Interface>(
JsonBufferBuilder.deserialize(serialized!).map,
(json) => Interface.fromJson(json as Map<String, Object?>),
(i) => i.toJson(),
);
}
Map<String, Object?> deserialize(Uint8List serialized) =>
_LazyMap<Object?, Interface>(
JsonBufferBuilder.deserialize(serialized).map,
(json) => Interface.fromJson(json as Map<String, Object?>),
(i) => i.toJson(),
);
}

class _LazyMap<From, To> extends MapBase<String, To> {
Expand Down
85 changes: 56 additions & 29 deletions pkgs/dart_model/benchmark/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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:math';

import 'package:collection/collection.dart';

import 'builder_maps_builder_wire_benchmark.dart';
Expand All @@ -15,51 +17,76 @@ import 'regular_dart_classes.dart' as regular;
import 'sdk_maps_buffer_wire_benchmark.dart';
import 'sdk_maps_builder_wire_benchmark.dart';
import 'sdk_maps_json_wire_benchmark.dart';
import 'serialization_benchmark.dart';

void main() {
final sdkMapsJsonWireBenchmark = SdkMapsJsonWireBenchmark();
final lazyMapsBufferWireBenchmark = LazyMapsBufferWireBenchmark();
final lazyWrappersBufferWireBenchmark = LazyWrappersBufferWireBenchmark();
final builderMapsBuilderWireBenchmark = BuilderMapsBuilderWireBenchmark();
final regularClassesBufferWireBenchmark = RegularClassesBufferWireBenchmark();
final serializationBenchmarks = [
sdkMapsJsonWireBenchmark,
SdkMapsJsonWireBenchmark(),
SdkMapsBufferWireBenchmark(),
SdkMapsBuilderWireBenchmark(),
LazyMapsJsonWireBenchmark(),
lazyMapsBufferWireBenchmark,
lazyWrappersBufferWireBenchmark,
LazyMapsBufferWireBenchmark(),
LazyWrappersBufferWireBenchmark(),
BuilderMapsJsonWireBenchmark(),
builderMapsBuilderWireBenchmark,
regularClassesBufferWireBenchmark,
BuilderMapsBuilderWireBenchmark(),
RegularClassesBufferWireBenchmark(),
];

for (var i = 0; i != 3; ++i) {
for (final benchmark in serializationBenchmarks) {
final measure = benchmark.measure().toMilliseconds;
final paddedName = benchmark.name.padLeft(31);
final paddedMeasure = '${measure}ms'.padLeft(6);
// Collects the total measurements from all phases, per benchmark.
final totals = <SerializationBenchmark, int>{
for (var benchmark in serializationBenchmarks) benchmark: 0,
};

for (var stage in BenchmarkStage.values) {
var padding = 0;
for (final benchmark in serializationBenchmarks) {
benchmark.stage = stage;
padding = max(padding, benchmark.name.length);
}

final paddedBytes = '${benchmark.serialized!.length}'.padLeft(7);
print('$paddedName: $paddedMeasure, $paddedBytes bytes');
benchmark.deserialize();
for (final benchmark in serializationBenchmarks) {
final measure = benchmark.measure().toMilliseconds;
totals[benchmark] = totals[benchmark]! + measure;

var buffer =
StringBuffer(benchmark.name.padLeft(padding + 1))
..write(': ')
..write('${measure}ms'.padLeft(6));

switch (stage) {
case BenchmarkStage.serialize:
final paddedBytes = '${benchmark.bytes}'.padLeft(7);
buffer.write(', $paddedBytes bytes');
case BenchmarkStage.process:
buffer.write(', hash ${benchmark.hashResult}');
default:
}
print(buffer.toString());
}
}
print('');

for (final benchmark in [
sdkMapsJsonWireBenchmark.processBenchmark(),
lazyMapsBufferWireBenchmark.processBenchmark(),
lazyWrappersBufferWireBenchmark.processBenchmark(),
builderMapsBuilderWireBenchmark.processBenchmark(),
regularClassesBufferWireBenchmark.processBenchmark(),
]) {
final measure = benchmark.measure().toMilliseconds;
final paddedName = benchmark.name.padLeft(36);
final paddedMeasure = '${measure}ms'.padLeft(6);
// Add up the totals and print them.
{
var padding = 0;
String name(SerializationBenchmark benchmark) =>
'${benchmark.runtimeType}-total';

print('$paddedName: $paddedMeasure, hash ${benchmark.computedResult}');
for (final benchmark in serializationBenchmarks) {
padding = max(padding, name(benchmark).length);
}
for (var benchmark in serializationBenchmarks) {
var buffer =
StringBuffer(name(benchmark).padLeft(padding + 1))
..write(':')
..write('${totals[benchmark]}ms'.padLeft(7));
print(buffer.toString());
}
}

print('');

print('validating benchmark results (this is slow)');
for (final benchmark in serializationBenchmarks.skip(1)) {
var deserialized = benchmark.deserialized;
// Need to unwrap these to compare them as raw maps.
Expand Down
31 changes: 14 additions & 17 deletions pkgs/dart_model/benchmark/regular_dart_classes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,18 @@
// 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:typed_data';

import 'package:dart_model/src/json_buffer/json_buffer_builder.dart';

import 'serialization_benchmark.dart';

JsonBufferBuilder? runningBuffer;

/// Benchmark accumulating data directly into a [JsonBufferBuilder] with an
/// indirection through a thin wrapper type (which is a real type, not an
/// extension type).
/// Benchmark for regular dart classes which serialize and deserializ into
/// a [JsonBufferBuilder].
class RegularClassesBufferWireBenchmark extends SerializationBenchmark {
@override
void run() {
var data = createData();

final buffer = runningBuffer = JsonBufferBuilder();
data.forEach((k, v) => buffer.map[k] = v.toJson());
serialized = runningBuffer!.serialize();
}

/// Creates the data, but its not ready yet to be serialized.
Map<String, Interface> createData() {
final map = <String, Interface>{};
Expand Down Expand Up @@ -62,12 +55,16 @@ class RegularClassesBufferWireBenchmark extends SerializationBenchmark {
}

@override
void deserialize() {
deserialized = JsonBufferBuilder.deserialize(
serialized!,
).map.map<String, Interface>(
(k, v) => MapEntry(k, Interface.fromJson(v as Map<String, Object?>)),
);
Map<String, Object?> deserialize(Uint8List serialized) =>
JsonBufferBuilder.deserialize(serialized).map.map<String, Interface>(
(k, v) => MapEntry(k, Interface.fromJson(v as Map<String, Object?>)),
);

@override
Uint8List serialize(Map<String, Object?> data) {
final buffer = runningBuffer = JsonBufferBuilder();
data.forEach((k, v) => buffer.map[k] = (v as Interface).toJson());
return runningBuffer!.serialize();
}
}

Expand Down
12 changes: 6 additions & 6 deletions pkgs/dart_model/benchmark/sdk_maps_buffer_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
// 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:typed_data';

import 'json_buffer.dart';
import 'sdk_maps_json_wire_benchmark.dart';

/// Benchmark accumulating data into SDK maps then serializing it via
/// [JsonBuffer].
class SdkMapsBufferWireBenchmark extends SdkMapsJsonWireBenchmark {
@override
void run() {
serialized = JsonBuffer(createData()).serialize();
}
Uint8List serialize(Map<String, Object?> data) =>
JsonBuffer(data).serialize();

@override
void deserialize() {
deserialized = JsonBuffer.deserialize(serialized!).asMap;
}
Map<String, Object?> deserialize(Uint8List serialized) =>
JsonBuffer.deserialize(serialized).asMap;
}
13 changes: 7 additions & 6 deletions pkgs/dart_model/benchmark/sdk_maps_builder_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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:typed_data';

import 'package:dart_model/src/json_buffer/json_buffer_builder.dart';

import 'sdk_maps_json_wire_benchmark.dart';
Expand All @@ -10,14 +12,13 @@ import 'sdk_maps_json_wire_benchmark.dart';
/// [JsonBufferBuilder].
class SdkMapsBuilderWireBenchmark extends SdkMapsJsonWireBenchmark {
@override
void run() {
Uint8List serialize(Map<String, Object?> data) {
final builder = JsonBufferBuilder();
builder.map.addAll(createData());
serialized = builder.serialize();
builder.map.addAll(data);
return builder.serialize();
}

@override
void deserialize() {
deserialized = JsonBufferBuilder.deserialize(serialized!).map;
}
Map<String, Object?> deserialize(Uint8List serialized) =>
JsonBufferBuilder.deserialize(serialized).map;
}
10 changes: 5 additions & 5 deletions pkgs/dart_model/benchmark/sdk_maps_json_wire_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import 'serialization_benchmark.dart';
/// Benchmark accumulating data into SDK maps then serializing it to JSON.
class SdkMapsJsonWireBenchmark extends SerializationBenchmark {
@override
void run() {
serialized = json.fuse(utf8).encode(createData()) as Uint8List;
}
Uint8List serialize(Map<String, Object?> data) =>
json.fuse(utf8).encode(data) as Uint8List;

@override
Map<String, Object?> createData() {
return Map<String, Object?>.fromIterable(
mapKeys,
Expand Down Expand Up @@ -53,8 +53,8 @@ class SdkMapsJsonWireBenchmark extends SerializationBenchmark {
}

@override
void deserialize() {
deserialized = json.fuse(utf8).decode(serialized!) as Map<String, Object?>;
Map<String, Object?> deserialize(Uint8List serialized) {
return json.fuse(utf8).decode(serialized) as Map<String, Object?>;
}
}

Expand Down
Loading

0 comments on commit 4c4adc1

Please sign in to comment.