Skip to content

Commit b25fa6a

Browse files
authored
Performance improvements in 1.2.0 (#12)
* Perf improvements in array diff * Fix perf in LCS * Refactor comparison context * Add deep equals to comparison context * Upload new benchmarks * Update release notes for 1.2.0
1 parent 10912bc commit b25fa6a

27 files changed

+1355
-1184
lines changed

Benchmark.md

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,91 @@
1-
# Benchmark
1+
# Benchmarks
22

3-
## Demo JSON object from jsondiffpatch
3+
## Benchmarks with different options
4+
5+
_All benchmarks are generated using the same small JSON object used in the **Newtonsoft Json vs System.Text.Json** section below._
6+
7+
``` ini
8+
9+
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1645 (21H1/May2021Update)
10+
11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
11+
.NET SDK=6.0.200
12+
[Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
13+
Job-ILXIOY : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
14+
15+
16+
```
17+
| Method | Mean | Min | Max | P80 | P95 | Allocated |
18+
|--------- |---------:|---------:|---------:|---------:|---------:|----------:|
19+
| RawText | 112.0 μs | 109.2 μs | 115.2 μs | 112.8 μs | 114.2 μs | 77 KB |
20+
| Semantic | 116.1 μs | 113.8 μs | 121.7 μs | 117.0 μs | 119.3 μs | 76 KB |
21+
22+
23+
## Newtonsoft Json vs System.Text.Json
24+
25+
_All benchmarks for `*_SystemTextJson` methods are generated with `JsonElementComparison.Semantic` option._
26+
27+
### Small JSON object
428

529
``` ini
630

7-
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1586 (21H1/May2021Update)
31+
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1645 (21H1/May2021Update)
832
11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
933
.NET SDK=6.0.200
1034
[Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
11-
DefaultJob : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
35+
Job-HEQUNO : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
1236

1337

1438
```
15-
| Method | Mean | Min | Max | P95 | P80 | Allocated |
16-
|----------------------------------- |----------:|----------:|----------:|----------:|----------:|----------:|
17-
| Diff_JsonNet | 170.86 μs | 112.81 μs | 250.44 μs | 242.28 μs | 222.06 μs | 132 KB |
18-
| Diff_SystemTextJson | 161.13 μs | 110.60 μs | 272.51 μs | 245.99 μs | 194.82 μs | 70 KB |
19-
| Diff_SystemTextJson_Semantic | 188.61 μs | 121.51 μs | 312.77 μs | 243.53 μs | 223.13 μs | 77 KB |
20-
| Diff_JsonNet_Rfc | 188.54 μs | 143.31 μs | 305.56 μs | 276.16 μs | 231.28 μs | 150 KB |
21-
| Diff_SystemTextJson_Rfc | 181.22 μs | 107.66 μs | 287.07 μs | 248.40 μs | 223.91 μs | 92 KB |
22-
| Patch_JsonNet | 205.86 μs | 123.47 μs | 319.94 μs | 277.28 μs | 242.98 μs | 162 KB |
23-
| Patch_SystemTextJson | 78.75 μs | 54.53 μs | 113.21 μs | 98.50 μs | 88.62 μs | 37 KB |
24-
| DeepEquals_JsonNet | 122.18 μs | 82.64 μs | 196.77 μs | 169.75 μs | 148.24 μs | 91 KB |
25-
| DeepEquals_SystemTextJson | 89.19 μs | 55.40 μs | 151.38 μs | 123.07 μs | 116.02 μs | 39 KB |
26-
| DeepEquals_SystemTextJson_Semantic | 119.93 μs | 79.38 μs | 189.04 μs | 173.98 μs | 150.50 μs | 46 KB |
27-
| DeepClone_JsonNet | 89.48 μs | 51.36 μs | 136.46 μs | 121.85 μs | 104.55 μs | 70 KB |
28-
| DeepClone_SystemTextJson | 64.91 μs | 38.96 μs | 97.91 μs | 87.33 μs | 77.57 μs | 45 KB |
29-
30-
31-
## Large JSON object
39+
| Method | Mean | Min | Max | P80 | P95 | Allocated |
40+
|-------------------------- |----------:|----------:|----------:|----------:|----------:|----------:|
41+
| Diff_JsonNet | 109.05 μs | 105.82 μs | 119.70 μs | 111.81 μs | 115.36 μs | 132 KB |
42+
| Diff_SystemTextJson | 88.99 μs | 87.03 μs | 90.95 μs | 89.82 μs | 90.78 μs | 66 KB |
43+
| Patch_JsonNet | 115.06 μs | 112.71 μs | 126.55 μs | 115.31 μs | 117.95 μs | 162 KB |
44+
| Patch_SystemTextJson | 41.39 μs | 40.67 μs | 42.67 μs | 41.62 μs | 42.03 μs | 35 KB |
45+
| DeepEquals_JsonNet | 70.90 μs | 68.80 μs | 74.54 μs | 71.31 μs | 72.68 μs | 91 KB |
46+
| DeepEquals_SystemTextJson | 63.46 μs | 61.45 μs | 66.30 μs | 64.26 μs | 64.70 μs | 39 KB |
47+
| DeepClone_JsonNet | 49.64 μs | 48.66 μs | 50.77 μs | 50.05 μs | 50.39 μs | 70 KB |
48+
| DeepClone_SystemTextJson | 34.90 μs | 33.38 μs | 38.59 μs | 36.32 μs | 37.19 μs | 40 KB |
49+
50+
51+
### Large JSON object
3252

3353
``` ini
3454

35-
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1586 (21H1/May2021Update)
55+
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1645 (21H1/May2021Update)
3656
11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
3757
.NET SDK=6.0.200
3858
[Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
39-
DefaultJob : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
59+
Job-BZNWDS : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
4060

4161

4262
```
43-
| Method | Mean | Min | Max | P95 | P80 | Allocated |
44-
|----------------------------------- |----------:|---------:|----------:|----------:|----------:|----------:|
45-
| Diff_JsonNet | 6.825 ms | 4.746 ms | 13.074 ms | 11.310 ms | 9.284 ms | 4 MB |
46-
| Diff_SystemTextJson | 5.898 ms | 4.996 ms | 7.424 ms | 6.910 ms | 6.329 ms | 3 MB |
47-
| Diff_SystemTextJson_Semantic | 6.466 ms | 4.683 ms | 10.261 ms | 8.130 ms | 7.464 ms | 4 MB |
48-
| Diff_JsonNet_Rfc | 12.654 ms | 8.208 ms | 17.506 ms | 15.528 ms | 14.234 ms | 6 MB |
49-
| Diff_SystemTextJson_Rfc | 10.018 ms | 6.678 ms | 16.484 ms | 13.998 ms | 11.816 ms | 5 MB |
50-
| Patch_JsonNet | 9.128 ms | 5.115 ms | 14.050 ms | 11.422 ms | 10.736 ms | 5 MB |
51-
| Patch_SystemTextJson | 3.772 ms | 2.576 ms | 5.572 ms | 4.933 ms | 4.421 ms | 2 MB |
52-
| DeepEquals_JsonNet | 4.549 ms | 3.280 ms | 6.667 ms | 6.059 ms | 5.529 ms | 2 MB |
53-
| DeepEquals_SystemTextJson | 3.673 ms | 2.321 ms | 6.153 ms | 5.028 ms | 4.303 ms | 2 MB |
54-
| DeepEquals_SystemTextJson_Semantic | 4.630 ms | 2.824 ms | 7.049 ms | 6.303 ms | 5.708 ms | 2 MB |
55-
| DeepClone_JsonNet | 3.294 ms | 2.014 ms | 5.439 ms | 4.518 ms | 4.190 ms | 2 MB |
56-
| DeepClone_SystemTextJson | 1.761 ms | 1.475 ms | 2.107 ms | 2.000 ms | 1.927 ms | 2 MB |
57-
58-
59-
## `DeepEquals` benchmarks
63+
| Method | Mean | Min | Max | P80 | P95 | Allocated |
64+
|-------------------------- |---------:|---------:|---------:|---------:|---------:|----------:|
65+
| Diff_JsonNet | 5.534 ms | 4.986 ms | 6.186 ms | 5.732 ms | 6.008 ms | 4 MB |
66+
| Diff_SystemTextJson | 5.026 ms | 4.725 ms | 5.229 ms | 5.124 ms | 5.216 ms | 3 MB |
67+
| Patch_JsonNet | 5.998 ms | 5.342 ms | 6.634 ms | 6.171 ms | 6.541 ms | 5 MB |
68+
| Patch_SystemTextJson | 2.603 ms | 2.276 ms | 2.965 ms | 2.720 ms | 2.934 ms | 2 MB |
69+
| DeepEquals_JsonNet | 2.986 ms | 2.684 ms | 3.512 ms | 3.252 ms | 3.307 ms | 2 MB |
70+
| DeepEquals_SystemTextJson | 2.461 ms | 2.348 ms | 2.644 ms | 2.514 ms | 2.620 ms | 2 MB |
71+
| DeepClone_JsonNet | 2.029 ms | 1.991 ms | 2.067 ms | 2.047 ms | 2.061 ms | 2 MB |
72+
| DeepClone_SystemTextJson | 1.522 ms | 1.484 ms | 1.576 ms | 1.538 ms | 1.562 ms | 2 MB |
73+
74+
75+
### `DeepEquals`
6076

6177
``` ini
6278

63-
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1586 (21H1/May2021Update)
79+
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1645 (21H1/May2021Update)
6480
11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
6581
.NET SDK=6.0.200
6682
[Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
67-
DefaultJob : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
83+
Job-MDGOSR : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT
6884

6985

7086
```
71-
| Method | Mean | Min | Max | P95 | P80 | Allocated |
72-
|-------------------------- |-----------:|-----------:|-----------:|-----------:|-----------:|----------:|
73-
| JsonNet_Array | 1,198.9 ns | 907.5 ns | 1,704.5 ns | 1,557.5 ns | 1,349.9 ns | 1,248 B |
74-
| JsonNet_ParseArray | 2,879.1 ns | 2,216.4 ns | 3,697.3 ns | 3,361.4 ns | 3,124.2 ns | 5,920 B |
75-
| SystemTextJson_Array | 857.1 ns | 643.5 ns | 1,312.3 ns | 1,183.3 ns | 1,033.4 ns | 864 B |
76-
| SystemTextJson_ParseArray | 2,141.7 ns | 2,027.8 ns | 2,188.0 ns | 2,184.4 ns | 2,159.7 ns | 1,264 B |
87+
| Method | Mean | Min | Max | P80 | P95 | Allocated |
88+
|--------------- |---------:|---------:|---------:|---------:|---------:|----------:|
89+
| JsonNet | 17.22 μs | 16.87 μs | 17.73 μs | 17.37 μs | 17.48 μs | 23 KB |
90+
| SystemTextJson | 16.76 μs | 16.44 μs | 17.07 μs | 16.87 μs | 16.99 μs | 10 KB |
7791

ReleaseNotes.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
# Release Notes
22

3+
## 1.2.0
4+
5+
- Major performance improvement in array comparion
6+
- Performance improvements in `DeepEquals` and `JsonValueComparer`
7+
- **[BREAKING CHANGE]** Breaking changes in array comparison:
8+
- Removed `JsonDiffOptions.PreferFuzzyArrayItemMatch` option
9+
- `JsonDiffOptions.ArrayItemMatcher` is only invoked when array items are not deeply equal
10+
- **[BREAKING CHANGE]** Base64 encoded text is considered as long text if length is greater than or equal to `JsonDiffOptions.TextDiffMinLength`
11+
312
## 1.1.0
13+
414
- Added `JsonValueComparer` that implements semantic comparison of two `JsonValue` objects (including the ones backed by `JsonElement`)
515
- **[BREAKING CHANGE]** `Diff` method no longer uses `object.Equals` to compare values encapsulated in `JsonValue<T>`. `JsonValueComparer` is used instead
616
- Added semantic equality to `DeepEquals` method
717
- Added options to `JsonDiffOptions` to enable semantic diff
818
- Added `JsonDiffPatcher.DefaultOptions` for customizing default diff options
919

1020
## 1.0.0
21+
1122
- Initial release

src/Directory.Build.props

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@
99
</PropertyGroup>
1010

1111
<PropertyGroup>
12+
<JsonDiffPatchPackageVersion>1.2.0</JsonDiffPatchPackageVersion>
1213
<Authors>Wei Chen</Authors>
1314
<PackageProjectUrl>https://github.com/weichch/system-text-json-jsondiffpatch</PackageProjectUrl>
1415
<Copyright>Copyright © Wei Chen 2022</Copyright>
1516
<PackageIcon>icon.png</PackageIcon>
1617
<PackageLicenseFile>LICENSE</PackageLicenseFile>
18+
<PackageReleaseNotes>https://github.com/weichch/system-text-json-jsondiffpatch/blob/$(JsonDiffPatchPackageVersion)/ReleaseNotes.md</PackageReleaseNotes>
1719
</PropertyGroup>
1820

1921
<PropertyGroup>
20-
<Version>1.1.0</Version>
22+
<Version>$(JsonDiffPatchPackageVersion)</Version>
2123
<AssemblyVersion>1.0.0.0</AssemblyVersion>
2224
<FileVersion>1.0.0.0</FileVersion>
2325
</PropertyGroup>

src/SystemTextJson.JsonDiffPatch/Diffs/ArrayItemMatchContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public ArrayItemMatchContext(JsonNode? left, int leftPos, JsonNode? right, int r
2222
RightPosition = rightPos;
2323
IsDeepEqual = false;
2424
}
25-
25+
2626
/// <summary>
2727
/// Gets the left item.
2828
/// </summary>

src/SystemTextJson.JsonDiffPatch/Diffs/DefaultArrayItemComparer.cs

Lines changed: 0 additions & 87 deletions
This file was deleted.

src/SystemTextJson.JsonDiffPatch/Diffs/JsonDiffOptions.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,6 @@ public class JsonDiffOptions
4242
/// </summary>
4343
public bool ArrayObjectItemMatchByPosition { get; set; }
4444

45-
/// <summary>
46-
/// Gets or sets whether to prefer <see cref="ArrayObjectItemKeyFinder"/> and
47-
/// <see cref="ArrayObjectItemMatchByPosition"/> than using deep value comparison
48-
/// to match array object items. By settings this property to <c>true</c>,
49-
/// a diff could be returned faster but larger in size. Default value is <c>false</c>.
50-
/// </summary>
51-
public bool PreferFuzzyArrayItemMatch { get; set; }
52-
5345
/// <summary>
5446
/// Gets or sets the minimum length for diffing texts using <see cref="TextDiffProvider"/>
5547
/// or default text diffing algorithm, aka Google's diff-match-patch algorithm. When text

0 commit comments

Comments
 (0)