Skip to content

Commit

Permalink
feat(csharp/src/Apache.Arrow.Adbc): improved performance of ValueAt h…
Browse files Browse the repository at this point in the history
…elper and AdbcDataReader (#2534)

I noticed that the ValueAt helper had compiled into some very
inefficient IL, so I decided to improve its performance by replacing
with a simpler switch statement. I then realized that in AdbcDataReader,
we don't need to do the type check on every row because it's the same
underlying Arrow type for the entire column -- so it's faster to get a
delegate once and keep using the same delegate for the entire data set.
Benchmarking came up with these results when testing through
AdbcDataReader.GetValues:

| Method      | Mean    | Error    | StdDev   |
|------------ |--------:|---------:|---------:|
| Original    | 6.263 s | 0.0575 s | 0.0538 s |
| New ValueAt | 5.400 s | 0.0424 s | 0.0397 s |
| Getter      | 4.650 s | 0.0281 s | 0.0249 s |
  • Loading branch information
CurtHagenlocher authored Feb 18, 2025
1 parent 7706ace commit 8dade5b
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 83 deletions.
7 changes: 7 additions & 0 deletions csharp/Apache.Arrow.Adbc.sln
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Apache.Arrow.Adbc.Drivers.F
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Apache.Arrow.Adbc.Tests.Drivers.FlightSql", "test\Drivers\FlightSql\Apache.Arrow.Adbc.Tests.Drivers.FlightSql.csproj", "{5B27FB02-D4AE-4ACB-AD88-5E64EEB61729}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{BAF2CF14-BA77-429E-AF54-A34B978E9F5C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -94,6 +96,10 @@ Global
{5B27FB02-D4AE-4ACB-AD88-5E64EEB61729}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B27FB02-D4AE-4ACB-AD88-5E64EEB61729}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B27FB02-D4AE-4ACB-AD88-5E64EEB61729}.Release|Any CPU.Build.0 = Release|Any CPU
{BAF2CF14-BA77-429E-AF54-A34B978E9F5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BAF2CF14-BA77-429E-AF54-A34B978E9F5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BAF2CF14-BA77-429E-AF54-A34B978E9F5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BAF2CF14-BA77-429E-AF54-A34B978E9F5C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -112,6 +118,7 @@ Global
{C5503227-C5A7-406F-83AA-681F292EA61F} = {C7290227-E925-47E7-8B6B-A8B171645D58}
{77D5A92F-4136-4DE7-81F4-43B981223280} = {FEB257A0-4FD3-495E-9A47-9E1649755445}
{5B27FB02-D4AE-4ACB-AD88-5E64EEB61729} = {C7290227-E925-47E7-8B6B-A8B171645D58}
{BAF2CF14-BA77-429E-AF54-A34B978E9F5C} = {5BD04C26-CE52-4893-8C1A-479705195CEF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4795CF16-0FDB-4BE0-9768-5CF31564DC03}
Expand Down
28 changes: 28 additions & 0 deletions csharp/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ProcessArchitecture>$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant())</ProcessArchitecture>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
<PackageReference Include="DuckDB.NET.Bindings.Full" Version="1.2.0" GeneratePathProperty="true" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
<ProjectReference Include="..\src\Client\Apache.Arrow.Adbc.Client.csproj" />
<ProjectReference Include="..\test\Apache.Arrow.Adbc.Tests\Apache.Arrow.Adbc.Tests.csproj" />
</ItemGroup>

<Target Name="CopyDuckDb" AfterTargets="Build" Condition="'$(PkgDuckDB_NET_Bindings_Full)' != ''">
<Copy Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'" SourceFiles="$(PkgDuckDB_NET_Bindings_Full)\runtimes\win-$(ProcessArchitecture)\native\duckdb.dll" DestinationFolder="$(OutputPath)" />
<Copy Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'" SourceFiles="$(PkgDuckDB_NET_Bindings_Full)\runtimes\linux-$(ProcessArchitecture)\native\libduckdb.so" DestinationFolder="$(OutputPath)" />
<Copy Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'" SourceFiles="$(PkgDuckDB_NET_Bindings_Full)\runtimes\osx\native\libduckdb.dylib" DestinationFolder="$(OutputPath)" />
</Target>

</Project>
80 changes: 80 additions & 0 deletions csharp/Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using Apache.Arrow.Adbc.Tests;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace Apache.Arrow.Adbc.Benchmarks
{
public class ClientBenchmark
{
public static DuckDbFixture? DuckDb;
public static Client.AdbcConnection? Connection;

static ClientBenchmark()
{
DuckDb = new DuckDbFixture();

using (var database = DuckDb.OpenDatabase("test.db"))
{
using var connection = database.Connect(null);
using var statement = connection.CreateStatement();

statement.SqlQuery = "INSTALL tpch";
statement.ExecuteUpdate();

statement.SqlQuery = "LOAD tpch";
statement.ExecuteUpdate();

statement.SqlQuery = "CALL dbgen(sf = 1)";
statement.ExecuteUpdate();
}

Connection = DuckDb.CreateConnection("test.db", null);
}

[Benchmark]
public void Test()
{
using var command = Connection!.CreateCommand();
command.CommandText = "SELECT * FROM lineitem";
using var result = command.ExecuteReader();
object[] row = new object[result.FieldCount];
while (result.Read())
{
result.GetValues(row);
}
}
}

public class Program
{
static void Main(string[] args)
{
try
{
BenchmarkRunner.Run(typeof(Program).Assembly);
}
finally
{
ClientBenchmark.Connection?.Dispose();
ClientBenchmark.DuckDb?.Dispose();
}
}
}
}
Loading

0 comments on commit 8dade5b

Please sign in to comment.