Skip to content

Commit 827c68b

Browse files
committed
reduce to fastcloner vs deepcloner
1 parent 569821e commit 827c68b

39 files changed

+1730
-6575
lines changed

benchmarks/DeepCloneBenchmarks.cs

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using BenchmarkDotNet.Attributes;
44
using BenchmarkDotNet.Configs;
55
using BenchmarkDotNet.Order;
6-
using Foundatio.Utility;
76
using DeepClonerExt = Foundatio.Force.DeepCloner.DeepClonerExtensions;
87
using FastClonerExt = Foundatio.Utility.ObjectExtensions;
98

@@ -24,54 +23,35 @@ namespace Foundatio.Benchmarks;
2423
[CategoriesColumn]
2524
public class DeepCloneBenchmarks
2625
{
27-
// Small objects - typical cache entries
2826
private SmallObject _smallObject;
2927
private SmallObjectWithCollections _smallObjectWithCollections;
30-
31-
// Medium objects - typical queue messages
3228
private MediumNestedObject _mediumNestedObject;
3329
private FileSpec _fileSpec;
34-
35-
// Large objects - ~10MB realistic data
3630
private LargeEventDocument _largeEventDocument;
3731
private LargeLogBatch _largeLogBatch;
38-
39-
// Dynamic type objects - object properties with various runtime types
4032
private ObjectWithDynamicProperties _dynamicWithDictionary;
4133
private ObjectWithDynamicProperties _dynamicWithNestedObject;
4234
private ObjectWithDynamicProperties _dynamicWithArray;
43-
44-
// Arrays and collections
4535
private string[] _stringArray;
4636
private List<MediumNestedObject> _objectList;
4737
private Dictionary<string, LargeEventDocument> _objectDictionary;
4838

49-
// Seed for deterministic data generation
5039
private const int Seed = 42;
5140

5241
[GlobalSetup]
5342
public void Setup()
5443
{
5544
var random = new Random(Seed);
5645

57-
// Small objects
5846
_smallObject = CreateSmallObject(random);
5947
_smallObjectWithCollections = CreateSmallObjectWithCollections(random);
60-
61-
// Medium objects
6248
_mediumNestedObject = CreateMediumNestedObject(random);
6349
_fileSpec = CreateFileSpec(random);
64-
65-
// Large objects (~10MB each)
6650
_largeEventDocument = CreateLargeEventDocument(random, targetSizeBytes: 10 * 1024 * 1024);
6751
_largeLogBatch = CreateLargeLogBatch(random, targetSizeBytes: 10 * 1024 * 1024);
68-
69-
// Dynamic type objects
7052
_dynamicWithDictionary = CreateDynamicWithDictionary(random);
7153
_dynamicWithNestedObject = CreateDynamicWithNestedObject(random);
7254
_dynamicWithArray = CreateDynamicWithArray(random);
73-
74-
// Arrays and collections
7555
_stringArray = CreateStringArray(random, 1000);
7656
_objectList = CreateObjectList(random, 100);
7757
_objectDictionary = CreateObjectDictionary(random, 50);
@@ -86,10 +66,6 @@ public void Setup()
8666
[BenchmarkCategory("SmallObject")]
8767
public SmallObject FastCloner_SmallObject() => FastClonerExt.DeepClone(_smallObject);
8868

89-
[Benchmark]
90-
[BenchmarkCategory("SmallObject")]
91-
public SmallObject FastClonerGenerated_SmallObject() => FastClonerExt.DeepCloneGenerated(_smallObject);
92-
9369
// ========== SmallObjectWithCollections ==========
9470
[Benchmark(Baseline = true)]
9571
[BenchmarkCategory("SmallObjectWithCollections")]
@@ -99,10 +75,6 @@ public void Setup()
9975
[BenchmarkCategory("SmallObjectWithCollections")]
10076
public SmallObjectWithCollections FastCloner_SmallObjectWithCollections() => FastClonerExt.DeepClone(_smallObjectWithCollections);
10177

102-
[Benchmark]
103-
[BenchmarkCategory("SmallObjectWithCollections")]
104-
public SmallObjectWithCollections FastClonerGenerated_SmallObjectWithCollections() => FastClonerExt.DeepCloneGenerated(_smallObjectWithCollections);
105-
10678
// ========== MediumNestedObject ==========
10779
[Benchmark(Baseline = true)]
10880
[BenchmarkCategory("MediumNestedObject")]
@@ -112,10 +84,6 @@ public void Setup()
11284
[BenchmarkCategory("MediumNestedObject")]
11385
public MediumNestedObject FastCloner_MediumNestedObject() => FastClonerExt.DeepClone(_mediumNestedObject);
11486

115-
[Benchmark]
116-
[BenchmarkCategory("MediumNestedObject")]
117-
public MediumNestedObject FastClonerGenerated_MediumNestedObject() => FastClonerExt.DeepCloneGenerated(_mediumNestedObject);
118-
11987
// ========== FileSpec ==========
12088
[Benchmark(Baseline = true)]
12189
[BenchmarkCategory("FileSpec")]
@@ -125,10 +93,6 @@ public void Setup()
12593
[BenchmarkCategory("FileSpec")]
12694
public FileSpec FastCloner_FileSpec() => FastClonerExt.DeepClone(_fileSpec);
12795

128-
[Benchmark]
129-
[BenchmarkCategory("FileSpec")]
130-
public FileSpec FastClonerGenerated_FileSpec() => FastClonerExt.DeepCloneGenerated(_fileSpec);
131-
13296
// ========== LargeEventDocument_10MB ==========
13397
[Benchmark(Baseline = true)]
13498
[BenchmarkCategory("LargeEventDocument")]
@@ -138,10 +102,6 @@ public void Setup()
138102
[BenchmarkCategory("LargeEventDocument")]
139103
public LargeEventDocument FastCloner_LargeEventDocument_10MB() => FastClonerExt.DeepClone(_largeEventDocument);
140104

141-
[Benchmark]
142-
[BenchmarkCategory("LargeEventDocument")]
143-
public LargeEventDocument FastClonerGenerated_LargeEventDocument_10MB() => FastClonerExt.DeepCloneGenerated(_largeEventDocument);
144-
145105
// ========== LargeLogBatch_10MB ==========
146106
[Benchmark(Baseline = true)]
147107
[BenchmarkCategory("LargeLogBatch")]
@@ -151,10 +111,6 @@ public void Setup()
151111
[BenchmarkCategory("LargeLogBatch")]
152112
public LargeLogBatch FastCloner_LargeLogBatch_10MB() => FastClonerExt.DeepClone(_largeLogBatch);
153113

154-
[Benchmark]
155-
[BenchmarkCategory("LargeLogBatch")]
156-
public LargeLogBatch FastClonerGenerated_LargeLogBatch_10MB() => FastClonerExt.DeepCloneGenerated(_largeLogBatch);
157-
158114
// ========== DynamicWithDictionary ==========
159115
[Benchmark(Baseline = true)]
160116
[BenchmarkCategory("DynamicWithDictionary")]
@@ -164,10 +120,6 @@ public void Setup()
164120
[BenchmarkCategory("DynamicWithDictionary")]
165121
public ObjectWithDynamicProperties FastCloner_DynamicWithDictionary() => FastClonerExt.DeepClone(_dynamicWithDictionary);
166122

167-
[Benchmark]
168-
[BenchmarkCategory("DynamicWithDictionary")]
169-
public ObjectWithDynamicProperties FastClonerGenerated_DynamicWithDictionary() => FastClonerExt.DeepCloneGenerated(_dynamicWithDictionary);
170-
171123
// ========== DynamicWithNestedObject ==========
172124
[Benchmark(Baseline = true)]
173125
[BenchmarkCategory("DynamicWithNestedObject")]
@@ -177,10 +129,6 @@ public void Setup()
177129
[BenchmarkCategory("DynamicWithNestedObject")]
178130
public ObjectWithDynamicProperties FastCloner_DynamicWithNestedObject() => FastClonerExt.DeepClone(_dynamicWithNestedObject);
179131

180-
[Benchmark]
181-
[BenchmarkCategory("DynamicWithNestedObject")]
182-
public ObjectWithDynamicProperties FastClonerGenerated_DynamicWithNestedObject() => FastClonerExt.DeepCloneGenerated(_dynamicWithNestedObject);
183-
184132
// ========== DynamicWithArray ==========
185133
[Benchmark(Baseline = true)]
186134
[BenchmarkCategory("DynamicWithArray")]
@@ -190,10 +138,6 @@ public void Setup()
190138
[BenchmarkCategory("DynamicWithArray")]
191139
public ObjectWithDynamicProperties FastCloner_DynamicWithArray() => FastClonerExt.DeepClone(_dynamicWithArray);
192140

193-
[Benchmark]
194-
[BenchmarkCategory("DynamicWithArray")]
195-
public ObjectWithDynamicProperties FastClonerGenerated_DynamicWithArray() => FastClonerExt.DeepCloneGenerated(_dynamicWithArray);
196-
197141
// ========== StringArray_1000 ==========
198142
[Benchmark(Baseline = true)]
199143
[BenchmarkCategory("StringArray")]
@@ -203,10 +147,6 @@ public void Setup()
203147
[BenchmarkCategory("StringArray")]
204148
public string[] FastCloner_StringArray_1000() => FastClonerExt.DeepClone(_stringArray);
205149

206-
[Benchmark]
207-
[BenchmarkCategory("StringArray")]
208-
public string[] FastClonerGenerated_StringArray_1000() => FastClonerExt.DeepCloneGenerated(_stringArray);
209-
210150
// ========== ObjectList_100 ==========
211151
[Benchmark(Baseline = true)]
212152
[BenchmarkCategory("ObjectList")]
@@ -216,10 +156,6 @@ public void Setup()
216156
[BenchmarkCategory("ObjectList")]
217157
public List<MediumNestedObject> FastCloner_ObjectList_100() => FastClonerExt.DeepClone(_objectList);
218158

219-
[Benchmark]
220-
[BenchmarkCategory("ObjectList")]
221-
public List<MediumNestedObject> FastClonerGenerated_ObjectList_100() => FastClonerExt.DeepCloneGenerated(_objectList);
222-
223159
// ========== ObjectDictionary_50 ==========
224160
[Benchmark(Baseline = true)]
225161
[BenchmarkCategory("ObjectDictionary")]
@@ -229,10 +165,6 @@ public void Setup()
229165
[BenchmarkCategory("ObjectDictionary")]
230166
public Dictionary<string, LargeEventDocument> FastCloner_ObjectDictionary_50() => FastClonerExt.DeepClone(_objectDictionary);
231167

232-
[Benchmark]
233-
[BenchmarkCategory("ObjectDictionary")]
234-
public Dictionary<string, LargeEventDocument> FastClonerGenerated_ObjectDictionary_50() => FastClonerExt.DeepCloneGenerated(_objectDictionary);
235-
236168
private static SmallObject CreateSmallObject(Random random)
237169
{
238170
return new SmallObject
@@ -301,14 +233,8 @@ private static FileSpec CreateFileSpec(Random random)
301233

302234
private static LargeEventDocument CreateLargeEventDocument(Random random, int targetSizeBytes)
303235
{
304-
// For 10MB target: Create extended data entries with large strings
305-
// Each char in .NET is 2 bytes, plus string object overhead (~26 bytes)
306-
// We want the cloned object to be ~10MB
307-
308236
var stackFrameCount = 100;
309237
var extendedDataCount = 200;
310-
// Calculate string length to achieve target size
311-
// Each string entry: ~50KB of chars = 25K chars
312238
var extendedDataStringLength = Math.Max(100, targetSizeBytes / extendedDataCount / 2);
313239

314240
var stackFrames = new List<StackFrameInfo>(stackFrameCount);
@@ -389,8 +315,6 @@ private static LargeEventDocument CreateLargeEventDocument(Random random, int ta
389315

390316
private static LargeLogBatch CreateLargeLogBatch(Random random, int targetSizeBytes)
391317
{
392-
// Each log entry is roughly 2000-5000 bytes
393-
// Target ~10MB total
394318
var entryCount = targetSizeBytes / 3000;
395319

396320
var entries = new List<LogEntry>(entryCount);
@@ -497,15 +421,13 @@ private static Dictionary<string, LargeEventDocument> CreateObjectDictionary(Ran
497421
var dict = new Dictionary<string, LargeEventDocument>(count);
498422
for (int i = 0; i < count; i++)
499423
{
500-
// Create medium-sized event documents for the dictionary (~10KB each)
501424
dict[$"event_{i}"] = CreateMediumEventDocument(random);
502425
}
503426
return dict;
504427
}
505428

506429
private static LargeEventDocument CreateMediumEventDocument(Random random)
507430
{
508-
// Create a medium-sized event document (~10KB) for collection benchmarks
509431
var stackFrames = new List<StackFrameInfo>(5);
510432
for (int i = 0; i < 5; i++)
511433
{
@@ -614,9 +536,6 @@ private static Dictionary<string, string> GenerateStringDictionary(Random random
614536
}
615537
}
616538

617-
/// <summary>
618-
/// Small object representing a typical cache entry.
619-
/// </summary>
620539
public class SmallObject
621540
{
622541
public int Id { get; set; }
@@ -626,9 +545,6 @@ public class SmallObject
626545
public double Score { get; set; }
627546
}
628547

629-
/// <summary>
630-
/// Small object with collections - typical for configuration or metadata caching.
631-
/// </summary>
632548
public class SmallObjectWithCollections
633549
{
634550
public int Id { get; set; }
@@ -637,9 +553,6 @@ public class SmallObjectWithCollections
637553
public Dictionary<string, string> Metadata { get; set; }
638554
}
639555

640-
/// <summary>
641-
/// Medium-sized nested object representing a typical queue message or event.
642-
/// </summary>
643556
public class MediumNestedObject
644557
{
645558
public Guid Id { get; set; }
@@ -654,9 +567,6 @@ public class MediumNestedObject
654567
public RequestInfo Request { get; set; }
655568
}
656569

657-
/// <summary>
658-
/// File specification - used in InMemoryFileStorage.
659-
/// </summary>
660570
public class FileSpec
661571
{
662572
public string Path { get; set; }
@@ -666,9 +576,6 @@ public class FileSpec
666576
public Dictionary<string, string> Data { get; set; }
667577
}
668578

669-
/// <summary>
670-
/// User information - common nested object in events.
671-
/// </summary>
672579
public class UserInfo
673580
{
674581
public string Id { get; set; }
@@ -677,9 +584,6 @@ public class UserInfo
677584
public List<string> Roles { get; set; }
678585
}
679586

680-
/// <summary>
681-
/// HTTP request information - common in error tracking systems.
682-
/// </summary>
683587
public class RequestInfo
684588
{
685589
public string Method { get; set; }
@@ -690,9 +594,6 @@ public class RequestInfo
690594
public string UserAgent { get; set; }
691595
}
692596

693-
/// <summary>
694-
/// Stack frame information for error tracking.
695-
/// </summary>
696597
public class StackFrameInfo
697598
{
698599
public string FileName { get; set; }
@@ -705,9 +606,6 @@ public class StackFrameInfo
705606
public Dictionary<string, string> LocalVariables { get; set; }
706607
}
707608

708-
/// <summary>
709-
/// Environment information for error tracking.
710-
/// </summary>
711609
public class EnvironmentInfo
712610
{
713611
public string MachineName { get; set; }
@@ -724,10 +622,6 @@ public class EnvironmentInfo
724622
public Dictionary<string, string> EnvironmentVariables { get; set; }
725623
}
726624

727-
/// <summary>
728-
/// Large event document - represents error/exception events in systems like Exceptionless.
729-
/// Designed to be ~10MB when fully populated.
730-
/// </summary>
731625
public class LargeEventDocument
732626
{
733627
public string Id { get; set; }
@@ -753,9 +647,6 @@ public class LargeEventDocument
753647
public EnvironmentInfo Environment { get; set; }
754648
}
755649

756-
/// <summary>
757-
/// Log entry for batch logging scenarios.
758-
/// </summary>
759650
public class LogEntry
760651
{
761652
public Guid Id { get; set; }
@@ -771,10 +662,6 @@ public class LogEntry
771662
public string ParentSpanId { get; set; }
772663
}
773664

774-
/// <summary>
775-
/// Large log batch - represents a batch of log entries for bulk processing.
776-
/// Designed to be ~10MB when fully populated.
777-
/// </summary>
778665
public class LargeLogBatch
779666
{
780667
public Guid BatchId { get; set; }
@@ -784,10 +671,6 @@ public class LargeLogBatch
784671
public Dictionary<string, string> Metadata { get; set; }
785672
}
786673

787-
/// <summary>
788-
/// Object with dynamic (object) properties to test cloning of unknown types at compile time.
789-
/// This simulates scenarios where JSON deserialization produces Dictionary&lt;string, object&gt; or JToken.
790-
/// </summary>
791674
public class ObjectWithDynamicProperties
792675
{
793676
public int Id { get; set; }
Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
using System.Diagnostics.CodeAnalysis;
2-
using RuntimeFastCloner = Foundatio.FastCloner.Code.FastClonerGenerator;
3-
using GeneratedFastCloner = Foundatio.FastClonerGenerated.Code.FastClonerGenerator;
42

53
namespace Foundatio.Utility;
64

@@ -9,12 +7,6 @@ public static class ObjectExtensions
97
[return: NotNullIfNotNull(nameof(original))]
108
public static T? DeepClone<T>(this T? original)
119
{
12-
return RuntimeFastCloner.CloneObject(original);
13-
}
14-
15-
[return: NotNullIfNotNull(nameof(original))]
16-
public static T? DeepCloneGenerated<T>(this T? original)
17-
{
18-
return GeneratedFastCloner.CloneObject(original);
10+
return Foundatio.FastCloner.Code.FastClonerGenerator.CloneObject(original);
1911
}
2012
}

0 commit comments

Comments
 (0)