Table of Contents

Exporters

An exporter allows you to export results of your benchmark in different formats. By default, files with results will be located in .\BenchmarkDotNet.Artifacts\results directory, but this can be changed via the ArtifactsPath property in the IConfig. Default exporters are: csv, html and markdown.


Sample: IntroExport

BenchmarkDotNet has a lot of predefined exporters.

Source code

using System;
using System.Threading;
using BenchmarkDotNet.Attributes;

namespace BenchmarkDotNet.Samples
{
    [ShortRunJob]
    [MediumRunJob]
    [KeepBenchmarkFiles]

    [AsciiDocExporter]
    [CsvExporter]
    [CsvMeasurementsExporter]
    [HtmlExporter]
    [PlainExporter]
    [RPlotExporter]
    [JsonExporterAttribute.Brief]
    [JsonExporterAttribute.BriefCompressed]
    [JsonExporterAttribute.Full]
    [JsonExporterAttribute.FullCompressed]
    [MarkdownExporterAttribute.Default]
    [MarkdownExporterAttribute.GitHub]
    [MarkdownExporterAttribute.StackOverflow]
    [MarkdownExporterAttribute.Atlassian]
    [XmlExporterAttribute.Brief]
    [XmlExporterAttribute.BriefCompressed]
    [XmlExporterAttribute.Full]
    [XmlExporterAttribute.FullCompressed]
    public class IntroExport
    {
        private Random random = new Random(42);

        [Benchmark(Baseline = true)]
        public void Sleep10() => Thread.Sleep(10);

        [Benchmark]
        public void Sleep50Noisy() => Thread.Sleep(random.Next(100));
    }
}

Sample: IntroExportJson

BenchmarkDotNet has a set of json exporters. You can customize the following properties of these exporters:

  • fileNameSuffix: a string which be placed in the end of target file name.
  • indentJson=false/true: should we format json or not.
  • excludeMeasurements=false/true: should we exclude detailed information about measurements or not (the final summary with statistics will be in the json file anyway).

Source code

using System.Threading;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Exporters.Json;

namespace BenchmarkDotNet.Samples
{
    // *** Attribute style ***

    [DryJob]
    [JsonExporterAttribute.Brief]
    [JsonExporterAttribute.Full]
    [JsonExporterAttribute.BriefCompressed]
    [JsonExporterAttribute.FullCompressed]
    [JsonExporter("-custom", indentJson: true, excludeMeasurements: true)]
    public class IntroExportJson
    {
        [Benchmark] public void Sleep10() => Thread.Sleep(10);
        [Benchmark] public void Sleep20() => Thread.Sleep(20);
    }

    // *** Object style ***

    [Config(typeof(Config))]
    public class IntroJsonExportObjectStyle
    {
        private class Config : ManualConfig
        {
            public Config()
            {
                AddExporter(JsonExporter.Brief);
                AddExporter(JsonExporter.Brief);
                AddExporter(JsonExporter.Full);
                AddExporter(JsonExporter.BriefCompressed);
                AddExporter(JsonExporter.FullCompressed);
                AddExporter(JsonExporter.Custom("-custom", indentJson: true, excludeMeasurements: true));
            }
        }

        [Benchmark] public void Sleep10() => Thread.Sleep(10);
        [Benchmark] public void Sleep20() => Thread.Sleep(20);
    }
}

Output

Example of IntroJsonExport-report-brief.json:

{
   "Title":"IntroJsonExport",
   "HostEnvironmentInfo":{
      "BenchmarkDotNetCaption":"BenchmarkDotNet-Dev.Core",
      "BenchmarkDotNetVersion":"0.9.9.0",
      "OsVersion":"Microsoft Windows NT 6.2.9200.0",
      "ProcessorName":{
         "IsValueCreated":true,
         "Value":"Intel(R) Core(TM) i7-4702MQ CPU 2.20GHz"
      },
      "ProcessorCount":8,
      "ClrVersion":"MS.NET 4.0.30319.42000",
      "Architecture":"64-bit",
      "HasAttachedDebugger":false,
      "HasRyuJit":true,
      "Configuration":"RELEASE",
      "JitModules":"clrjit-v4.6.1586.0",
      "DotNetCliVersion":"1.0.0-preview2-003121",
      "ChronometerFrequency":2143474,
      "HardwareTimerKind":"Tsc"
   },
   "Benchmarks":[
      {
         "ShortInfo":"IntroJsonExport_Sleep10",
         "Namespace":"BenchmarkDotNet.Samples.Intro",
         "Type":"IntroJsonExport",
         "Method":"Sleep10",
         "MethodTitle":"Sleep10",
         "Parameters":"",
         "Properties":{
            "Mode":"Throughput",
            "Platform":"Host",
            "Jit":"Host",
            "Runtime":"Host",
            "GcMode":"Host",
            "WarmupCount":"Auto",
            "IterationCount":"Auto",
            "LaunchCount":"Auto",
            "IterationTime":"Auto",
            "Affinity":"Auto"
         },
         "Statistics":{
            "N":20,
            "Min":10265993.7209375,
            "LowerFence":10255329.082734371,
            "Q1":10337369.528437499,
            "Median":10360382.6953125,
            "Mean":10362283.085796878,
            "Q3":10392063.158906251,
            "UpperFence":10474103.60460938,
            "Max":10436008.3209375,
            "InterquartileRange":54693.630468752235,
            "Outliers":[
               
            ],
            "StandardError":10219.304338928456,
            "Variance":2088683623.4328396,
            "StandardDeviation":45702.118369205156,
            "Skewness":-0.1242777170069375,
            "Kurtosis":2.31980277935226,
            "ConfidenceInterval":{
               "Mean":10362283.085796878,
               "Error":10219.304338928456,
               "Level":6,
               "Margin":20029.836504299772,
               "Lower":10342253.249292579,
               "Upper":10382312.922301177
            },
            "Percentiles":{
               "P0":10265993.7209375,
               "P25":10338555.905625,
               "P50":10360382.6953125,
               "P67":10373496.555659376,
               "P80":10400703.4841875,
               "P85":10417280.326718749,
               "P90":10424125.595812501,
               "P95":10435620.51609375,
               "P100":10436008.3209375
            }
         }
      },{
         "ShortInfo":"IntroJsonExport_Sleep20",
         "Namespace":"BenchmarkDotNet.Samples.Intro",
         "Type":"IntroJsonExport",
         "Method":"Sleep20",
         "MethodTitle":"Sleep20",
         "Parameters":"",
         "Properties":{
            "Mode":"Throughput",
            "Platform":"Host",
            "Jit":"Host",
            "Runtime":"Host",
            "GcMode":"Host",
            "WarmupCount":"Auto",
            "IterationCount":"Auto",
            "LaunchCount":"Auto",
            "IterationTime":"Auto",
            "Affinity":"Auto"
         },
         "Statistics":{
            "N":20,
            "Min":20258672.37,
            "LowerFence":20206333.269843742,
            "Q1":20325342.761249997,
            "Median":20362636.192500003,
            "Mean":20360791.931687497,
            "Q3":20404682.4221875,
            "UpperFence":20523691.913593754,
            "Max":20422396.073125,
            "InterquartileRange":79339.66093750298,
            "Outliers":[
               
            ],
            "StandardError":10728.817907277158,
            "Variance":2302150673.7502208,
            "StandardDeviation":47980.732317777525,
            "Skewness":-0.50826238372439869,
            "Kurtosis":2.11050327966268,
            "ConfidenceInterval":{
               "Mean":20360791.931687497,
               "Error":10728.817907277158,
               "Level":6,
               "Margin":21028.48309826323,
               "Lower":20339763.448589232,
               "Upper":20381820.414785761
            },
            "Percentiles":{
               "P0":20258672.37,
               "P25":20327638.975312497,
               "P50":20362636.192500003,
               "P67":20391669.3762875,
               "P80":20406370.68625,
               "P85":20412542.034406248,
               "P90":20414412.5376875,
               "P95":20416606.697718751,
               "P100":20422396.073125
            }
         }
      }
   ]
}

Sample: IntroExportXml

BenchmarkDotNet has a set of XML exporters. You can customize the following properties of these exporters:

  • fileNameSuffix: a string which be placed in the end of target file name.
  • indentXml=false/true: should we format xml or not.
  • excludeMeasurements=false/true: should we exclude detailed information about measurements or not (the final summary with statistics will be in the XML file anyway).

Source code

using System.Threading;
using BenchmarkDotNet.Attributes;

namespace BenchmarkDotNet.Samples
{
    [DryJob]
    [XmlExporterAttribute.Brief]
    [XmlExporterAttribute.Full]
    [XmlExporterAttribute.BriefCompressed]
    [XmlExporterAttribute.FullCompressed]
    [XmlExporter("-custom", indentXml: true, excludeMeasurements: true)]
    public class IntroExportXml
    {
        [Benchmark] public void Sleep10() => Thread.Sleep(10);
        [Benchmark] public void Sleep20() => Thread.Sleep(20);
    }
}

Output

Example of IntroXmlExport-report-brief.xml:

<?xml version="1.0" encoding="utf-8"?>
<Summary>
  <Title>IntroXmlExport</Title>
  <HostEnvironmentInfo>
    <BenchmarkDotNetCaption>BenchmarkDotNet</BenchmarkDotNetCaption>
    <BenchmarkDotNetVersion>0.10.9.20170805-develop</BenchmarkDotNetVersion>
    <OsVersion>Windows 10 Redstone 2 (10.0.15063)</OsVersion>
    <ProcessorName>Intel Core i7-3770K CPU 3.50GHz (Ivy Bridge)</ProcessorName>
    <ProcessorCount>8</ProcessorCount>
    <RuntimeVersion>.NET Framework 4.7 (CLR 4.0.30319.42000)</RuntimeVersion>
    <Architecture>64bit</Architecture>
    <HasAttachedDebugger>False</HasAttachedDebugger>
    <HasRyuJit>True</HasRyuJit>
    <Configuration>RELEASE</Configuration>
    <JitModules>clrjit-v4.7.2101.1</JitModules>
    <DotNetSdkVersion>1.0.4</DotNetSdkVersion>
    <ChronometerFrequency>
      <Hertz>3410220</Hertz>
    </ChronometerFrequency>
    <HardwareTimerKind>Tsc</HardwareTimerKind>
  </HostEnvironmentInfo>
  <Benchmarks>
    <Benchmark>
      <DisplayInfo>IntroXmlExport.Sleep10: DefaultJob</DisplayInfo>
      <Namespace>BenchmarkDotNet.Samples.Intro</Namespace>
      <Type>IntroXmlExport</Type>
      <Method>Sleep10</Method>
      <MethodTitle>Sleep10</MethodTitle>
      <Statistics>
        <N>15</N>
        <Min>10989865.8785938</Min>
        <LowerFence>10989836.0967969</LowerFence>
        <Q1>10990942.6053125</Q1>
        <Median>10991249.5870313</Median>
        <Mean>10991270.0524583</Mean>
        <Q3>10991680.2776563</Q3>
        <UpperFence>10992786.7861719</UpperFence>
        <Max>10992115.5501563</Max>
        <InterquartileRange>737.672343749553</InterquartileRange>
        <StandardError>148.484545262958</StandardError>
        <Variance>330714.902729213</Variance>
        <StandardDeviation>575.07817097262</StandardDeviation>
        <Skewness>-0.67759778074187</Skewness>
        <Kurtosis>3.14296703520386</Kurtosis>
        <ConfidenceInterval>
          <N>15</N>
          <Mean>10991270.0524583</Mean>
          <StandardError>148.484545262958</StandardError>
          <Level>L999</Level>
          <Margin>614.793505974065</Margin>
          <Lower>10990655.2589524</Lower>
          <Upper>10991884.8459643</Upper>
        </ConfidenceInterval>
        <Percentiles>
          <P0>10989865.8785938</P0>
          <P25>10991027.3689063</P25>
          <P50>10991249.5870313</P50>
          <P67>10991489.490875</P67>
          <P80>10991696.7722187</P80>
          <P85>10991754.5031875</P85>
          <P90>10991933.1939688</P90>
          <P95>10992067.441125</P95>
          <P100>10992115.5501563</P100>
        </Percentiles>
      </Statistics>
    </Benchmark>
  </Benchmarks>
</Summary>

Plots

You can install R to automatically get nice plots of your benchmark results. First, make sure Rscript.exe or Rscript is in your path, or define an R_HOME environment variable pointing to the R installation directory.
eg: If Rscript is located in /path/to/R/R-1.2.3/bin/Rscript, then R_HOME must point to /path/to/R/R-1.2.3/, it should not point to /path/to/R/R-1.2.3/bin
Use RPlotExporter.Default and CsvMeasurementsExporter.Default in your config, and the BuildPlots.R script in your bin directory will take care of the rest.

Examples:

<BenchmarkName>-barplot.png
<BenchmarkName>-boxplot.png
<BenchmarkName>-<MethodName>-density.png
<BenchmarkName>-<MethodName>-facetTimeline.png
<BenchmarkName>-<MethodName>-facetTimelineSmooth.png
<BenchmarkName>-<MethodName>-<JobName>-timelineSmooth.png
<BenchmarkName>-<MethodName>-<JobName>-timelineSmooth.png

A config example in C#:

public class Config : ManualConfig
{
    public Config()
    {
        Add(CsvMeasurementsExporter.Default);
        Add(RPlotExporter.Default);
    }
}

A config example in F#:

module MyBenchmark

open BenchmarkDotNet.Attributes
open BenchmarkDotNet.Configs
open BenchmarkDotNet.Exporters
open BenchmarkDotNet.Exporters.Csv
open MyProjectUnderTest

type MyConfig() as this =
    inherit ManualConfig()
    do
        this.Add(CsvMeasurementsExporter.Default)
        this.Add(RPlotExporter.Default)

[<
  MemoryDiagnoser; 
  Config(typeof<MyConfig>);
  RPlotExporter
>]
type MyPerformanceTests() =

    let someTestData = getTestDataAsList ()

    [<Benchmark>]
    member __.SomeTestCase() = 
        someTestData |> myFunctionUnderTest

CSV

The CSV file format is often used to graph the output or to analyze the results programmatically. The CSV exporter may be configured to produce sanitized output, where cell values are numerals and their units are predefined.

The CSV exporter and other compatible exporters may consume an instance of ISummaryStyle that defines how the output should look like:

Property Remarks Default
PrintUnitsInHeader If true, units will be displayed in the header row false
PrintUnitsInContent If true, units will be appended to the value true
TimeUnit If null, unit will be automatically selected null
SizeUnit If null, unit will be automatically selected null

Example of CSV exporter configured to always use microseconds, kilobytes, and to render units only in column headers:

var exporter = new CsvExporter(
    CsvSeparator.CurrentCulture,
    new SummaryStyle(
        cultureInfo: System.Globalization.CultureInfo.CurrentCulture,
        printUnitsInHeader: true,
        printUnitsInContent: false,
        timeUnit: Perfolizer.Horology.TimeUnit.Microsecond,
        sizeUnit: SizeUnit.KB
    ));

var config = ManualConfig.CreateMinimumViable().AddExporter(exporter);

Excerpt from the resulting CSV file:

Method,...,Mean [us],Error [us],StdDev [us],Min [us],Max [us],Allocated [KB]
Benchmark,...,"37,647.6","32,717.9","21,640.9","11,209.2","59,492.6",1.58