Skip to content

Commit

Permalink
Benchmarks v2: BenchmarkDotNet and friends
Browse files Browse the repository at this point in the history
This is based on BenchmarkDotNet (while preserving the legacy format
with minor improvements as well - legacy runs much faster). See #666 for
details. Not an ominus number at all.

Note: this code will get a bit simpler with BenchmarkDotNet categories,
see dotnet/BenchmarkDotNet#248 for details.
  • Loading branch information
NickCraver committed May 11, 2017
1 parent 4915071 commit 0a8fcd9
Show file tree
Hide file tree
Showing 16 changed files with 761 additions and 133 deletions.
44 changes: 44 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.Belgrade.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using BenchmarkDotNet.Attributes;
using Belgrade.SqlClient.SqlDb;
using System.Threading.Tasks;

namespace Dapper.Tests.Performance
{
public class BelgradeBenchmarks : BenchmarkBase
{
private QueryMapper _mapper;

[Setup]
public void Setup()
{
BaseSetup();
_mapper = new QueryMapper(ConnectionString);
}

[Benchmark(Description = "Belgrade: ExecuteReader", OperationsPerInvoke = Iterations)]
public Task ExecuteReader()
{
Step();
// TODO: How do you get a Post out of this thing?
return _mapper.ExecuteReader("SELECT TOP 1 * FROM Posts WHERE Id = " + i,
reader =>
{
var post = new Post();
post.Id = reader.GetInt32(0);
post.Text = reader.GetString(1);
post.CreationDate = reader.GetDateTime(2);
post.LastChangeDate = reader.GetDateTime(3);

post.Counter1 = reader.IsDBNull(4) ? null : (int?)reader.GetInt32(4);
post.Counter2 = reader.IsDBNull(5) ? null : (int?)reader.GetInt32(5);
post.Counter3 = reader.IsDBNull(6) ? null : (int?)reader.GetInt32(6);
post.Counter4 = reader.IsDBNull(7) ? null : (int?)reader.GetInt32(7);
post.Counter5 = reader.IsDBNull(8) ? null : (int?)reader.GetInt32(8);
post.Counter6 = reader.IsDBNull(9) ? null : (int?)reader.GetInt32(9);
post.Counter7 = reader.IsDBNull(10) ? null : (int?)reader.GetInt32(10);
post.Counter8 = reader.IsDBNull(11) ? null : (int?)reader.GetInt32(11);
post.Counter9 = reader.IsDBNull(12) ? null : (int?)reader.GetInt32(12);
});
}
}
}
64 changes: 64 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.Dapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using BenchmarkDotNet.Attributes;
using Dapper.Contrib.Extensions;
using System.Linq;

namespace Dapper.Tests.Performance
{
public class DapperBenchmarks : BenchmarkBase
{
[Setup]
public void Setup()
{
BaseSetup();
}

[Benchmark(Description = "Dapper: Query<T> (buffered)", OperationsPerInvoke = Iterations)]
public Post QueryBuffered()
{
Step();
return _connection.Query<Post>("select * from Posts where Id = @Id", new { Id = i }, buffered: true).First();
}

[Benchmark(Description = "Dapper: Query<T> (unbuffered)", OperationsPerInvoke = Iterations)]
public Post QueryUnbuffered()
{
Step();
return _connection.Query<Post>("select * from Posts where Id = @Id", new { Id = i }, buffered: false).First();
}

[Benchmark(Description = "Dapper: QueryFirstOrDefault<T>", OperationsPerInvoke = Iterations)]
public Post QueryFirstOrDefault()
{
Step();
return _connection.QueryFirstOrDefault<Post>("select * from Posts where Id = @Id", new { Id = i });
}

[Benchmark(Description = "Dapper: Query<dyanmic> (buffered)", OperationsPerInvoke = Iterations)]
public object QueryBufferedDynamic()
{
Step();
return _connection.Query("select * from Posts where Id = @Id", new { Id = i }, buffered: true).First();
}

[Benchmark(Description = "Dapper: Query<dyanmic> (unbuffered)", OperationsPerInvoke = Iterations)]
public object QueryUnbufferedDynamic()
{
Step();
return _connection.Query("select * from Posts where Id = @Id", new { Id = i }, buffered: false).First();
}

[Benchmark(Description = "Dapper: QueryFirstOrDefault<dyanmic>", OperationsPerInvoke = Iterations)]
public object QueryFirstOrDefaultDynamic()
{
Step();
return _connection.QueryFirstOrDefault("select * from Posts where Id = @Id", new { Id = i }).First();
}

[Benchmark(Description = "Dapper: Contrib Get<T>", OperationsPerInvoke = Iterations)]
public object ContribGet()
{
Step();
return _connection.Get<Post>(i);
}
}
}
43 changes: 43 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.EntityFramework.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using BenchmarkDotNet.Attributes;
using Dapper.Tests.Performance.Linq2Sql;
using System;
using System.Data.Linq;
using System.Linq;

namespace Dapper.Tests.Performance
{
public class EntityFrameworkBenchmarks : BenchmarkBase
{
private EntityFramework.EFContext Context;
private static readonly Func<DataClassesDataContext, int, Linq2Sql.Post> compiledQuery =
CompiledQuery.Compile((DataClassesDataContext ctx, int id) => ctx.Posts.First(p => p.Id == id));

[Setup]
public void Setup()
{
BaseSetup();
Context = new EntityFramework.EFContext(_connection);
}

[Benchmark(Description = "EF6: Normal", OperationsPerInvoke = Iterations)]
public Post Normal()
{
Step();
return Context.Posts.First(p => p.Id == i);
}

[Benchmark(Description = "EF6: SqlQuery", OperationsPerInvoke = Iterations)]
public Post SqlQuery()
{
Step();
return Context.Database.SqlQuery<Post>("select * from Posts where Id = {0}", i).First();
}

[Benchmark(Description = "EF6: No Tracking", OperationsPerInvoke = Iterations)]
public Post NoTracking()
{
Step();
return Context.Posts.AsNoTracking().First(p => p.Id == i);
}
}
}
93 changes: 93 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.HandCoded.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using BenchmarkDotNet.Attributes;
using System;
using System.Data;
using System.Data.SqlClient;

namespace Dapper.Tests.Performance
{
public class HandCodedBenchmarks : BenchmarkBase
{
private SqlCommand _postCommand;
private SqlParameter _idParam;
#if !COREFX
private DataTable _table;
#endif

[Setup]
public void Setup()
{
BaseSetup();
_postCommand = new SqlCommand()
{
Connection = _connection,
CommandText = @"select Id, [Text], [CreationDate], LastChangeDate,
Counter1,Counter2,Counter3,Counter4,Counter5,Counter6,Counter7,Counter8,Counter9 from Posts where Id = @Id"
};
_idParam = _postCommand.Parameters.Add("@Id", SqlDbType.Int);
#if !COREFX
_table = new DataTable
{
Columns =
{
{"Id", typeof (int)},
{"Text", typeof (string)},
{"CreationDate", typeof (DateTime)},
{"LastChangeDate", typeof (DateTime)},
{"Counter1", typeof (int)},
{"Counter2", typeof (int)},
{"Counter3", typeof (int)},
{"Counter4", typeof (int)},
{"Counter5", typeof (int)},
{"Counter6", typeof (int)},
{"Counter7", typeof (int)},
{"Counter8", typeof (int)},
{"Counter9", typeof (int)},
}
};
#endif
}

[Benchmark(Description = "HandCoded: SqlCommand", OperationsPerInvoke = Iterations)]
public dynamic SqlCommand()
{
Step();
_idParam.Value = i;

using (var reader = _postCommand.ExecuteReader())
{
reader.Read();
var post = new Post();
post.Id = reader.GetInt32(0);
post.Text = reader.GetNullableString(1);
post.CreationDate = reader.GetDateTime(2);
post.LastChangeDate = reader.GetDateTime(3);

post.Counter1 = reader.GetNullableValue<int>(4);
post.Counter2 = reader.GetNullableValue<int>(5);
post.Counter3 = reader.GetNullableValue<int>(6);
post.Counter4 = reader.GetNullableValue<int>(7);
post.Counter5 = reader.GetNullableValue<int>(8);
post.Counter6 = reader.GetNullableValue<int>(9);
post.Counter7 = reader.GetNullableValue<int>(10);
post.Counter8 = reader.GetNullableValue<int>(11);
post.Counter9 = reader.GetNullableValue<int>(12);
return post;
}
}

[Benchmark(Description = "HandCoded: DataTable", OperationsPerInvoke = Iterations)]
public dynamic DataTable()
{
Step();
_idParam.Value = i;
var values = new object[13];
using (var reader = _postCommand.ExecuteReader())
{
reader.Read();
reader.GetValues(values);
_table.Rows.Add(values);
return _table.Rows[_table.Rows.Count-1];
}
}
}
}
43 changes: 43 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.Linq2Sql.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using BenchmarkDotNet.Attributes;
using Dapper.Tests.Performance.Linq2Sql;
using System;
using System.Data.Linq;
using System.Linq;

namespace Dapper.Tests.Performance
{
public class Linq2SqlBenchmarks : BenchmarkBase
{
private DataClassesDataContext Linq2SqlContext;
private static readonly Func<DataClassesDataContext, int, Linq2Sql.Post> compiledQuery =
CompiledQuery.Compile((DataClassesDataContext ctx, int id) => ctx.Posts.First(p => p.Id == id));

[Setup]
public void Setup()
{
BaseSetup();
Linq2SqlContext = new DataClassesDataContext(_connection);
}

[Benchmark(Description = "Linq2Sql: Normal", OperationsPerInvoke = Iterations)]
public Linq2Sql.Post Normal()
{
Step();
return Linq2SqlContext.Posts.First(p => p.Id == i);
}

[Benchmark(Description = "Linq2Sql: Compiled", OperationsPerInvoke = Iterations)]
public Linq2Sql.Post Compiled()
{
Step();
return compiledQuery(Linq2SqlContext, i);
}

[Benchmark(Description = "Linq2Sql: ExecuteQuery", OperationsPerInvoke = Iterations)]
public Post ExecuteQuery()
{
Step();
return Linq2SqlContext.ExecuteQuery<Post>("select * from Posts where Id = {0}", i).First();
}
}
}
25 changes: 25 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.Massive.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using BenchmarkDotNet.Attributes;
using Massive;
using System.Linq;

namespace Dapper.Tests.Performance
{
public class MassiveBenchmarks : BenchmarkBase
{
private DynamicModel _model;

[Setup]
public void Setup()
{
BaseSetup();
_model = new DynamicModel(ConnectionString);
}

[Benchmark(Description = "Massive: Query (dynamic)", OperationsPerInvoke = Iterations)]
public dynamic Query()
{
Step();
return _model.Query("select * from Posts where Id = @0", _connection, i).First();
}
}
}
69 changes: 69 additions & 0 deletions Dapper.Tests.Performance/Benchmarks.NHibernate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using BenchmarkDotNet.Attributes;
using Dapper.Tests.Performance.NHibernate;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Linq;
using NHibernate.Transform;
using NHibernate.Util;
using System.Linq;

namespace Dapper.Tests.Performance
{
public class NHibernateBenchmarks : BenchmarkBase
{
private IStatelessSession _sql, _hql, _criteria, _linq, _get;

[Setup]
public void Setup()
{
BaseSetup();
_sql = NHibernateHelper.OpenSession();
_hql = NHibernateHelper.OpenSession();
_criteria = NHibernateHelper.OpenSession();
_linq = NHibernateHelper.OpenSession();
_get = NHibernateHelper.OpenSession();
}

[Benchmark(Description = "NHibernate: SQL", OperationsPerInvoke = Iterations)]
public Post SQL()
{
Step();
return _sql.CreateSQLQuery(@"select * from Posts where Id = :id")
.SetInt32("id", i)
.SetResultTransformer(Transformers.AliasToBean<Post>())
.List<Post>()[0];
}

[Benchmark(Description = "NHibernate: HQL", OperationsPerInvoke = Iterations)]
public Post HQL()
{
Step();
return _hql.CreateQuery(@"from Post as p where p.Id = :id")
.SetInt32("id", i)
.List<Post>()[0];
}

[Benchmark(Description = "NHibernate: Criteria", OperationsPerInvoke = Iterations)]
public Post Criteria()
{
Step();
return _criteria.CreateCriteria<Post>()
.Add(Restrictions.IdEq(i))
.List<Post>()[0];
}

[Benchmark(Description = "NHibernate: LINQ", OperationsPerInvoke = Iterations)]
public Post LINQ()
{
Step();
return _linq.Query<Post>().First(p => p.Id == i);
}

[Benchmark(Description = "NHibernate: Get<T>", OperationsPerInvoke = Iterations)]
public Post Get()
{
Step();
return _get.Get<Post>(i);
}
}
}
Loading

0 comments on commit 0a8fcd9

Please sign in to comment.