Last active
January 19, 2024 22:21
-
-
Save ksysiekj/8f952a6cb26cf7db4185c008f696a94f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang='en'> | |
<head> | |
<meta charset='utf-8' /> | |
<title>LinqBenchmarks.LinqBenchmark-20240119-231018</title> | |
<style type="text/css"> | |
table { border-collapse: collapse; display: block; width: 100%; overflow: auto; } | |
td, th { padding: 6px 13px; border: 1px solid #ddd; text-align: right; } | |
tr { background-color: #fff; border-top: 1px solid #ccc; } | |
tr:nth-child(even) { background: #f8f8f8; } | |
</style> | |
</head> | |
<body> | |
<pre><code> | |
BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.3803/22H2/2022Update) | |
Intel Core i7-3632QM CPU 2.20GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores | |
.NET SDK 8.0.101 | |
[Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX [AttachedDebugger] | |
Job-CRZKKL : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX | |
</code></pre> | |
<pre><code>InvocationCount=15 IterationCount=13 RunStrategy=ColdStart | |
UnrollFactor=1 WarmupCount=3 | |
</code></pre> | |
<table> | |
<thead><tr><th>Method </th><th>Count</th><th>Mean </th><th>Error </th><th>StdDev</th><th>Median </th><th>Ratio</th><th>RatioSD</th><th>Rank</th><th>Gen0</th><th>Gen1</th><th>Allocated</th><th>Alloc Ratio</th> | |
</tr> | |
</thead><tbody><tr><td>Linq</td><td>100</td><td>17.03 μs</td><td>42.16 μs</td><td>35.21 μs</td><td>7.473 μs</td><td>1.00</td><td>0.00</td><td>1</td><td>-</td><td>-</td><td>1027 B</td><td>1.00</td> | |
</tr><tr><td>LinqStatic</td><td>100</td><td>25.32 μs</td><td>66.22 μs</td><td>55.30 μs</td><td>9.340 μs</td><td>1.50</td><td>0.64</td><td>2</td><td>-</td><td>-</td><td>1027 B</td><td>1.00</td> | |
</tr><tr><td>NoAllocToSpanEnumerableStatic</td><td>100</td><td>103.84 μs</td><td>315.80 μs</td><td>263.71 μs</td><td>31.973 μs</td><td>4.88</td><td>1.98</td><td>4</td><td>-</td><td>-</td><td>1051 B</td><td>1.02</td> | |
</tr><tr><td>NoAllocAsSpanStatic</td><td>100</td><td>78.39 μs</td><td>268.20 μs</td><td>223.96 μs</td><td>17.187 μs</td><td>2.69</td><td>1.26</td><td>3</td><td>-</td><td>-</td><td>999 B</td><td>0.97</td> | |
</tr><tr><td>RefStructLinqStructStatic</td><td>100</td><td>223.90 μs</td><td>877.46 μs</td><td>732.72 μs</td><td>20.407 μs</td><td>4.53</td><td>4.91</td><td>5</td><td>-</td><td>-</td><td>809 B</td><td>0.79</td> | |
</tr><tr><td>StructLinqStaticZeroAlloc</td><td>100</td><td>292.21 μs</td><td>1,195.45 μs</td><td>998.26 μs</td><td>12.613 μs</td><td>4.20</td><td>6.94</td><td>6</td><td>-</td><td>-</td><td>761 B</td><td>0.74</td> | |
</tr><tr><td>StructLinqStaticZeroPerformanceAlloc</td><td>100</td><td>283.16 μs</td><td>1,161.36 μs</td><td>969.79 μs</td><td>14.507 μs</td><td>4.00</td><td>6.72</td><td>6</td><td>-</td><td>-</td><td>761 B</td><td>0.74</td> | |
</tr><tr><td>Linq</td><td>1000</td><td>77.94 μs</td><td>102.03 μs</td><td>85.20 μs</td><td>54.960 μs</td><td>1.00</td><td>0.00</td><td>1</td><td>-</td><td>-</td><td>7811 B</td><td>1.00</td> | |
</tr><tr><td>LinqStatic</td><td>1000</td><td>74.65 μs</td><td>58.95 μs</td><td>49.23 μs</td><td>63.400 μs</td><td>1.11</td><td>0.33</td><td>1</td><td>-</td><td>-</td><td>7811 B</td><td>1.00</td> | |
</tr><tr><td>NoAllocToSpanEnumerableStatic</td><td>1000</td><td>333.49 μs</td><td>277.78 μs</td><td>231.96 μs</td><td>302.393 μs</td><td>4.93</td><td>1.45</td><td>5</td><td>-</td><td>-</td><td>8675 B</td><td>1.11</td> | |
</tr><tr><td>NoAllocAsSpanStatic</td><td>1000</td><td>191.13 μs</td><td>288.30 μs</td><td>240.74 μs</td><td>133.520 μs</td><td>2.38</td><td>0.65</td><td>2</td><td>-</td><td>-</td><td>8643 B</td><td>1.11</td> | |
</tr><tr><td>RefStructLinqStructStatic</td><td>1000</td><td>314.11 μs</td><td>747.47 μs</td><td>624.17 μs</td><td>151.407 μs</td><td>2.93</td><td>1.28</td><td>4</td><td>-</td><td>-</td><td>6569 B</td><td>0.84</td> | |
</tr><tr><td>StructLinqStaticZeroAlloc</td><td>1000</td><td>303.04 μs</td><td>954.71 μs</td><td>797.22 μs</td><td>93.773 μs</td><td>2.06</td><td>1.90</td><td>3</td><td>-</td><td>-</td><td>6521 B</td><td>0.83</td> | |
</tr><tr><td>StructLinqStaticZeroPerformanceAlloc</td><td>1000</td><td>270.19 μs</td><td>834.84 μs</td><td>697.13 μs</td><td>75.280 μs</td><td>1.89</td><td>1.68</td><td>3</td><td>-</td><td>-</td><td>6521 B</td><td>0.83</td> | |
</tr><tr><td>Linq</td><td>10000</td><td>487.01 μs</td><td>274.97 μs</td><td>229.61 μs</td><td>549.547 μs</td><td>1.00</td><td>0.00</td><td>1</td><td>-</td><td>-</td><td>72739 B</td><td>1.00</td> | |
</tr><tr><td>LinqStatic</td><td>10000</td><td>434.23 μs</td><td>234.29 μs</td><td>195.64 μs</td><td>494.447 μs</td><td>1.14</td><td>0.86</td><td>1</td><td>-</td><td>-</td><td>72739 B</td><td>1.00</td> | |
</tr><tr><td>NoAllocToSpanEnumerableStatic</td><td>10000</td><td>1,919.30 μs</td><td>1,250.77 μs</td><td>1,044.45 μs</td><td>2,247.220 μs</td><td>4.56</td><td>2.62</td><td>3</td><td>-</td><td>-</td><td>80683 B</td><td>1.11</td> | |
</tr><tr><td>NoAllocAsSpanStatic</td><td>10000</td><td>1,147.08 μs</td><td>574.89 μs</td><td>480.06 μs</td><td>1,178.180 μs</td><td>2.59</td><td>1.02</td><td>3</td><td>-</td><td>-</td><td>80651 B</td><td>1.11</td> | |
</tr><tr><td>RefStructLinqStructStatic</td><td>10000</td><td>1,289.87 μs</td><td>824.93 μs</td><td>688.85 μs</td><td>1,048.067 μs</td><td>3.23</td><td>1.76</td><td>3</td><td>-</td><td>-</td><td>64169 B</td><td>0.88</td> | |
</tr><tr><td>StructLinqStaticZeroAlloc</td><td>10000</td><td>924.29 μs</td><td>825.47 μs</td><td>689.31 μs</td><td>754.093 μs</td><td>2.12</td><td>1.11</td><td>2</td><td>-</td><td>-</td><td>64121 B</td><td>0.88</td> | |
</tr><tr><td>StructLinqStaticZeroPerformanceAlloc</td><td>10000</td><td>835.45 μs</td><td>832.44 μs</td><td>695.13 μs</td><td>651.660 μs</td><td>1.82</td><td>1.00</td><td>2</td><td>-</td><td>-</td><td>64121 B</td><td>0.88</td> | |
</tr><tr><td>Linq</td><td>1000000</td><td>50,612.51 μs</td><td>24,954.45 μs</td><td>20,838.10 μs</td><td>41,931.267 μs</td><td>1.00</td><td>0.00</td><td>2</td><td>933.3333</td><td>466.6667</td><td>7449462 B</td><td>1.00</td> | |
</tr><tr><td>LinqStatic</td><td>1000000</td><td>50,721.75 μs</td><td>28,266.20 μs</td><td>23,603.55 μs</td><td>43,100.287 μs</td><td>1.01</td><td>0.24</td><td>2</td><td>933.3333</td><td>466.6667</td><td>7449826 B</td><td>1.00</td> | |
</tr><tr><td>NoAllocToSpanEnumerableStatic</td><td>1000000</td><td>71,570.22 μs</td><td>18,859.43 μs</td><td>15,748.48 μs</td><td>66,139.707 μs</td><td>1.52</td><td>0.40</td><td>3</td><td>933.3333</td><td>466.6667</td><td>8498018 B</td><td>1.14</td> | |
</tr><tr><td>NoAllocAsSpanStatic</td><td>1000000</td><td>46,823.22 μs</td><td>8,652.38 μs</td><td>7,225.13 μs</td><td>45,998.967 μs</td><td>1.03</td><td>0.31</td><td>2</td><td>933.3333</td><td>466.6667</td><td>8497970 B</td><td>1.14</td> | |
</tr><tr><td>RefStructLinqStructStatic</td><td>1000000</td><td>61,907.58 μs</td><td>11,337.82 μs</td><td>9,467.59 μs</td><td>56,572.453 μs</td><td>1.34</td><td>0.33</td><td>3</td><td>866.6667</td><td>400.0000</td><td>6400552 B</td><td>0.86</td> | |
</tr><tr><td>StructLinqStaticZeroAlloc</td><td>1000000</td><td>41,577.96 μs</td><td>7,242.12 μs</td><td>6,047.50 μs</td><td>38,881.953 μs</td><td>0.93</td><td>0.30</td><td>1</td><td>866.6667</td><td>400.0000</td><td>6400504 B</td><td>0.86</td> | |
</tr><tr><td>StructLinqStaticZeroPerformanceAlloc</td><td>1000000</td><td>39,547.39 μs</td><td>7,171.81 μs</td><td>5,988.78 μs</td><td>36,427.280 μs</td><td>0.87</td><td>0.26</td><td>1</td><td>866.6667</td><td>400.0000</td><td>6400523 B</td><td>0.86</td> | |
</tr></tbody></table> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Engines; | |
using BenchmarkDotNet.Running; | |
using NoAlloq; | |
using StructLinq; | |
namespace LinqBenchmarks | |
{ | |
internal class Program | |
{ | |
static void Main(string[] args) | |
{ | |
BenchmarkRunner.Run<LinqBenchmark>(); | |
} | |
} | |
[MemoryDiagnoser] | |
[RankColumn] | |
[SimpleJob(RunStrategy.ColdStart,warmupCount:3,iterationCount:13, invocationCount:15)] | |
public class LinqBenchmark | |
{ | |
private User[] _users; | |
[Params(100, 1_000, 10_000, 1_000_000)] | |
public int Count { get; set; } | |
[GlobalSetup] | |
public void Setup() | |
{ | |
_users = Enumerable.Range(0, Count).Select(static i => new User | |
{ | |
Age = i % 38, | |
Id = Guid.NewGuid(), | |
LastName = $"Smith_{i}", | |
Name = $"John", | |
InternalId = i | |
}).ToArray(); | |
} | |
[Benchmark(Baseline =true)] | |
public void Linq() | |
{ | |
var dtos = _users.Where(q => q.InternalId % 10 == 7).Select(u => u.MapToDto()).ToArray(); | |
} | |
[Benchmark] | |
public void LinqStatic() | |
{ | |
var dtos = _users.Where(static q => q.InternalId % 10 == 7).Select(static u => u.MapToDto()).ToArray(); | |
} | |
[Benchmark] | |
public void NoAllocToSpanEnumerableStatic() | |
{ | |
var dtos = _users.ToSpanEnumerable().Where(static q => q.InternalId % 10 == 7).Select(static u => u.MapToDto()).ToArray(); | |
} | |
[Benchmark] | |
public void NoAllocAsSpanStatic() | |
{ | |
var dtos = _users.AsSpan().Where(static q => q.InternalId % 10 == 7).Select(static u => u.MapToDto()).ToArray(); | |
} | |
[Benchmark] | |
public void RefStructLinqStructStatic() | |
{ | |
var dtos = _users.ToRefStructEnumerable().Where((in User q) => q.InternalId % 10 == 7).Select((in User u) => u.MapToDto()).ToArray(); | |
} | |
[Benchmark] | |
public void StructLinqStaticZeroAlloc() | |
{ | |
var dtos = _users.ToStructEnumerable().Where(static q => q.InternalId % 10 == 7, w=>w).Select(static u => u.MapToDto(), v=>v).ToArray(); | |
} | |
[Benchmark] | |
public void StructLinqStaticZeroPerformanceAlloc() | |
{ | |
var @where = new UserWhereFunc(); | |
var @select = new UserDtoSelectFunc(); | |
var dtos = _users.ToStructEnumerable() | |
.Where(ref @where, w => w) | |
.Select(ref @select, v => v, n => n) | |
.ToArray(); | |
} | |
} | |
struct RefUserDtoSelectFunc : IFunction<User, UserDto> | |
{ | |
public UserDto Eval(User user) | |
{ | |
return user.MapToDto(); | |
} | |
} | |
struct RefUserWhereFunc : IFunction<User, bool> | |
{ | |
public bool Eval(User user) | |
{ | |
return user.InternalId % 10 == 7; | |
} | |
} | |
struct UserDtoSelectFunc : IFunction<User, UserDto> | |
{ | |
public readonly UserDto Eval(User user) | |
{ | |
return user.MapToDto(); | |
} | |
} | |
struct UserWhereFunc : IFunction<User, bool> | |
{ | |
public readonly bool Eval(User user) | |
{ | |
return user.InternalId % 10 == 7; | |
} | |
} | |
public class User | |
{ | |
public int Age { get; init; } | |
public string Name { get; init; } | |
public string LastName { get; init; } | |
public Guid Id { get; init; } | |
public int InternalId { get; init; } | |
} | |
static class UserExtensions | |
{ | |
internal static UserDto MapToDto(this User user) | |
{ | |
return new UserDto | |
{ | |
Age = user.Age, | |
LastName = user.LastName, | |
Name = user.Name, | |
Id = user.Id | |
}; | |
} | |
} | |
public class UserDto | |
{ | |
public int Age { get; init; } | |
public string Name { get; init; } | |
public string LastName { get; init; } | |
public Guid Id { get; init; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment