Skip to content

Investigating: FastCloner as DeepCloner replacement - #444

Closed
niemyjski wants to merge 1 commit into
mainfrom
investigate-fastcloner-replacement
Closed

niemyjski wants to merge 1 commit into
mainfrom
investigate-fastcloner-replacement

Conversation

@niemyjski

Copy link
Copy Markdown
Member

Summary

This PR investigates replacing Force.DeepCloner with FastCloner for our DeepClone() implementation.

Changes

  • Replace Force.DeepCloner with FastCloner v3.4.4 (source imported)
  • Add Update-FastCloner.ps1 script for source import automation
  • Update ObjectExtensions.DeepClone to use FastClonerGenerator
  • Add nullable annotations ([NotNullIfNotNull]) to DeepClone extension method
  • Replace #if MODERN with #if true // MODERN for .NET 8+ targets
  • Add benchmark comparison results

Benchmark Results

Benchmark DeepCloner FastCloner Change
SmallObject 52.93 ns 132 ns +149% slower
FileSpec 299.87 ns 402 ns +34% slower
SmallObjectWithCollections 384.61 ns 490 ns +27% slower
StringArray_1000 470.19 ns 501 ns +7% slower
DynamicWithDictionary 797.00 ns 905 ns +14% slower
MediumNestedObject 1,020.19 ns 1,313 ns +29% slower
DynamicWithNestedObject 1,130.58 ns 1,315 ns +16% slower
DynamicWithArray 3,672.72 ns 3,343 ns -9% faster
LargeEventDocument_10MB 43,718.94 ns 48,415 ns +11% slower
ObjectList_100 110,525.77 ns 120,509 ns +9% slower
ObjectDictionary_50 555,214.24 ns 597,092 ns +8% slower
LargeLogBatch_10MB 3,662,330.45 ns 5,726,243 ns +56% slower

Observations

  1. FastCloner is consistently slower across 11 of 12 benchmarks (7-149% slower)
  2. Only DynamicWithArray showed improvement (9% faster)
  3. Large batch operations show the biggest regression (56% slower for 5MB log batch)
  4. Small objects show the largest relative regression (149% slower)
  5. Memory allocations are similar between the two libraries

Questions

  1. Are the published benchmarks using the source generator (FastDeepClone()) rather than reflection (DeepClone())? The README shows ~25x improvement which we're not seeing with reflection-based cloning.

  2. Is there something specific about ARM64/Apple Silicon that might cause different performance characteristics?

  3. Are there configuration options or usage patterns that would improve performance for complex nested objects with collections?

Test Environment

  • Platform: Apple M1 Max (ARM64), macOS Tahoe 26.2
  • Runtime: .NET 10.0.2 (10.0.2, 10.0.225.61305), Arm64 RyuJIT
  • FastCloner: v3.4.4 (reflection-based, MODERN code paths enabled)
  • BenchmarkDotNet: v0.15.8

Conclusion

Based on these benchmarks, FastCloner does not appear to be a performance improvement over Force.DeepCloner for our use cases. We should either:

  1. Get clarification from the FastCloner maintainer on expected performance characteristics
  2. Investigate the source generator approach if AOT cloning is acceptable
  3. Keep Force.DeepCloner as our current implementation

Note: This is a draft PR for investigation purposes. Do not merge.

@niemyjski

Copy link
Copy Markdown
Member Author

@lofcz - We evaluated FastCloner as a potential replacement for Force.DeepCloner in Foundatio and ran comprehensive benchmarks. Our results show FastCloner's reflection-based DeepClone() is 7-149% slower than Force.DeepCloner across most of our test cases.

Questions:

  1. Are the published benchmarks using the source generator (FastDeepClone()) rather than reflection-based cloning? The README shows ~25x improvement which we're not seeing.

  2. Is there something specific about ARM64/Apple Silicon that might cause different performance characteristics?

  3. Are there configuration options or usage patterns that would improve performance for complex nested objects with collections?

Our benchmark objects include:

  • Simple POCOs with primitives
  • Nested objects with UserInfo, RequestInfo, collections
  • Large error tracking events with stack traces (~155KB)
  • Batch log entries (~5MB with ~3000 entries)
  • Dynamic types with object properties containing Dictionary, nested POCOs, or mixed arrays

The full benchmark code is available in this PR. We'd appreciate any insights on expected performance characteristics or if we're missing something in our usage.

@niemyjski
niemyjski changed the base branch from main to feature/deepclone January 30, 2026 18:07
@niemyjski
niemyjski changed the base branch from feature/deepclone to main January 30, 2026 18:07
state.DecrementDepth();

// if UseWorkList was set during recursive cloning, process the worklist
if (!state.UseWorkList)
List<Expression> expressionList = [];

ParameterExpression from = Expression.Parameter(methodType);
ParameterExpression fromLocal = from;
ParameterExpression from = Expression.Parameter(methodType);
ParameterExpression fromLocal = from;
ParameterExpression to = Expression.Parameter(methodType);
ParameterExpression toLocal = to;
Comment on lines +52 to +59
foreach (KeyValuePair<Type, CloneBehavior> kvp in TypeBehaviors)
{
if (kvp.Value == CloneBehavior.Ignore && FastClonerSafeTypes.DefaultKnownTypes.ContainsKey(kvp.Key))
{
HasSafeTypeOverrides = true;
return;
}
}
Comment on lines +154 to +160
foreach (EventInfo evtInfo in events)
{
if (MemberIsIgnored(evtInfo))
{
details[evtInfo.Name] = evtInfo.EventHandlerType;
}
}
Comment on lines +432 to +438
foreach (EventInfo evtInfo in events)
{
if (MemberIsIgnored(evtInfo))
{
details[evtInfo.Name] = evtInfo.EventHandlerType;
}
}
Comment on lines +160 to +171
foreach (FieldInfo fi in tp.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
Type ft = fi.FieldType;
if (ft == type)
{
return true;
}
if (ft.IsArray && ft.GetElementType() == type)
{
return true;
}
}
Comment on lines +247 to +263
foreach (FieldInfo fieldInfo in GetAllTypeFields(type))
{
Type fieldType = fieldInfo.FieldType;

if (processingTypes.Contains(fieldType))
{
continue;
}

if (CanReturnSameType(fieldType, processingTypes))
{
continue;
}

knownTypes.TryAdd(type, false);
return false;
}
Comment on lines +472 to +486
if (member is FieldInfo fieldInfoForEventCheck && ignoredEventDetails.TryGetValue(fieldInfoForEventCheck.Name, out Type? evtType))
{
if (evtType == memberType)
{
if (canAssignDirect)
{
expressionList.Add(Expression.Assign(
Expression.MakeMemberAccess(toLocal, member),
Expression.Default(memberType)
));
}

continue;
}
}
Comment on lines +522 to +531
else if (member is FieldInfo fi)
{
if (ignoredEventDetails.TryGetValue(fi.Name, out Type? eventHandlerTypeFromCache))
{
if (eventHandlerTypeFromCache == fi.FieldType)
{
shouldBeIgnored = true;
}
}
}
@lofcz

lofcz commented Jan 31, 2026 •

Copy link
Copy Markdown
Contributor

@niemyjski I'll look into your setup and tests. I'm very busy with dayjob for the upcoming two weeks, but if you can keep the PR open, I'll get to this after that. Note that I don't have a MacOS machine available, but if the performance characteristic will show similar results under Windows, I'll work on it. Note that original DeepCloner is doing a lot of things naively, that leads to subtle bugs that surface only with certain usage patterns of the cloned object. Since you are internalizing, I might also strip certain parts of FastCloner to create a "slim" distribution.

@niemyjski

Copy link
Copy Markdown
Member Author

@lofcz no worries, totally understand time commitments and no rush to close this. I appreciate your time and help.

- Replace Force.DeepCloner with FastCloner v3.4.4 (source imported)
- Add Update-FastCloner.ps1 script for source import automation
- Update ObjectExtensions.DeepClone to use FastClonerGenerator
- Add nullable annotations to DeepClone extension method
- Replace #if MODERN with #if true // MODERN for .NET 8+ targets
- Add benchmark comparison results

Benchmark results show FastCloner is 7-149% slower than DeepCloner
for our test cases, contrary to published benchmarks.
@niemyjski
niemyjski force-pushed the investigate-fastcloner-replacement branch from 0711b0c to b85edeb Compare February 6, 2026 21:37
@lofcz

lofcz commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Just a quick update for now, that this is being worked on, progress in https://github.com/lofcz/Foundatio/tree/feat-fast-cloner, will open a new PR once it's done. For now I have both cloners side by side in my branch for reproducible benchmarks.

@lofcz

lofcz commented Mar 3, 2026 •

Copy link
Copy Markdown
Contributor

Quick update - results seem good, at least on my Windows machine. But I'd be surprised if macOS differed much. Need to figure out how to bring this back upstream first, enable "Ultra" mode that disables the features slimmed for Foundatio's build and how to properly generate code for internalization.

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26300.7939)
Intel Core i7-8700 CPU 3.20GHz (Max: 3.19GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.102
  [Host]     : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3
  Job-IJPESX : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3

IterationCount=5  LaunchCount=1  WarmupCount=3 // <-- note that this is low, full precision runs for an hour..

| Method                                | Categories                 | Mean            | Error            | StdDev         | Ratio | RatioSD | Gen0     | Gen1     | Gen2    | Allocated | Alloc Ratio |
|-------------------------------------- |--------------------------- |----------------:|-----------------:|---------------:|------:|--------:|---------:|---------:|--------:|----------:|------------:|
| FastCloner_DynamicWithArray           | DynamicWithArray           |     4,209.09 ns |       503.379 ns |      77.898 ns |  0.52 |    0.10 |   0.9537 |   0.0076 |       - |    6008 B |        0.68 |
| DeepCloner_DynamicWithArray           | DynamicWithArray           |     8,406.90 ns |     7,091.861 ns |   1,841.734 ns |  1.04 |    0.29 |   1.3962 |   0.0229 |       - |    8800 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_DynamicWithDictionary      | DynamicWithDictionary      |     1,321.86 ns |       647.517 ns |     100.204 ns |  0.84 |    0.12 |   0.2651 |        - |       - |    1664 B |        0.61 |
| DeepCloner_DynamicWithDictionary      | DynamicWithDictionary      |     1,588.48 ns |     1,386.457 ns |     214.556 ns |  1.01 |    0.17 |   0.4311 |   0.0019 |       - |    2712 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_DynamicWithNestedObject    | DynamicWithNestedObject    |     1,155.78 ns |       172.854 ns |      26.749 ns |  0.74 |    0.02 |   0.2918 |        - |       - |    1840 B |        0.52 |
| DeepCloner_DynamicWithNestedObject    | DynamicWithNestedObject    |     1,566.68 ns |       148.512 ns |      22.982 ns |  1.00 |    0.02 |   0.5646 |   0.0038 |       - |    3560 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_FileSpec                   | FileSpec                   |       231.15 ns |        33.752 ns |       5.223 ns |  0.54 |    0.01 |   0.0663 |        - |       - |     416 B |        0.45 |
| DeepCloner_FileSpec                   | FileSpec                   |       428.18 ns |        25.398 ns |       3.930 ns |  1.00 |    0.01 |   0.1464 |        - |       - |     920 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_LargeEventDocument_10MB    | LargeEventDocument         |    35,487.81 ns |     4,447.006 ns |   1,154.873 ns |  0.45 |    0.02 |   7.9346 |   0.8545 |       - |   50112 B |        0.39 |
| DeepCloner_LargeEventDocument_10MB    | LargeEventDocument         |    78,126.04 ns |    14,403.120 ns |   2,228.899 ns |  1.00 |    0.04 |  20.6299 |   4.0283 |       - |  129792 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_LargeLogBatch_10MB         | LargeLogBatch              | 5,310,627.81 ns | 1,117,946.138 ns | 290,327.062 ns |  0.57 |    0.03 | 367.1875 | 226.5625 | 62.5000 | 2993234 B |        0.84 |
| DeepCloner_LargeLogBatch_10MB         | LargeLogBatch              | 9,340,684.06 ns | 1,198,884.797 ns | 311,346.575 ns |  1.00 |    0.04 | 484.3750 | 296.8750 | 62.5000 | 3564667 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_MediumNestedObject         | MediumNestedObject         |       978.26 ns |        71.164 ns |      11.013 ns |  0.65 |    0.03 |   0.2670 |        - |       - |    1680 B |        0.49 |
| DeepCloner_MediumNestedObject         | MediumNestedObject         |     1,496.87 ns |       262.514 ns |      68.174 ns |  1.00 |    0.06 |   0.5436 |   0.0038 |       - |    3416 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_ObjectDictionary_50        | ObjectDictionary           |   172,718.54 ns |    26,168.577 ns |   4,049.616 ns |  0.16 |    0.01 |  37.1094 |  11.2305 |       - |  233168 B |        0.42 |
| DeepCloner_ObjectDictionary_50        | ObjectDictionary           | 1,050,157.46 ns |   191,182.882 ns |  49,649.588 ns |  1.00 |    0.06 |  76.1719 |  39.0625 |  7.8125 |  549653 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_ObjectList_100             | ObjectList                 |   110,054.03 ns |     4,760.622 ns |   1,236.318 ns |  0.59 |    0.05 |  26.3672 |   6.9580 |       - |  165784 B |        0.52 |
| DeepCloner_ObjectList_100             | ObjectList                 |   186,597.24 ns |    65,584.427 ns |  17,032.067 ns |  1.01 |    0.12 |  50.7813 |  16.8457 |       - |  318888 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_SmallObject                | SmallObject                |        42.32 ns |         8.577 ns |       1.327 ns |  0.60 |    0.02 |   0.0076 |        - |       - |      48 B |        0.26 |
| DeepCloner_SmallObject                | SmallObject                |        70.44 ns |         5.380 ns |       1.397 ns |  1.00 |    0.03 |   0.0293 |        - |       - |     184 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_SmallObjectWithCollections | SmallObjectWithCollections |       301.94 ns |        14.615 ns |       3.795 ns |  0.43 |    0.01 |   0.0916 |        - |       - |     576 B |        0.53 |
| DeepCloner_SmallObjectWithCollections | SmallObjectWithCollections |       702.77 ns |        89.850 ns |      23.334 ns |  1.00 |    0.04 |   0.1745 |        - |       - |    1096 B |        1.00 |
|                                       |                            |                 |                  |                |       |         |          |          |         |           |             |
| FastCloner_StringArray_1000           | StringArray                |       560.76 ns |       158.421 ns |      24.516 ns |  0.83 |    0.10 |   1.2779 |        - |       - |    8024 B |        0.98 |
| DeepCloner_StringArray_1000           | StringArray                |       686.98 ns |       339.262 ns |      88.105 ns |  1.01 |    0.16 |   1.2999 |   0.0362 |       - |    8160 B |        1.00 |

@lofcz

lofcz commented Mar 3, 2026 •

Copy link
Copy Markdown
Contributor

Quick update, I now have the improvements backported upstream and a new utility that generates builds for internalization of FastCloner is finished. This uses Roslyn and can evaluate preprocessor symbols used by us - allowing to either remap them, or evaluate (eg. our MODERN is simply true in Foundatio, so the dead code is dropped). Minor sacrifices had to be made for the sake of correctness, but still looks good, and the Generated cloner passes all ~800 tests we have.

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26300.7939)
Intel Core i7-8700 CPU 3.20GHz (Max: 3.19GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.102
  [Host]     : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3
  Job-IJPESX : .NET 10.0.2 (10.0.2, 10.0.225.61305), X64 RyuJIT x86-64-v3

IterationCount=5  LaunchCount=1  WarmupCount=3  

| Method                                         | Categories                 | Mean             | Error            | StdDev           | Ratio | RatioSD | Gen0     | Gen1     | Gen2    | Allocated | Alloc Ratio |
|----------------------------------------------- |--------------------------- |-----------------:|-----------------:|-----------------:|------:|--------:|---------:|---------:|--------:|----------:|------------:|
| FastCloner_DynamicWithArray                    | DynamicWithArray           |      5,813.30 ns |     6,063.814 ns |     1,574.753 ns |  0.99 |    0.25 |   0.9537 |   0.0076 |       - |    6008 B |        0.68 |
| DeepCloner_DynamicWithArray                    | DynamicWithArray           |      5,925.25 ns |     2,729.998 ns |       422.470 ns |  1.00 |    0.09 |   1.3962 |   0.0229 |       - |    8800 B |        1.00 |
| FastClonerGenerated_DynamicWithArray           | DynamicWithArray           |      6,409.19 ns |       846.122 ns |       219.735 ns |  1.09 |    0.08 |   0.9537 |   0.0076 |       - |    6008 B |        0.68 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastClonerGenerated_DynamicWithDictionary      | DynamicWithDictionary      |        970.66 ns |       160.009 ns |        24.762 ns |  0.78 |    0.03 |   0.2651 |        - |       - |    1664 B |        0.61 |
| FastCloner_DynamicWithDictionary               | DynamicWithDictionary      |      1,165.39 ns |     1,016.465 ns |       157.299 ns |  0.93 |    0.11 |   0.2651 |        - |       - |    1664 B |        0.61 |
| DeepCloner_DynamicWithDictionary               | DynamicWithDictionary      |      1,247.57 ns |       137.055 ns |        35.593 ns |  1.00 |    0.04 |   0.4311 |   0.0019 |       - |    2712 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastClonerGenerated_DynamicWithNestedObject    | DynamicWithNestedObject    |      1,227.54 ns |       127.891 ns |        19.791 ns |  0.65 |    0.07 |   0.2918 |        - |       - |    1840 B |        0.52 |
| FastCloner_DynamicWithNestedObject             | DynamicWithNestedObject    |      1,289.43 ns |       401.271 ns |       104.209 ns |  0.68 |    0.09 |   0.2918 |        - |       - |    1840 B |        0.52 |
| DeepCloner_DynamicWithNestedObject             | DynamicWithNestedObject    |      1,914.23 ns |       859.106 ns |       223.107 ns |  1.01 |    0.15 |   0.5646 |   0.0038 |       - |    3560 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_FileSpec                            | FileSpec                   |        237.98 ns |        17.312 ns |         4.496 ns |  0.53 |    0.04 |   0.0663 |        - |       - |     416 B |        0.45 |
| FastClonerGenerated_FileSpec                   | FileSpec                   |        269.11 ns |        85.462 ns |        22.194 ns |  0.60 |    0.06 |   0.0663 |        - |       - |     416 B |        0.45 |
| DeepCloner_FileSpec                            | FileSpec                   |        447.15 ns |       133.748 ns |        34.734 ns |  1.00 |    0.10 |   0.1459 |        - |       - |     920 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_LargeEventDocument_10MB             | LargeEventDocument         |     34,861.69 ns |     4,824.717 ns |     1,252.964 ns |  0.50 |    0.02 |   7.9346 |   0.8545 |       - |   50112 B |        0.39 |
| FastClonerGenerated_LargeEventDocument_10MB    | LargeEventDocument         |     35,611.13 ns |     1,679.673 ns |       259.931 ns |  0.51 |    0.01 |   8.0566 |   1.0986 |       - |   50880 B |        0.39 |
| DeepCloner_LargeEventDocument_10MB             | LargeEventDocument         |     69,310.21 ns |     6,187.628 ns |     1,606.907 ns |  1.00 |    0.03 |  20.6299 |   4.0283 |       - |  129792 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_LargeLogBatch_10MB                  | LargeLogBatch              |  5,147,517.77 ns | 1,651,474.501 ns |   255,567.507 ns |  0.47 |    0.05 | 367.1875 | 218.7500 | 62.5000 | 2993232 B |        0.84 |
| FastClonerGenerated_LargeLogBatch_10MB         | LargeLogBatch              |  5,214,198.44 ns |   597,141.796 ns |   155,075.828 ns |  0.48 |    0.05 | 367.1875 | 218.7500 | 62.5000 | 2993483 B |        0.84 |
| DeepCloner_LargeLogBatch_10MB                  | LargeLogBatch              | 11,054,202.19 ns | 4,553,765.728 ns | 1,182,598.501 ns |  1.01 |    0.15 | 484.3750 | 296.8750 | 62.5000 | 3564670 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastClonerGenerated_MediumNestedObject         | MediumNestedObject         |      1,159.87 ns |       517.129 ns |       134.297 ns |  0.52 |    0.06 |   0.2670 |        - |       - |    1680 B |        0.49 |
| FastCloner_MediumNestedObject                  | MediumNestedObject         |      1,269.05 ns |       816.668 ns |       212.086 ns |  0.57 |    0.09 |   0.2670 |        - |       - |    1680 B |        0.49 |
| DeepCloner_MediumNestedObject                  | MediumNestedObject         |      2,224.15 ns |       532.301 ns |       138.237 ns |  1.00 |    0.08 |   0.5436 |   0.0038 |       - |    3416 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_ObjectDictionary_50                 | ObjectDictionary           |    177,222.43 ns |     9,931.593 ns |     2,579.203 ns |  0.16 |    0.00 |  37.1094 |  11.2305 |       - |  233168 B |        0.42 |
| FastClonerGenerated_ObjectDictionary_50        | ObjectDictionary           |    186,210.18 ns |    38,377.616 ns |     9,966.545 ns |  0.17 |    0.01 |  35.4004 |  10.2539 |       - |  223568 B |        0.41 |
| DeepCloner_ObjectDictionary_50                 | ObjectDictionary           |  1,092,449.30 ns |   110,816.656 ns |    28,778.734 ns |  1.00 |    0.03 |  76.1719 |  39.0625 |  7.8125 |  549653 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastClonerGenerated_ObjectList_100             | ObjectList                 |    114,175.20 ns |     6,075.752 ns |     1,577.854 ns |  0.69 |    0.02 |  26.3672 |   7.3242 |       - |  165720 B |        0.52 |
| FastCloner_ObjectList_100                      | ObjectList                 |    118,679.80 ns |     8,062.871 ns |     2,093.902 ns |  0.72 |    0.03 |  26.3672 |   7.0801 |       - |  165784 B |        0.52 |
| DeepCloner_ObjectList_100                      | ObjectList                 |    165,527.96 ns |    40,553.032 ns |     6,275.627 ns |  1.00 |    0.05 |  50.7813 |  16.8457 |       - |  318888 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_SmallObject                         | SmallObject                |         40.10 ns |         2.455 ns |         0.380 ns |  0.57 |    0.01 |   0.0076 |        - |       - |      48 B |        0.26 |
| FastClonerGenerated_SmallObject                | SmallObject                |         56.29 ns |         2.954 ns |         0.767 ns |  0.81 |    0.01 |   0.0076 |        - |       - |      48 B |        0.26 |
| DeepCloner_SmallObject                         | SmallObject                |         69.81 ns |         3.598 ns |         0.934 ns |  1.00 |    0.02 |   0.0293 |        - |       - |     184 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_SmallObjectWithCollections          | SmallObjectWithCollections |        337.32 ns |       183.386 ns |        47.625 ns |  0.59 |    0.08 |   0.0916 |        - |       - |     576 B |        0.53 |
| FastClonerGenerated_SmallObjectWithCollections | SmallObjectWithCollections |        348.10 ns |        62.316 ns |        16.183 ns |  0.61 |    0.04 |   0.0916 |        - |       - |     576 B |        0.53 |
| DeepCloner_SmallObjectWithCollections          | SmallObjectWithCollections |        570.44 ns |       107.813 ns |        27.999 ns |  1.00 |    0.06 |   0.1745 |        - |       - |    1096 B |        1.00 |
|                                                |                            |                  |                  |                  |       |         |          |          |         |           |             |
| FastCloner_StringArray_1000                    | StringArray                |        612.44 ns |       144.210 ns |        37.451 ns |  0.82 |    0.17 |   1.2779 |        - |       - |    8024 B |        0.98 |
| FastClonerGenerated_StringArray_1000           | StringArray                |        626.36 ns |       371.226 ns |        96.406 ns |  0.83 |    0.21 |   1.2779 |        - |       - |    8024 B |        0.98 |
| DeepCloner_StringArray_1000                    | StringArray                |        783.26 ns |       699.819 ns |       181.741 ns |  1.04 |    0.31 |   1.2999 |   0.0362 |       - |    8160 B |        1.00 |

@lofcz lofcz mentioned this pull request Mar 4, 2026
6 tasks done
@niemyjski niemyjski closed this Mar 9, 2026
@niemyjski
niemyjski deleted the investigate-fastcloner-replacement branch March 9, 2026 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants