Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions DuckDB.NET.Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Optimize>true</Optimize>
<BuildType>Full</BuildType>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\keyPair.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.4" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DuckDB.NET.Data\Data.csproj" />
<ProjectReference Include="..\DuckDB.NET.Bindings\Bindings.csproj" Properties="BuildType=Full" />
</ItemGroup>

<ItemGroup>
<None Include="..\DuckDB.NET.Bindings\obj\runtimes\**\*.dll;..\DuckDB.NET.Bindings\obj\runtimes\**\*.so;..\DuckDB.NET.Bindings\obj\runtimes\**\*.dylib;">
<Visible>false</Visible>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>runtimes\%(RecursiveDir)\%(FileName)%(Extension)</Link>
</None>
</ItemGroup>

</Project>
53 changes: 53 additions & 0 deletions DuckDB.NET.Benchmarks/NativeLibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace DuckDB.NET.Benchmarks;

/// <summary>
/// Loads the platform-native DuckDB library for the benchmark process.
/// </summary>
internal static class NativeLibraryLoader
{
[ModuleInitializer]
public static void Init()
{
if (GetRid() is not { } rid)
{
return;
}

_ = NativeLibrary.TryLoad(Path.Join("runtimes", rid, "native", "duckdb"), Assembly.GetExecutingAssembly(), DllImportSearchPath.AssemblyDirectory, out _) ||
NativeLibrary.TryLoad(Path.Join("runtimes", rid, "native", "libduckdb"), Assembly.GetExecutingAssembly(), DllImportSearchPath.AssemblyDirectory, out _);
}

private static string? GetRid()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return RuntimeInformation.ProcessArchitecture switch
{
Architecture.X64 => "win-x64",
Architecture.Arm64 => "win-arm64",
_ => null,
};
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return RuntimeInformation.ProcessArchitecture switch
{
Architecture.X64 => "linux-x64",
Architecture.Arm64 => "linux-arm64",
_ => null,
};
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "osx";
}

return null;
}
}
101 changes: 101 additions & 0 deletions DuckDB.NET.Benchmarks/PreparedCommandBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using BenchmarkDotNet.Attributes;
using DuckDB.NET.Data;

namespace DuckDB.NET.Benchmarks;

[MemoryDiagnoser]
public class PreparedCommandBenchmark
{
private DuckDBConnection connection = null!;
private DuckDBCommand unpreparedCommand = null!;
private DuckDBCommand preparedCommand = null!;
private DuckDBParameter unpreparedParameter = null!;
private DuckDBParameter preparedParameter = null!;
private int nextValue;

[GlobalSetup]
public void Setup()
{
connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();

unpreparedCommand = CreateCommand(out unpreparedParameter);
preparedCommand = CreateCommand(out preparedParameter);
preparedCommand.Prepare();
}

[GlobalCleanup]
public void Cleanup()
{
preparedCommand.Dispose();
unpreparedCommand.Dispose();
connection.Dispose();
}

[Benchmark(Baseline = true)]
public int ExecuteUnprepared()
{
unpreparedParameter.Value = nextValue++;
return (int)unpreparedCommand.ExecuteScalar()!;
}

[Benchmark]
public int ExecutePrepared()
{
preparedParameter.Value = nextValue++;
return (int)preparedCommand.ExecuteScalar()!;
}

private DuckDBCommand CreateCommand(out DuckDBParameter changingParameter)
{
var command = connection.CreateCommand();
command.CommandText = "SELECT $first::INTEGER + $second::INTEGER + $third::INTEGER";
changingParameter = new DuckDBParameter("first", 1);
command.Parameters.Add(changingParameter);
command.Parameters.Add(new DuckDBParameter("second", 2));
command.Parameters.Add(new DuckDBParameter("third", 3));
return command;
}
}

[MemoryDiagnoser]
public class PreparedCommandSetupBenchmark
{
private DuckDBConnection connection = null!;

[GlobalSetup]
public void Setup()
{
connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();
}

[GlobalCleanup]
public void Cleanup()
{
connection.Dispose();
}

[Benchmark(Baseline = true)]
public void CreateUnpreparedCommand()
{
using var command = CreateCommand();
}

[Benchmark]
public void CreateAndPrepareCommand()
{
using var command = CreateCommand();
command.Prepare();
}

private DuckDBCommand CreateCommand()
{
var command = connection.CreateCommand();
command.CommandText = "SELECT $first::INTEGER + $second::INTEGER + $third::INTEGER";
command.Parameters.Add(new DuckDBParameter("first", 1));
command.Parameters.Add(new DuckDBParameter("second", 2));
command.Parameters.Add(new DuckDBParameter("third", 3));
return command;
}
}
15 changes: 15 additions & 0 deletions DuckDB.NET.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Toolchains.InProcess.Emit;
using DuckDB.NET.Benchmarks;

// The repo's Directory.Build.props renames the output assembly to DuckDB.NET.Benchmarks
// while the project file stays Benchmarks.csproj, so BenchmarkDotNet's default toolchain
// can't locate the csproj. Run in-process to avoid the separate build/spawn step.
var config = DefaultConfig.Instance
.AddJob(Job.ShortRun.WithToolchain(InProcessEmitToolchain.Instance));

BenchmarkSwitcher
.FromTypes([typeof(PreparedCommandBenchmark), typeof(PreparedCommandSetupBenchmark)])
.Run(args, config);
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ public static partial class PreparedStatements
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial DuckDBState DuckDBBindNull(DuckDBPreparedStatement preparedStatement, long index);

// Clears values from a reusable prepared statement before rebinding it. This prevents a
// parameter omitted by a later named collection from retaining its previous value.
[LibraryImport(DuckDbLibrary, EntryPoint = "duckdb_clear_bindings")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial DuckDBState DuckDBClearBindings(DuckDBPreparedStatement preparedStatement);

[LibraryImport(DuckDbLibrary, EntryPoint = "duckdb_execute_prepared")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial DuckDBState DuckDBExecutePrepared(DuckDBPreparedStatement preparedStatement, out DuckDBResult result);
Expand Down
Loading
Loading