Skip to content

Commit

Permalink
Merge branch 'master' into feat/performance-improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel authored Oct 11, 2024
2 parents 725f521 + ecfe98d commit b21514f
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 32 deletions.
24 changes: 2 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,29 +326,9 @@ class EquatableDateTimeSubclass extends EquatableDateTime {
}
```

## Performance
## Benchmarks

You might be wondering what the performance impact will be if you use `Equatable`.

### Results (average over 10 runs)

#### Equality Comparison A == A

| Class | Runtime (μs) |
| ------------------ | ------------ |
| Manual | 0.193 |
| Empty Equatable | 0.191 |
| Hydrated Equatable | 0.190 |

#### Instantiation A()

| Class | Runtime (μs) |
| ------------------ | ------------ |
| Manual | 0.165 |
| Empty Equatable | 0.181 |
| Hydrated Equatable | 0.182 |

\*_Performance Tests run using: Dart VM version: 2.4.0_
You can see and run performance benchmarks by heading over to [benchmarks](./benchmarks).

## Maintainers

Expand Down
92 changes: 92 additions & 0 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Equatable Benchmarks

Benchmarks used to measure the performance of equality comparisons using `package:equatable`.

## Quick Start

1. Install dependencies
`dart pub get`
1. Run the benchmarks
`dart run main.dart`

## Results

```
EmptyEquatable
total runs: 2 064 037
total time: 2.0000 s
average run: 0 μs
runs/second: Infinity
units: 100
units/second: Infinity
time per unit: 0.0000 μs
PrimitiveEquatable
total runs: 729 555
total time: 2.0000 s
average run: 2 μs
runs/second: 500 000
units: 100
units/second: 50 000 000
time per unit: 0.0200 μs
CollectionEquatable (static, small)
total runs: 51 944
total time: 2.0000 s
average run: 38 μs
runs/second: 26 316
units: 100
units/second: 2 631 579
time per unit: 0.3800 μs
CollectionEquatable (static, medium)
total runs: 44 572
total time: 2.0000 s
average run: 44 μs
runs/second: 22 727
units: 100
units/second: 2 272 727
time per unit: 0.4400 μs
CollectionEquatable (static, large)
total runs: 21 027
total time: 2.0001 s
average run: 95 μs
runs/second: 10 526
units: 100
units/second: 1 052 632
time per unit: 0.9500 μs
CollectionEquatable (dynamic, small)
total runs: 400 934
total time: 2.0000 s
average run: 4 μs
runs/second: 250 000
units: 100
units/second: 25 000 000
time per unit: 0.0400 μs
CollectionEquatable (dynamic, medium)
total runs: 400 408
total time: 2.0000 s
average run: 4 μs
runs/second: 250 000
units: 100
units/second: 25 000 000
time per unit: 0.0400 μs
CollectionEquatable (dynamic, large)
total runs: 400 966
total time: 2.0000 s
average run: 4 μs
runs/second: 250 000
units: 100
units/second: 25 000 000
time per unit: 0.0400 μs
```

_Last Updated: June 3, 2024 using `725b76c9ef072695f3ae4f036c4fa5e015528f13`_

_MacBook Pro (M1 Pro, 16GB RAM)_

Dart SDK version: 3.5.0-218.0.dev (dev) (Mon Jun 3 13:02:57 2024 -0700) on "macos_arm64"
133 changes: 133 additions & 0 deletions benchmarks/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import 'package:benchmarking/benchmarking.dart';
import 'package:equatable/equatable.dart';

class EmptyEquatable extends Equatable {
@override
List<Object> get props => [];
}

class PrimitiveEquatable extends Equatable {
const PrimitiveEquatable({
required this.integer,
required this.string,
required this.boolean,
});

final int integer;
final String string;
final bool boolean;

@override
List<Object> get props => [integer, string, boolean];
}

class CollectionEquatable extends Equatable {
const CollectionEquatable({
required this.list,
required this.map,
required this.set,
});

final List<int> list;
final Map<String, int> map;
final Set<int> set;

@override
List<Object> get props => [list, map, set];
}

void main() {
_runBenchmark('EmptyEquatable', (_) => EmptyEquatable());

_runBenchmark(
'PrimitiveEquatable',
(index) => PrimitiveEquatable(
integer: index,
string: '$index',
boolean: index.isEven,
),
);

_runBenchmark(
'CollectionEquatable (static, small)',
(index) => CollectionEquatable(
list: List.generate(1, (_) => 42),
map: Map.fromEntries(
// ignore: prefer_const_constructors
List.generate(1, (_) => MapEntry('42', 42)),
),
set: Set.from(List.generate(1, (_) => 42)),
),
);

_runBenchmark(
'CollectionEquatable (static, medium)',
(index) => CollectionEquatable(
list: List.generate(10, (_) => 42),
map: Map.fromEntries(
// ignore: prefer_const_constructors
List.generate(10, (_) => MapEntry('42', 42)),
),
set: Set.from(List.generate(10, (_) => 42)),
),
);

_runBenchmark(
'CollectionEquatable (static, large)',
(index) => CollectionEquatable(
list: List.generate(100, (_) => 42),
map: Map.fromEntries(
// ignore: prefer_const_constructors
List.generate(100, (_) => MapEntry('42', 42)),
),
set: Set.from(List.generate(100, (_) => 42)),
),
);

_runBenchmark(
'CollectionEquatable (dynamic, small)',
(index) => CollectionEquatable(
list: List.generate(1, (i) => index + i),
map: Map.fromEntries(
List.generate(1, (i) => MapEntry('${index + i}', index + i)),
),
set: Set.from(List.generate(1, (i) => index + i)),
),
);

_runBenchmark(
'CollectionEquatable (dynamic, medium)',
(index) => CollectionEquatable(
list: List.generate(10, (i) => index + i),
map: Map.fromEntries(
List.generate(10, (i) => MapEntry('${index + i}', index + i)),
),
set: Set.from(List.generate(10, (i) => index + i)),
),
);

_runBenchmark(
'CollectionEquatable (dynamic, large)',
(index) => CollectionEquatable(
list: List.generate(100, (i) => index + i),
map: Map.fromEntries(
List.generate(100, (i) => MapEntry('${index + i}', index + i)),
),
set: Set.from(List.generate(100, (i) => index + i)),
),
);
}

void _runBenchmark(String name, Object Function(int index) create) {
const poolSize = 100;
final pool = List.generate(poolSize, create);
final poolA = [...pool]..shuffle();
final poolB = [...pool]..shuffle();
bool? result; // so that the loop isn't optimized out
syncBenchmark(name, () {
for (var i = 0; i < poolSize; i++) {
result = poolA[i] == poolB[i];
}
}).report(units: poolSize);
assert(result != null, 'result should be defined.');
}
12 changes: 12 additions & 0 deletions benchmarks/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: equatable_benchmarks
publish_to: none

environment:
sdk: ">=2.12.0 <3.0.0"

dependencies:
equatable: ^2.0.0

dev_dependencies:
benchmarking: ^0.6.1
test: ^1.16.0
3 changes: 3 additions & 0 deletions benchmarks/pubspec_overrides.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependency_overrides:
equatable:
path: ../
18 changes: 9 additions & 9 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class Credentials extends Equatable {

class EquatableDateTime extends DateTime with EquatableMixin {
EquatableDateTime(
int year, [
int month = 1,
int day = 1,
int hour = 0,
int minute = 0,
int second = 0,
int millisecond = 0,
int microsecond = 0,
]) : super(year, month, day, hour, minute, second, millisecond, microsecond);
super.year, [
super.month,
super.day,
super.hour,
super.minute,
super.second,
super.millisecond,
super.microsecond,
]);

@override
List<Object> get props {
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: example

environment:
sdk: ">=2.12.0 <3.0.0"
sdk: ">=3.5.0 <4.0.0"

dependencies:
equatable:
Expand Down
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ repository: https://github.com/felangel/equatable
issue_tracker: https://github.com/felangel/equatable/issues
homepage: https://github.com/felangel/equatable
documentation: https://github.com/felangel/equatable
topics: [equality, equals]
funding: [https://github.com/sponsors/felangel]

environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down

0 comments on commit b21514f

Please sign in to comment.