Write performance benchmarks for your Revit add-ins using the BenchmarkDotNet, and share reproducible measurement experiments.
You can install this library as a NuGet package.
The packages are compiled for specific versions of Revit. To support different versions of libraries in one project, use the RevitVersion property:
<PackageReference Include="Nice3point.BenchmarkDotNet.Revit" Version="$(RevitVersion).*"/>Start by creating a new class inheriting from RevitApiBenchmark:
public class MyBenchmarks : RevitApiBenchmark
{
}Add one or more methods marked with [Benchmark]:
using BenchmarkDotNet.Attributes;
public class MyBenchmarks : RevitApiBenchmark
{
[Benchmark]
public void MyBenchmark()
{
}
}This is your runnable benchmark. The base class ensures the benchmark executes within Revit's single-threaded API context.
You can run your benchmarks with a simple configuration.
BenchmarkDotNet uses the Release configuration by default to run, which will cause a failure when running benchmarks for Revit, where API multi-versioning is required.
In this case, use the WithCurrentConfiguration() extension for the Job, which will run the benchmark for your selected Solution configuration.
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using Nice3point.BenchmarkDotNet.Revit;
var configuration = ManualConfig.Create()
.AddJob(Job.Default.WithCurrentConfiguration());
BenchmarkRunner.Run<MyBenchmarks>(configuration);Important
You must have a licensed copy of Autodesk Revit installed on your machine to run benchmarks, with a version that matches the selected Solution configuration.
Benchmark Revit application‑level operations:
using BenchmarkDotNet.Attributes;
public class RevitApplicationBenchmarks : RevitApiBenchmark
{
[Benchmark]
public double Create_XYZ_Distance()
{
var point = Application.Create.NewXYZ(3, 4, 5);
return point.DistanceTo(XYZ.Zero);
}
}BenchmarkDotNet provides [GlobalSetup] and [GlobalCleanup] hooks, but due to library limitations, it cannot be assigned twice.
If you need these hooks in your benchmarks, for example to open the Document, use OnSetup/OnCleanup overrides instead:
using BenchmarkDotNet.Attributes;
public class RevitDocumentBenchmarks : RevitApiBenchmark
{
private Document _documentFile = null!;
protected sealed override void OnSetup()
{
_documentFile = Application.OpenDocumentFile($@"C:\Program Files\Autodesk\Revit {Application.VersionNumber}\Samples\rac_basic_sample_family.rfa");
}
protected sealed override void OnCleanup()
{
_documentFile.Close(false);
}
[Benchmark]
public IList<Element> WhereElementIsElementTypeToElements()
{
return new FilteredElementCollector(_documentFile)
.WhereElementIsElementType()
.ToElements();
}
[Benchmark]
public IList<Element> ElementIsElementTypeFilterToElements()
{
return new FilteredElementCollector(_documentFile)
.WherePasses(new ElementIsElementTypeFilter())
.ToElements();
}
[Benchmark]
public List<Element> WhereElementIsElementTypeToList()
{
return new FilteredElementCollector(_documentFile)
.WhereElementIsElementType()
.ToList();
}
[Benchmark]
public List<ElementType> WhereElementIsElementTypeCastToList()
{
return new FilteredElementCollector(_documentFile)
.WhereElementIsElementType()
.Cast<ElementType>()
.ToList();
}
[Benchmark]
public List<ElementType> WhereElementIsElementTypeOfTypeToList()
{
return new FilteredElementCollector(_documentFile)
.WhereElementIsElementType()
.OfType<ElementType>()
.ToList();
}
}
BenchmarkDotNet v0.15.8, Windows 11 (10.0.22631.6199/23H2/2023Update/SunValley3)
AMD Ryzen 5 5600 3.50GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.100
[Host] : .NET 8.0.22 (8.0.22, 8.0.2225.52707), X64 RyuJIT x86-64-v3
MediumRun : .NET 8.0.22 (8.0.22, 8.0.2225.52707), X64 RyuJIT x86-64-v3
Job=MediumRun BuildConfiguration=Release.R26 IterationCount=15
LaunchCount=2 WarmupCount=10
| Method | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|
| WhereElementIsElementTypeToElements | 122.0 μs | 4.54 μs | 6.80 μs | 5.55 KB |
| ElementIsElementTypeFilterToElements | 412.0 μs | 7.52 μs | 11.26 μs | 5.71 KB |
| WhereElementIsElementTypeToList | 122.1 μs | 2.84 μs | 4.17 μs | 5.7 KB |
| WhereElementIsElementTypeCastToList | 122.6 μs | 2.41 μs | 3.45 μs | 5.76 KB |
| WhereElementIsElementTypeOfTypeToList | 122.0 μs | 2.19 μs | 3.20 μs | 5.76 KB |