Skip to content

Commit

Permalink
Adding CsvWriter performance tests (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
shibayan authored Jul 13, 2020
1 parent 654845c commit 5166a3b
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace CsvHelper.FastDynamic.Performance.Internal
{
internal static class CsvReaderExtension
{
internal static IList<IDictionary<string, object>> GetDictionaryRecords(this CsvReader csvReader)
internal static IReadOnlyList<IDictionary<string, object>> GetDictionaryRecords(this CsvReader csvReader)
{
// Read Header
csvReader.Read();
Expand Down
1 change: 1 addition & 0 deletions CsvHelper.FastDynamic.Performance/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Program
static void Main(string[] args)
{
BenchmarkRunner.Run<ReaderBenchmark>();
BenchmarkRunner.Run<WriterBenchmark>();
}
}
}
2 changes: 1 addition & 1 deletion CsvHelper.FastDynamic.Performance/ReaderBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public IReadOnlyList<IDictionary<string, object>> GetDictionaryRecords()
{
using var csvReader = new CsvReader(new StringReader(_sampleCsvData), CultureInfo.InvariantCulture);

return csvReader.GetDictionaryRecords().ToArray();
return csvReader.GetDictionaryRecords();
}

[Benchmark]
Expand Down
39 changes: 39 additions & 0 deletions CsvHelper.FastDynamic.Performance/WriterBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;

using BenchmarkDotNet.Attributes;

namespace CsvHelper.FastDynamic.Performance
{
[MemoryDiagnoser]
public class WriterBenchmark
{
private const string SampleCsvFile = @".\sampledata\SFO_Airport_Monthly_Utility_Consumption_for_Natural_Gas__Water__and_Electricity.csv";

public WriterBenchmark()
{
using var csvReader = new CsvReader(new StreamReader(SampleCsvFile), CultureInfo.InvariantCulture);

_sampleCsvData = csvReader.GetDynamicRecords();
}

private readonly IReadOnlyList<dynamic> _sampleCsvData;

[Benchmark]
public void WriteRecords()
{
using var csvWriter = new CsvWriter(new StringWriter(), CultureInfo.InvariantCulture);

csvWriter.WriteRecords(_sampleCsvData);
}

[Benchmark]
public void WriteDynamicRecords()
{
using var csvWriter = new CsvWriter(new StringWriter(), CultureInfo.InvariantCulture);

csvWriter.WriteDynamicRecords(_sampleCsvData);
}
}
}
10 changes: 2 additions & 8 deletions CsvHelper.FastDynamic/CsvReaderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ public static IEnumerable<dynamic> EnumerateDynamicRecords(this CsvReader csvRea
{
var values = new object[context.HeaderRecord.Length];

for (int i = 0; i < values.Length; i++)
{
values[i] = csvReader.GetField(i);
}
Array.Copy(context.Record, values, values.Length);

record = new CsvRecord(csvHeader, values);
}
Expand Down Expand Up @@ -99,10 +96,7 @@ public static async IAsyncEnumerable<dynamic> EnumerateDynamicRecordsAsync(this
{
var values = new object[context.HeaderRecord.Length];

for (int i = 0; i < values.Length; i++)
{
values[i] = csvReader.GetField(i);
}
Array.Copy(context.Record, values, values.Length);

record = new CsvRecord(csvHeader, values);
}
Expand Down
4 changes: 3 additions & 1 deletion CsvHelper.FastDynamic/CsvRecordMetaObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace CsvHelper.FastDynamic
// Thanks, from https://github.com/StackExchange/Dapper/blob/master/Dapper/SqlMapper.DapperRowMetaObject.cs
internal sealed class CsvRecordMetaObject : DynamicMetaObject
{
private static readonly string[] EmptyArray = Array.Empty<string>();

private static readonly MethodInfo GetValueMethod = typeof(IDictionary<string, object>).GetProperty("Item").GetGetMethod();
private static readonly MethodInfo SetValueMethod = typeof(CsvRecord).GetMethod(nameof(CsvRecord.SetValue), new[] { typeof(string), typeof(object) });

Expand Down Expand Up @@ -60,7 +62,7 @@ public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicM

public override IEnumerable<string> GetDynamicMemberNames()
{
return HasValue && Value is IDictionary<string, object> lookup ? lookup.Keys : Array.Empty<string>();
return HasValue && Value is IDictionary<string, object> lookup ? lookup.Keys : EmptyArray;
}
}
}
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,37 @@ class Program

## Performance

### Reader

```
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.264 (2004/?/20H1)
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.329 (2004/?/20H1)
Intel Core i9-10940X CPU 3.30GHz, 1 CPU, 28 logical and 14 physical cores
.NET Core SDK=3.1.300
[Host] : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT
DefaultJob : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT
.NET Core SDK=3.1.301
[Host] : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
DefaultJob : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------- |-----------:|---------:|---------:|--------:|--------:|------:|----------:|
| GetRecords | 1,586.6 us | 12.29 us | 11.50 us | 83.9844 | 41.0156 | - | 828.13 KB |
| GetDictionaryRecords | 734.3 us | 7.96 us | 7.45 us | 73.2422 | 35.1563 | - | 728.99 KB |
| GetDynamicRecords | 599.2 us | 5.04 us | 4.47 us | 61.5234 | 1.9531 | - | 607.82 KB |
| GetRecords | 1,687.1 us | 17.11 us | 15.17 us | 83.9844 | 41.0156 | - | 829.18 KB |
| GetDictionaryRecords | 776.7 us | 14.59 us | 16.21 us | 73.2422 | 34.1797 | - | 725.63 KB |
| GetDynamicRecords | 617.3 us | 11.23 us | 9.96 us | 61.5234 | 2.9297 | - | 608.87 KB |
```

### Writer

```
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.329 (2004/?/20H1)
Intel Core i9-10940X CPU 3.30GHz, 1 CPU, 28 logical and 14 physical cores
.NET Core SDK=3.1.301
[Host] : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
DefaultJob : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|-------------------- |-----------:|---------:|---------:|---------:|--------:|------:|-----------:|
| WriteRecords | 2,355.6 us | 46.86 us | 64.14 us | 148.4375 | 27.3438 | - | 1476.46 KB |
| WriteDynamicRecords | 885.7 us | 17.50 us | 16.37 us | 17.5781 | 2.9297 | - | 174.49 KB |
```

## Thanks
Expand Down

0 comments on commit 5166a3b

Please sign in to comment.