Nice3point.BenchmarkDotNet.Revit 2022.1.2

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Nice3point.BenchmarkDotNet.Revit --version 2022.1.2
                    
NuGet\Install-Package Nice3point.BenchmarkDotNet.Revit -Version 2022.1.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nice3point.BenchmarkDotNet.Revit" Version="2022.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nice3point.BenchmarkDotNet.Revit" Version="2022.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Nice3point.BenchmarkDotNet.Revit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nice3point.BenchmarkDotNet.Revit --version 2022.1.2
                    
#r "nuget: Nice3point.BenchmarkDotNet.Revit, 2022.1.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nice3point.BenchmarkDotNet.Revit@2022.1.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nice3point.BenchmarkDotNet.Revit&version=2022.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Nice3point.BenchmarkDotNet.Revit&version=2022.1.2
                    
Install as a Cake Tool

Benchmarking library for Revit

Nuget Downloads Last Commit

Write performance benchmarks for your Revit add-ins using the BenchmarkDotNet, and share reproducible measurement experiments.

Installation

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).*"/>

Writing your first benchmark

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.

Running your benchmarks

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());

BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly)
    .Run(args, configuration);

BenchmarkSwitcher runs the benchmarks the command-line arguments select:

dotnet run -c Release.R26 -- --filter '*MyBenchmarks*'

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.

Application-level benchmarks

Benchmark Revit application-level operations:

using BenchmarkDotNet.Attributes;

public class RevitApplicationBenchmarks : RevitApiBenchmark
{
    [Benchmark]
    public XYZ NewXyz()
    {
        return new XYZ(3, 4, 5);
    }

    [Benchmark]
    public XYZ CreateNewXyz()
    {
        return Application.Create.NewXYZ(3, 4, 5);
    }
}

Document benchmarks

Use OnGlobalSetup and OnGlobalCleanup overrides to open and close a document around benchmark iterations. BenchmarkDotNet provides [GlobalSetup] and [GlobalCleanup] hooks, but due to library limitations, they cannot be assigned twice:

using BenchmarkDotNet.Attributes;

public class RevitCollectorBenchmarks : RevitApiBenchmark
{
    private Document _document = null!;

    protected sealed override void OnGlobalSetup()
    {
        _document = Application.NewProjectDocument(UnitSystem.Metric);
    }

    protected sealed override void OnGlobalCleanup()
    {
        _document.Close(false);
    }

    [Benchmark]
    public IList<Element> WhereElementIsNotElementTypeToElements()
    {
        return new FilteredElementCollector(_document)
            .WhereElementIsNotElementType()
            .ToElements();
    }

    [Benchmark]
    public List<Element> WhereElementIsNotElementTypeToList()
    {
        return new FilteredElementCollector(_document)
            .WhereElementIsNotElementType()
            .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
WhereElementIsNotElementTypeToElements 2.203 ms 0.0494 ms 0.1440 ms 295.05 KB
WhereElementIsNotElementTypeToList 2.190 ms 0.0436 ms 0.0929 ms 310.09 KB

User interface benchmarks

Benchmark the functionality that needs the Revit user interface by deriving from RevitApiUiBenchmark. The class exposes UiApplication, and runs every benchmark method and hook on the Revit thread inside a Revit API context. Use OnGlobalSetup and OnGlobalCleanup overrides to open a model around benchmark iterations:

using Autodesk.Revit.UI;
using BenchmarkDotNet.Attributes;

public class RevitSelectionBenchmarks : RevitApiUiBenchmark
{
    private UIDocument _uiDocument = null!;

    protected sealed override void OnGlobalSetup()
    {
        _uiDocument = UiApplication.OpenAndActivateDocument(modelPath);
    }

    [Benchmark]
    public List<Wall> GetElementOfTypeToList()
    {
        var document = _uiDocument.Document;
        return _uiDocument.Selection.GetElementIds()
            .Select(document.GetElement)
            .OfType<Wall>()
            .ToList();
    }

    [Benchmark]
    public List<Wall> FilteredElementCollectorOfClassToList()
    {
        return new FilteredElementCollector(_uiDocument.Document, _uiDocument.Selection.GetElementIds())
            .OfClass(typeof(Wall))
            .Cast<Wall>()
            .ToList();
    }
}

UI benchmarks share one Revit instance, which starts with the first UI benchmark and closes when the run ends. Asynchronous benchmark methods and the job settings of the benchmark process, such as the runtime and the GC mode, are not supported.

DotTrace profiler

Profile your benchmarks with dotTrace by adding the DotTraceDiagnoser from the BenchmarkDotNet.Diagnostics.dotTrace package to the configuration:

using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnostics.dotTrace;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using Nice3point.BenchmarkDotNet.Revit;

var configuration = ManualConfig.Create()
    .AddJob(Job.Default.WithCurrentConfiguration())
    .AddDiagnoser(new DotTraceDiagnoser());

BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly)
    .Run(args, configuration);

The diagnoser profiles RevitApiBenchmark and RevitApiUiBenchmark classes alike. To profile a single class, mark it with the [DotTraceDiagnoser] attribute.

Benchmark configuration

BenchmarkDotNet initializes Revit with the English - United States language, the C:\Program Files\Autodesk\Revit {version} installation path, and an add-in with a random ID. To override these defaults:

  • Add the assembly-level attribute to any .cs file in your project (e.g., Program.cs):

    using Nice3point.Revit.Injector.Attributes;
    
    [assembly: RevitLanguage("ENU")]
    [assembly: RevitInstallationPath(@"D:\Autodesk\Revit Preview")]
    [assembly: RevitClient(Id = "B3E7F5A2-9C4D-4E81-A6F0-2D8C51E7B934", Name = "Benchmarks", VendorId = "Contoso")]
    
  • Or add the attributes directly to your .csproj file:

    
    <ItemGroup>
    
        <AssemblyAttribute Include="Nice3point.Revit.Injector.Attributes.RevitLanguageAttribute">
            <_Parameter1>ENU</_Parameter1>
        </AssemblyAttribute>
    
        <AssemblyAttribute Include="Nice3point.Revit.Injector.Attributes.RevitInstallationPathAttribute">
            <_Parameter1>D:\Autodesk\Revit $(RevitVersion)</_Parameter1>
        </AssemblyAttribute>
    
        <AssemblyAttribute Include="Nice3point.Revit.Injector.Attributes.RevitClientAttribute">
            <Id>B3E7F5A2-9C4D-4E81-A6F0-2D8C51E7B934</Id>
            <Name>Benchmarks</Name>
            <VendorId>Contoso</VendorId>
        </AssemblyAttribute>
    
    </ItemGroup>
    

The RevitLanguage attribute accepts a language name (e.g., "English - United States"), code (e.g., "ENU") or LanguageType enum value (e.g., "English_GB" or "15").

The RevitClient attribute sets the add-in that Revit attributes every API call of the benchmark to, and Application.ActiveAddInId returns it. Each property is optional, Id accepts any format Guid accepts, VendorId must match the vendor of an Extensible Storage schema the benchmark writes with vendor access.

Product Compatible and additional computed target framework versions.
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories (2)

Showing the top 2 popular GitHub repositories that depend on Nice3point.BenchmarkDotNet.Revit:

Repository Stars
Nice3point/RevitTemplates
Project templates for Revit add-ins
Nice3point/RevitExtensions
Extensions for Revit plugin development
Version Downloads Last Updated
2027.0.4 126 11/2/2026
2027.0.3 99 11/2/2026
2027.0.2 121 11/1/2026
2026.1.4 115 11/2/2026
2026.1.3 101 11/2/2026
2026.1.2 106 11/1/2026
2025.1.4 131 11/2/2026
2025.1.3 92 11/2/2026
2025.1.2 107 11/1/2026
2024.1.4 84 11/2/2026
2024.1.3 89 11/2/2026
2024.1.2 97 11/1/2026
2023.1.4 86 11/2/2026
2023.1.3 87 11/2/2026
2023.1.2 102 11/1/2026
2022.1.4 76 11/2/2026
2022.1.3 85 11/2/2026
2022.1.2 91 11/1/2026
2021.1.4 82 11/2/2026
2021.1.3 84 11/2/2026
Loading failed

This release adds benchmarking of the Revit user interface.

Revit UI benchmarks

RevitApiUiBenchmark runs benchmarks inside a Revit process started with its user interface.
The UiApplication property exposes the UIApplication of that process, and every benchmark method and hook runs on the Revit thread inside a Revit API context:

public class SelectionBenchmarks : RevitApiUiBenchmark
{
   private UIDocument _uiDocument = null!;

   protected sealed override void OnGlobalSetup()
   {
       _uiDocument = UiApplication.OpenAndActivateDocument(modelPath);
   }

   [Benchmark]
   public List<Wall> GetElementOfTypeToList()
   {
       var document = _uiDocument.Document;
       return _uiDocument.Selection.GetElementIds()
           .Select(document.GetElement)
           .OfType<Wall>()
           .ToList();
   }

   [Benchmark]
   public List<Wall> FilteredElementCollectorOfClassToList()
   {
       return new FilteredElementCollector(_uiDocument.Document, _uiDocument.Selection.GetElementIds())
           .OfClass(typeof(Wall))
           .Cast<Wall>()
           .ToList();
   }
}

UI benchmarks use the RevitAPIUI types, add the Nice3point.Revit.Api.RevitAPIUI package reference.

DotTrace profiler

Benchmarks support profiling with dotTrace.
Add the DotTraceDiagnoser from the BenchmarkDotNet.Diagnostics.dotTrace package to the configuration:

var configuration = ManualConfig.Create()
   .AddJob(Job.Default.WithCurrentConfiguration())
   .AddDiagnoser(new DotTraceDiagnoser());

The diagnoser profiles RevitApiBenchmark and RevitApiUiBenchmark classes alike.
To profile a single class, mark it with the [DotTraceDiagnoser] attribute.

Bug fixes

• A benchmark project that references RevitAPIUI runs without FileNotFoundException https://github.com/Nice3point/RevitBenchmark/issues/57.
• After a run of RevitApiUiBenchmark benchmarks, Revit opens its window at the position, the size, and the maximized state it had before the run.