File: BenchmarksTest.cs
Web Access
Project: src\test\Microsoft.ML.Benchmarks.Tests\Microsoft.ML.Benchmarks.Tests.csproj (Microsoft.ML.Benchmarks.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
using Microsoft.ML.PerformanceTests.Harness;
using Microsoft.ML.TestFramework;
using Microsoft.ML.TestFramework.Attributes;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.ML.PerformanceTests.Tests
{
    public class TestConfig : RecommendedConfig
    {
        protected override Job GetJobDefinition() => Job.Dry; // Job.Dry runs the benchmark just once
    }
 
    public class BenchmarksTest : BaseTestClass
    {
        public BenchmarksTest(ITestOutputHelper output) : base(output)
        {
            this.output = output;
        }
 
        private ITestOutputHelper output { get; }
 
        public static TheoryData<Type> GetBenchmarks()
        {
            TheoryData<Type> benchmarks = new TheoryData<Type>();
            Assembly asm = typeof(StochasticDualCoordinateAscentClassifierBench).Assembly;
 
            var types = from type in asm.GetTypes()
                        where Attribute.IsDefined(type, typeof(CIBenchmark))
                        select type;
 
            foreach (Type type in types)
            {
                benchmarks.Add(type);
            }
            return benchmarks;
        }
 
        [BenchmarkTheory]
        [MemberData(nameof(GetBenchmarks))]
        public void BenchmarksProjectIsNotBroken(Type type)
        {
            var summary = BenchmarkRunner.Run(type, new TestConfig().AddLogger(new OutputLogger(output)));
 
            Assert.False(summary.HasCriticalValidationErrors, "The \"Summary\" should have NOT \"HasCriticalValidationErrors\"");
 
            Assert.True(summary.Reports.Any(), "The \"Summary\" should contain at least one \"BenchmarkReport\" in the \"Reports\" collection");
 
            Assert.True(summary.Reports.All(r => r.BuildResult.IsBuildSuccess),
                "The following benchmarks failed to build: " +
                string.Join(", ", summary.Reports.Where(r => !r.BuildResult.IsBuildSuccess).Select(r => r.BenchmarkCase.DisplayInfo)));
 
            Assert.True(summary.Reports.All(r => r.ExecuteResults != null),
                "The following benchmarks don't have any execution results: " +
                string.Join(", ", summary.Reports.Where(r => r.ExecuteResults == null).Select(r => r.BenchmarkCase.DisplayInfo)));
 
            Assert.True(summary.Reports.All(r => r.ExecuteResults.Any(er => er.FoundExecutable && er.Results.Any())),
                "All reports should have at least one \"ExecuteResult\" with \"FoundExecutable\" = true and at least one \"Data\" item");
 
            Assert.True(summary.Reports.All(report => report.AllMeasurements.Any()),
                "All reports should have at least one \"Measurement\" in the \"AllMeasurements\" collection");
        }
    }
 
    public class OutputLogger : AccumulationLogger
    {
        private readonly ITestOutputHelper _testOutputHelper;
        private string _currentLine = "";
 
        public OutputLogger(ITestOutputHelper testOutputHelper)
        {
            this._testOutputHelper = testOutputHelper ?? throw new ArgumentNullException(nameof(testOutputHelper));
        }
 
        public override void Write(LogKind logKind, string text)
        {
            _currentLine += text;
            base.Write(logKind, text);
        }
 
        public override void WriteLine()
        {
            _testOutputHelper.WriteLine(_currentLine);
            _currentLine = "";
            base.WriteLine();
        }
 
        public override void WriteLine(LogKind logKind, string text)
        {
            _testOutputHelper.WriteLine(_currentLine + text);
            _currentLine = "";
            base.WriteLine(logKind, text);
        }
    }
}