From b68e111e3dabf0633f9b5e2bf71e1f1f57d536c3 Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Wed, 27 Sep 2023 00:37:42 +1000 Subject: [PATCH 01/10] Add VSTest Adapter --- BenchmarkDotNet.sln | 11 +- .../BenchmarkDotNet.Samples.FSharp.fsproj | 3 + .../BenchmarkDotNet.Samples.csproj | 3 + .../BenchmarkCaseExtensions.cs | 110 +++++++++ .../BenchmarkDotNet.TestAdapter.csproj | 22 ++ .../BenchmarkEnumerator.cs | 30 +++ .../BenchmarkExecutor.cs | 86 ++++++++ .../Remoting/BenchmarkEnumeratorWrapper.cs | 35 +++ .../Remoting/BenchmarkExecutorWrapper.cs | 23 ++ .../Remoting/MessageLoggerWrapper.cs | 23 ++ .../Remoting/SerializationHelpers.cs | 20 ++ .../Remoting/TestExecutionRecorderWrapper.cs | 39 ++++ .../VSTestAdapter.cs | 208 ++++++++++++++++++ .../VSTestEventProcessor.cs | 187 ++++++++++++++++ .../VSTestLogger.cs | 58 +++++ .../VSTestProperties.cs | 63 ++++++ .../Properties/AssemblyInfo.cs | 2 + 17 files changed, 921 insertions(+), 2 deletions(-) create mode 100644 src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj create mode 100644 src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/Remoting/TestExecutionRecorderWrapper.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs diff --git a/BenchmarkDotNet.sln b/BenchmarkDotNet.sln index ba31552c8a..eed29c80af 100644 --- a/BenchmarkDotNet.sln +++ b/BenchmarkDotNet.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34004.107 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D6597E3A-6892-4A68-8E14-042FC941FDA2}" EndProject @@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkDotNet.Diagnostics EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkDotNet.IntegrationTests.ManualRunning.MultipleFrameworks", "tests\BenchmarkDotNet.IntegrationTests.ManualRunning.MultipleFrameworks\BenchmarkDotNet.IntegrationTests.ManualRunning.MultipleFrameworks.csproj", "{AACA2C63-A85B-47AB-99FC-72C3FF408B14}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.TestAdapter", "src\BenchmarkDotNet.TestAdapter\BenchmarkDotNet.TestAdapter.csproj", "{4C9C89B8-7C4E-4ECF-B3C9-324C8772EDAC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -137,6 +139,10 @@ Global {AACA2C63-A85B-47AB-99FC-72C3FF408B14}.Debug|Any CPU.Build.0 = Debug|Any CPU {AACA2C63-A85B-47AB-99FC-72C3FF408B14}.Release|Any CPU.ActiveCfg = Release|Any CPU {AACA2C63-A85B-47AB-99FC-72C3FF408B14}.Release|Any CPU.Build.0 = Release|Any CPU + {4C9C89B8-7C4E-4ECF-B3C9-324C8772EDAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C9C89B8-7C4E-4ECF-B3C9-324C8772EDAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C9C89B8-7C4E-4ECF-B3C9-324C8772EDAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C9C89B8-7C4E-4ECF-B3C9-324C8772EDAC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -162,6 +168,7 @@ Global {B620D10A-CD8E-4A34-8B27-FD6257E63AD0} = {63B94FD6-3F3D-4E04-9727-48E86AC4384C} {C5BDA61F-3A56-4B59-901D-0A17E78F4076} = {D6597E3A-6892-4A68-8E14-042FC941FDA2} {AACA2C63-A85B-47AB-99FC-72C3FF408B14} = {14195214-591A-45B7-851A-19D3BA2413F9} + {4C9C89B8-7C4E-4ECF-B3C9-324C8772EDAC} = {D6597E3A-6892-4A68-8E14-042FC941FDA2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4D9AF12B-1F7F-45A7-9E8C-E4E46ADCBD1F} diff --git a/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj b/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj index 55045658d8..21bc1adec8 100644 --- a/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj +++ b/samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj @@ -6,12 +6,14 @@ Exe net462;net7.0 + false + @@ -25,5 +27,6 @@ + diff --git a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj index 180148454a..ec5c070647 100644 --- a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj +++ b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj @@ -11,6 +11,7 @@ AnyCPU true $(NoWarn);CA1018;CA5351;CA1825 + false @@ -19,10 +20,12 @@ + + diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs new file mode 100644 index 0000000000..80c554b6df --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs @@ -0,0 +1,110 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Characteristics; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Extensions; +using BenchmarkDotNet.Running; +using Microsoft.TestPlatform.AdapterUtilities; +using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using System; +using System.Linq; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// A set of extensions for BenchmarkCase to support converting to VSTest TestCase objects. + /// + internal static class BenchmarkCaseExtensions + { + /// + /// Converts a BDN BenchmarkCase to a VSTest TestCase. + /// + /// The BenchmarkCase to convert. + /// The dll or exe of the benchmark project. + /// Whether or not the display name should include the job name. + /// The VSTest TestCase. + internal static TestCase ToVSTestCase(this BenchmarkCase benchmarkCase, string source, bool includeJobInName=false) + { + var benchmarkMethod = benchmarkCase.Descriptor.WorkloadMethod; + var fullClassName = benchmarkCase.Descriptor.Type.FullName; + var benchmarkMethodName = benchmarkCase.Descriptor.WorkloadMethodDisplayInfo; + var benchmarkFullName = $"{fullClassName}.{benchmarkMethodName}"; + + ManagedNameHelper.GetManagedName(benchmarkMethod, out var managedType, out var managedMethod, out var hierarchyValues); + hierarchyValues[HierarchyConstants.Levels.ContainerIndex] = null; // Gets set by the test explorer window to the test project name + if (includeJobInName) + { + hierarchyValues[HierarchyConstants.Levels.TestGroupIndex] += $" [{benchmarkCase.GetUnrandomizedJobDisplayInfo()}]"; + } + + var hasManagedMethodAndTypeProperties = !string.IsNullOrWhiteSpace(managedType) && !string.IsNullOrWhiteSpace(managedMethod); + + var vsTestCase = new TestCase(benchmarkFullName, VSTestAdapter.ExecutorUri, source) + { + DisplayName = FullNameProvider.GetBenchmarkName(benchmarkCase), + Id = GetTestCaseId(benchmarkCase), + }; + + if (includeJobInName) + { + vsTestCase.DisplayName += $" [{benchmarkCase.GetUnrandomizedJobDisplayInfo()}]"; + } + + var benchmarkAttribute = benchmarkMethod.ResolveAttribute(); + if (benchmarkAttribute != null) + { + vsTestCase.CodeFilePath = benchmarkAttribute.SourceCodeFile; + vsTestCase.LineNumber = benchmarkAttribute.SourceCodeLineNumber; + } + + vsTestCase.SetPropertyValue(VSTestProperties.HierarchyProperty, hierarchyValues.ToArray()); + vsTestCase.SetPropertyValue(VSTestProperties.TestCategoryProperty, benchmarkCase.Descriptor.Categories); + if (hasManagedMethodAndTypeProperties) + { + vsTestCase.SetPropertyValue(VSTestProperties.ManagedTypeProperty, managedType); + vsTestCase.SetPropertyValue(VSTestProperties.ManagedMethodProperty, managedMethod); + vsTestCase.SetPropertyValue(VSTestProperties.TestClassNameProperty, managedType); + } + else + { + vsTestCase.SetPropertyValue(VSTestProperties.TestClassNameProperty, fullClassName); + } + + return vsTestCase; + } + + /// + /// If an ID is not provided, a random string is used for the ID. This method will identify if randomness was + /// used for the ID and return the Job's DisplayInfo with that randomness removed so that the same benchmark + /// can be referenced across multiple processes. + /// + /// The benchmark case. + /// The benchmark case' job's DisplayInfo without randomness. + internal static string GetUnrandomizedJobDisplayInfo(this BenchmarkCase benchmarkCase) + { + var jobDisplayInfo = benchmarkCase.Job.DisplayInfo; + if (!benchmarkCase.Job.HasValue(CharacteristicObject.IdCharacteristic) && benchmarkCase.Job.ResolvedId.StartsWith("Job-", StringComparison.OrdinalIgnoreCase)) + { + // Replace Job-ABCDEF with Job + jobDisplayInfo = "Job" + jobDisplayInfo.Substring(benchmarkCase.Job.ResolvedId.Length); + } + + return jobDisplayInfo; + } + + /// + /// Gets an ID for a given BenchmarkCase that is uniquely identifiable from discovery to execution phase. + /// + /// The benchmark case. + /// The test case ID. + internal static Guid GetTestCaseId(this BenchmarkCase benchmarkCase) + { + var testIdProvider = new TestIdProvider(); + testIdProvider.AppendString(VSTestAdapter.ExecutorUriString); + testIdProvider.AppendString(benchmarkCase.Descriptor.DisplayInfo); + testIdProvider.AppendString(benchmarkCase.GetUnrandomizedJobDisplayInfo()); + testIdProvider.AppendString(benchmarkCase.Parameters.DisplayInfo); + return testIdProvider.GetId(); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj b/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj new file mode 100644 index 0000000000..dc8664400b --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0;net462 + BenchmarkDotNet.TestAdapter + BenchmarkDotNet.TestAdapter + BenchmarkDotNet.TestAdapter + True + enable + + + + + + + + + + + + + diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs new file mode 100644 index 0000000000..a64fc23017 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs @@ -0,0 +1,30 @@ +using BenchmarkDotNet.Extensions; +using BenchmarkDotNet.Helpers; +using BenchmarkDotNet.Running; +using System.Linq; +using System.Reflection; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// A class used for enumerating all the benchmarks in a source. + /// + internal static class BenchmarkEnumerator + { + /// + /// Returns all the BenchmarkRunInfo objects from a given source. + /// + /// The dll or exe of the benchmark project. + /// The benchmarks inside the source. + public static BenchmarkRunInfo[] GetBenchmarksFromSource(string source) + { + var assembly = Assembly.LoadFrom(source); + + // TODO: Allow for defining a base config inside the BDN project that is used by the VSTest Adapter. + return GenericBenchmarksBuilder.GetRunnableBenchmarks(assembly.GetRunnableBenchmarks()) + .Select(type => BenchmarkConverter.TypeToBenchmarks(type)) + .Where(runInfo => runInfo.BenchmarksCases.Length > 0) + .ToArray(); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs new file mode 100644 index 0000000000..4eb8231e18 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs @@ -0,0 +1,86 @@ +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Running; +using BenchmarkDotNet.TestAdapter.Remoting; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// A class used for executing benchmarks + /// + internal class BenchmarkExecutor + { + private readonly CancellationTokenSource cts = new (); + + /// + /// Runs all the benchmarks in the given source, updating the TestExecutionRecorder as they get run. + /// + /// The dll or exe of the benchmark project. + /// The interface used to record the current test execution progress. + /// + /// An optional list of benchmark IDs specifying which benchmarks to run. + /// These IDs are the same as the ones generated for the VSTest TestCase. + /// + public void RunBenchmarks(string source, TestExecutionRecorderWrapper recorder, HashSet? benchmarkIds = null) + { + var benchmarks = BenchmarkEnumerator.GetBenchmarksFromSource(source); + var testCases = new List(); + + var filteredBenchmarks = new List(); + foreach (var benchmark in benchmarks) + { + var needsJobInfo = benchmark.BenchmarksCases.Select(c => c.Job.DisplayInfo).Distinct().Count() > 1; + var filteredCases = new List(); + foreach (var benchmarkCase in benchmark.BenchmarksCases) + { + var testId = benchmarkCase.GetTestCaseId(); + if (benchmarkIds != null && benchmarkIds.Contains(testId)) + { + filteredCases.Add(benchmarkCase); + testCases.Add(benchmarkCase.ToVSTestCase(source, needsJobInfo)); + } + } + + if (filteredCases.Count > 0) + { + filteredBenchmarks.Add(new BenchmarkRunInfo(filteredCases.ToArray(), benchmark.Type, benchmark.Config)); + } + } + + benchmarks = filteredBenchmarks.ToArray(); + + if (benchmarks.Length == 0) + return; + + // Create an event processor which will subscribe to events and push them to VSTest + var eventProcessor = new VSTestEventProcessor(testCases, recorder, cts.Token); + + // Create a logger which will forward all log messages in BDN to the VSTest logger. + var logger = new VSTestLogger(recorder.GetLogger()); + + // Modify all the benchmarks so that the event process and logger is added. + benchmarks = benchmarks + .Select(b => new BenchmarkRunInfo( + b.BenchmarksCases, + b.Type, + b.Config.AddEventProcessor(eventProcessor).AddLogger(logger).CreateImmutableConfig())) + .ToArray(); + + // Run all the benchmarks, and ensure that any tests that don't have a result yet are sent. + BenchmarkRunner.Run(benchmarks); + eventProcessor.SendUnsentTestResults(); + } + + /// + /// Stop the benchmarks when next able. + /// + public void Cancel() + { + cts.Cancel(); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs new file mode 100644 index 0000000000..d6de5178ea --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BenchmarkDotNet.TestAdapter.Remoting +{ + /// + /// A wrapper around the BenchmarkEnumerator for passing data across AppDomain boundaries. + /// + internal class BenchmarkEnumeratorWrapper : MarshalByRefObject + { + /// + /// Gets a list of VSTest TestCases from the given source. + /// Each test case is serialize into a string so that it can be used across AppDomain boundaries. + /// + /// The dll or exe of the benchmark project. + /// The serialized test cases. + public List GetTestCasesFromSourceSerialized(string source) + { + var serializedTestCases = new List(); + foreach (var runInfo in BenchmarkEnumerator.GetBenchmarksFromSource(source)) + { + // If all the benchmarks have the same job, then no need to include job info. + var needsJobInfo = runInfo.BenchmarksCases.Select(c => c.Job.DisplayInfo).Distinct().Count() > 1; + foreach (var benchmarkCase in runInfo.BenchmarksCases) + { + var testCase = benchmarkCase.ToVSTestCase(source, needsJobInfo); + serializedTestCases.Add(SerializationHelpers.Serialize(testCase)); + } + } + + return serializedTestCases; + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs new file mode 100644 index 0000000000..b94e7aa603 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace BenchmarkDotNet.TestAdapter.Remoting +{ + /// + /// A wrapper around the BenchmarkExecutor that works across AppDomain boundaries. + /// + internal class BenchmarkExecutorWrapper : MarshalByRefObject + { + private readonly BenchmarkExecutor benchmarkExecutor = new (); + + public void RunBenchmarks(string source, TestExecutionRecorderWrapper recorder, HashSet? benchmarkIds = null) + { + benchmarkExecutor.RunBenchmarks(source, recorder, benchmarkIds); + } + + public void Cancel() + { + benchmarkExecutor.Cancel(); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs new file mode 100644 index 0000000000..db603a98cf --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs @@ -0,0 +1,23 @@ +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using System; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// A wrapper around an IMessageLogger that works across AppDomain boundaries. + /// + internal class MessageLoggerWrapper : MarshalByRefObject, IMessageLogger + { + private readonly IMessageLogger logger; + + public MessageLoggerWrapper(IMessageLogger logger) + { + this.logger = logger; + } + + public void SendMessage(TestMessageLevel testMessageLevel, string message) + { + logger.SendMessage(testMessageLevel, message); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs new file mode 100644 index 0000000000..1c1945b236 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs @@ -0,0 +1,20 @@ +using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; + +namespace BenchmarkDotNet.TestAdapter.Remoting +{ + /// + /// A set of helper methods for serializing and deserializing the VSTest TestCases and TestReports. + /// + internal static class SerializationHelpers + { + public static string Serialize(T data) + { + return JsonDataSerializer.Instance.Serialize(data, version: 7); + } + + public static T Deserialize(string data) + { + return JsonDataSerializer.Instance.Deserialize(data, version: 7)!; + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/TestExecutionRecorderWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/TestExecutionRecorderWrapper.cs new file mode 100644 index 0000000000..0669e79019 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/TestExecutionRecorderWrapper.cs @@ -0,0 +1,39 @@ +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; +using System; + +namespace BenchmarkDotNet.TestAdapter.Remoting +{ + /// + /// A wrapper around the ITestExecutionRecorder which works across AppDomain boundaries. + /// + internal class TestExecutionRecorderWrapper : MarshalByRefObject + { + private readonly ITestExecutionRecorder testExecutionRecorder; + + public TestExecutionRecorderWrapper(ITestExecutionRecorder testExecutionRecorder) + { + this.testExecutionRecorder = testExecutionRecorder; + } + + public MessageLoggerWrapper GetLogger() + { + return new MessageLoggerWrapper(testExecutionRecorder); + } + + internal void RecordStart(string serializedTestCase) + { + testExecutionRecorder.RecordStart(SerializationHelpers.Deserialize(serializedTestCase)); + } + + internal void RecordEnd(string serializedTestCase, TestOutcome testOutcome) + { + testExecutionRecorder.RecordEnd(SerializationHelpers.Deserialize(serializedTestCase), testOutcome); + } + + internal void RecordResult(string serializedTestResult) + { + testExecutionRecorder.RecordResult(SerializationHelpers.Deserialize(serializedTestResult)); + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs b/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs new file mode 100644 index 0000000000..5fa6a13024 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs @@ -0,0 +1,208 @@ +using BenchmarkDotNet.TestAdapter.Remoting; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// Discovers and executes benchmarks using the VSTest protocol. + /// + [ExtensionUri(ExecutorUriString)] + [DefaultExecutorUri(ExecutorUriString)] + [FileExtension(".dll")] + [FileExtension(".exe")] + public class VSTestAdapter : ITestExecutor, ITestDiscoverer + { + // This URI is used to identify the adapter. + internal const string ExecutorUriString = "executor://BenchmarkDotNet.TestAdapter"; + internal static readonly Uri ExecutorUri = new Uri(ExecutorUriString); + + /// + /// Cancellation token used to stop any benchmarks that are currently running. + /// + private CancellationTokenSource? cts = null; + + /// + /// Discovers the benchmarks. + /// + /// List of assemblies to search for benchmarks in. + /// A context that the discovery is performed in. + /// Logger that sends messages back to VSTest host. + /// Interface that provides methods for sending discovered benchmarks back to the host. + public void DiscoverTests( + IEnumerable sources, + IDiscoveryContext discoveryContext, + IMessageLogger logger, + ITestCaseDiscoverySink discoverySink) + { + foreach (var source in sources) + { + ValidateSourceOrThrow(source); + foreach (var testCase in GetVSTestCasesFromSource(source, logger)) + { + discoverySink.SendTestCase(testCase); + } + } + } + + /// + /// Runs a given set of test cases that represent benchmarks. + /// + /// The tests to run. + /// A context that the run is performed in. + /// Interface used for communicating with the VSTest host. + public void RunTests(IEnumerable? tests, IRunContext? runContext, IFrameworkHandle? frameworkHandle) + { + if (tests == null) + throw new ArgumentNullException(nameof(tests)); + if (frameworkHandle == null) + throw new ArgumentNullException(nameof(frameworkHandle)); + + cts ??= new CancellationTokenSource(); + + foreach (var testsPerSource in tests.GroupBy(t => t.Source)) + RunBenchmarks(testsPerSource.Key, frameworkHandle, testsPerSource); + + cts = null; + } + + /// + /// Runs all benchmarks in the given set of sources (assemblies). + /// + /// The assemblies to run. + /// A context that the run is performed in. + /// Interface used for communicating with the VSTest host. + public void RunTests(IEnumerable? sources, IRunContext? runContext, IFrameworkHandle? frameworkHandle) + { + if (sources == null) + throw new ArgumentNullException(nameof(sources)); + if (frameworkHandle == null) + throw new ArgumentNullException(nameof(frameworkHandle)); + + cts ??= new CancellationTokenSource(); + + foreach (var source in sources) + RunBenchmarks(source, frameworkHandle); + + cts = null; + } + + /// + /// Stops any currently running benchmarks. + /// + public void Cancel() + { + cts?.Cancel(); + } + + /// + /// Gets the VSTest test cases in the given source. + /// + /// The dll or exe of the benchmark project. + /// A logger that sends logs to VSTest. + /// The VSTest test cases inside the given source. + private static List GetVSTestCasesFromSource(string source, IMessageLogger logger) + { + ValidateSourceOrThrow(source); + + try + { + // Ensure that the test enumeration is done inside the context of the source directory. + var enumerator = (BenchmarkEnumeratorWrapper)CreateIsolatedType(typeof(BenchmarkEnumeratorWrapper), source); + var testCases = enumerator + .GetTestCasesFromSourceSerialized(source) + .Select(SerializationHelpers.Deserialize) + .ToList(); + + // Validate that all test ids are unique + var idLookup = new Dictionary(); + foreach (var testCase in testCases) + { + if (idLookup.TryGetValue(testCase.Id, out var matchingCase)) + throw new Exception($"Encountered Duplicate Test ID: '{testCase.DisplayName}' and '{matchingCase}'"); + + idLookup[testCase.Id] = testCase.DisplayName; + } + + return testCases; + } + catch (Exception ex) + { + logger.SendMessage(TestMessageLevel.Error, $"Failed to load benchmarks from source\n{ex}"); + throw; + } + } + + /// + /// Runs the benchmarks in the given source. + /// + /// The dll or exe of the benchmark project. + /// An interface used to communicate with the VSTest host. + /// + /// The specific test cases to be run if specified. + /// If unspecified, runs all the test cases in the source. + /// + private void RunBenchmarks(string source, IFrameworkHandle frameworkHandle, IEnumerable? testCases = null) + { + ValidateSourceOrThrow(source); + + // Create a HashSet of all the TestCase IDs to be run if specified. + var caseIds = testCases == null ? null : new HashSet(testCases.Select(c => c.Id)); + + try + { + // Ensure that test execution is done inside the context of the source directory. + var executor = (BenchmarkExecutorWrapper)CreateIsolatedType(typeof(BenchmarkExecutorWrapper), source); + cts?.Token.Register(executor.Cancel); + + executor.RunBenchmarks(source, new TestExecutionRecorderWrapper(frameworkHandle), caseIds); + } + catch (Exception ex) + { + frameworkHandle.SendMessage(TestMessageLevel.Error, $"Failed to run benchmarks in source\n{ex}"); + throw; + } + } + + /// + /// This will create the given type in a child AppDomain when used in .NET Framework. + /// If not in the .NET Framework, it will use the current + /// + /// The type to create. + /// The dll or exe of the benchmark project. + /// The created object. + private static object CreateIsolatedType(Type type, string source) + { +#if NETFRAMEWORK + var appBase = Path.GetDirectoryName(source); + var setup = new AppDomainSetup { ApplicationBase = appBase }; + var domainName = $"Isolated Domain for {type.Name}"; + var appDomain = AppDomain.CreateDomain(domainName, null, setup); + return appDomain.CreateInstanceAndUnwrap( + type.Assembly.FullName, type.FullName, false, BindingFlags.Default, null, null, null, null); +#else + return Activator.CreateInstance(type); +#endif + } + + private static void ValidateSourceOrThrow(string source) + { + if (string.IsNullOrEmpty(source)) + throw new ArgumentException($"'{nameof(source)}' cannot be null or whitespace.", nameof(source)); + + if (!Path.HasExtension(source)) + throw new NotSupportedException($"Missing extension on source '{source}', must have the extension '.dll' or '.exe'."); + + var extension = Path.GetExtension(source); + if (!string.Equals(extension, ".dll") && !string.Equals(extension, ".exe")) + throw new NotSupportedException($"Unsupported extension on source '{source}', must have the extension '.dll' or '.exe'."); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs b/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs new file mode 100644 index 0000000000..6a17016db6 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs @@ -0,0 +1,187 @@ +using BenchmarkDotNet.EventProcessors; +using BenchmarkDotNet.Extensions; +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Running; +using BenchmarkDotNet.TestAdapter.Remoting; +using BenchmarkDotNet.Toolchains.Results; +using BenchmarkDotNet.Validators; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Threading; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// An event processor which will pass on benchmark execution information to VSTest. + /// + internal class VSTestEventProcessor : EventProcessor + { + private readonly Dictionary cases; + private readonly TestExecutionRecorderWrapper recorder; + private readonly CancellationToken cancellationToken; + private readonly Stopwatch runTimerStopwatch = new (); + private readonly Dictionary testResults = new (); + private readonly HashSet sentTestResults = new (); + + public VSTestEventProcessor( + List cases, + TestExecutionRecorderWrapper recorder, + CancellationToken cancellationToken) + { + this.cases = cases.ToDictionary(c => c.Id); + this.recorder = recorder; + this.cancellationToken = cancellationToken; + } + + public override void OnValidationError(ValidationError validationError) + { + // If the error is not linked to a benchmark case, then set the error on all benchmarks + var errorCases = validationError.BenchmarkCase == null + ? cases.Values.ToList() + : new List { cases[validationError.BenchmarkCase.GetTestCaseId()] }; + foreach (var testCase in errorCases) + { + var testResult = GetOrCreateTestResult(testCase); + + if (validationError.IsCritical) + { + // Fail if there is a critical validation error + testResult.Outcome = TestOutcome.Failed; + + // Append validation error message to end of test case error message + testResult.ErrorMessage = testResult.ErrorMessage == null + ? validationError.Message + : $"{testResult.ErrorMessage}\n{validationError.Message}"; + + // The test result is not sent yet, in case there are multiple validation errors that need to be sent. + } + else + { + // If the validation error is not critical, append it as a message + testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, $"WARNING: {validationError.Message}\n")); + } + } + } + + public override void OnBuildComplete(BuildPartition buildPartition, BuildResult buildResult) + { + // Only need to handle build failures + if (!buildResult.IsBuildSuccess) + { + foreach (var benchmarkBuildInfo in buildPartition.Benchmarks) + { + var testCase = cases[benchmarkBuildInfo.BenchmarkCase.GetTestCaseId()]; + var testResult = GetOrCreateTestResult(testCase); + + if (buildResult.GenerateException != null) + testResult.ErrorMessage = $"// Generate Exception: {buildResult.GenerateException.Message}"; + else if (!buildResult.IsBuildSuccess && buildResult.TryToExplainFailureReason(out string reason)) + testResult.ErrorMessage = $"// Build Error: {reason}"; + else if (buildResult.ErrorMessage != null) + testResult.ErrorMessage = $"// Build Error: {buildResult.ErrorMessage}"; + testResult.Outcome = TestOutcome.Failed; + + // Send the result immediately + RecordStart(testCase); + RecordEnd(testCase, testResult.Outcome); + RecordResult(testResult); + sentTestResults.Add(testCase.Id); + } + } + } + + public override void OnStartRunBenchmark(BenchmarkCase benchmarkCase) + { + // TODO: add proper cancellation support to BDN so that we don't need to do cancellation through the event processor + cancellationToken.ThrowIfCancellationRequested(); + + var testCase = cases[benchmarkCase.GetTestCaseId()]; + var testResult = GetOrCreateTestResult(testCase); + testResult.StartTime = DateTimeOffset.UtcNow; + + RecordStart(testCase); + runTimerStopwatch.Restart(); + } + + public override void OnEndRunBenchmark(BenchmarkCase benchmarkCase, BenchmarkReport report) + { + var testCase = cases[benchmarkCase.GetTestCaseId()]; + var testResult = GetOrCreateTestResult(testCase); + testResult.EndTime = DateTimeOffset.UtcNow; + testResult.Duration = runTimerStopwatch.Elapsed; + testResult.Outcome = report.Success ? TestOutcome.Passed : TestOutcome.Failed; + + var resultRuns = report.GetResultRuns(); + + // Provide the raw result runs data. + testResult.SetPropertyValue(VSTestProperties.Measurement, resultRuns.Select(m => m.Nanoseconds.ToString()).ToArray()); + + // Add a message to the TestResult which contains the results summary. + testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, report.BenchmarkCase.DisplayInfo + "\n")); + testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, $"Runtime = {report.GetRuntimeInfo()}; GC = {report.GetGcInfo()}\n")); + + var statistics = resultRuns.GetStatistics(); + var cultureInfo = CultureInfo.InvariantCulture; + var formatter = statistics.CreateNanosecondFormatter(cultureInfo); + var statisticsOutput = statistics.ToString(cultureInfo, formatter, calcHistogram: true); + testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, statisticsOutput)); + + RecordEnd(testResult.TestCase, testResult.Outcome); + RecordResult(testResult); + sentTestResults.Add(testCase.Id); + } + + /// + /// Iterate through all the benchmarks that were scheduled to run, and if they haven't been sent yet, send the result through. + /// + public void SendUnsentTestResults() + { + foreach (var testCase in cases.Values) + { + if (!sentTestResults.Contains(testCase.Id)) + { + var testResult = GetOrCreateTestResult(testCase); + if (testResult.Outcome == TestOutcome.None) + testResult.Outcome = TestOutcome.Skipped; + RecordStart(testCase); + RecordEnd(testCase, testResult.Outcome); + RecordResult(testResult); + } + } + } + + private TestResult GetOrCreateTestResult(TestCase testCase) + { + if (testResults.TryGetValue(testCase.Id, out var testResult)) + return testResult; + + var newResult = new TestResult(testCase) + { + ComputerName = Environment.MachineName, + DisplayName = testCase.DisplayName + }; + + testResults[testCase.Id] = newResult; + return newResult; + } + + private void RecordStart(TestCase testCase) + { + recorder.RecordStart(SerializationHelpers.Serialize(testCase)); + } + + private void RecordEnd(TestCase testCase, TestOutcome testOutcome) + { + recorder.RecordEnd(SerializationHelpers.Serialize(testCase), testOutcome); + } + + private void RecordResult(TestResult testResult) + { + recorder.RecordResult(SerializationHelpers.Serialize(testResult)); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs b/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs new file mode 100644 index 0000000000..ab514004bd --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs @@ -0,0 +1,58 @@ +using BenchmarkDotNet.Loggers; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using System.Text; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// A class to send logs from BDN to the VSTest output log. + /// + internal class VSTestLogger : ILogger + { + private readonly IMessageLogger messageLogger; + private readonly StringBuilder currentLine = new StringBuilder(); + private TestMessageLevel currentLevel = TestMessageLevel.Informational; + + public VSTestLogger(IMessageLogger logger) + { + messageLogger = logger; + } + + public string Id => nameof(VSTestLogger); + + public int Priority => 0; + + public void Flush() + { + WriteLine(); + } + + public void Write(LogKind logKind, string text) + { + currentLine.Append(text); + + // Assume that if the log kind if an error, that the whole line is treated as an error + // The level will be reset to Informational when WriteLine() is called. + if (logKind == LogKind.Error) + currentLevel = TestMessageLevel.Error; + } + + public void WriteLine() + { + // The VSTest logger throws an error on logging empty or whitespace strings, so skip them. + if (currentLine.Length == 0) + return; + + messageLogger.SendMessage(currentLevel, currentLine.ToString()); + + currentLevel = TestMessageLevel.Informational; + currentLine.Clear(); + } + + public void WriteLine(LogKind logKind, string text) + { + Write(logKind, text); + WriteLine(); + } + } +} diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs b/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs new file mode 100644 index 0000000000..d35aad5234 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs @@ -0,0 +1,63 @@ +using Microsoft.TestPlatform.AdapterUtilities; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; + +namespace BenchmarkDotNet.TestAdapter +{ + /// + /// A class that contains all the properties that can be set on VSTest TestCase and TestResults. + /// Some of these properties are well known as they are also used by VSTest adapters for other test libraries. + /// + internal static class VSTestProperties + { + internal static readonly TestProperty Measurement = TestProperty.Register( + "BenchmarkDotNet.TestAdapter.Measurements", + "Measurements", + typeof(string[]), + TestPropertyAttributes.Hidden, + typeof(TestResult)); + + internal static readonly TestProperty TestCategoryProperty = TestProperty.Register( + "BenchmarkDotNet.TestAdapter.TestCategory", + "TestCategory", + typeof(string[]), + TestPropertyAttributes.Hidden, + typeof(TestCase)); + + internal static readonly TestProperty TestClassNameProperty = TestProperty.Register( + "BenchmarkDotNet.TestAdapter.TestClassName", + "ClassName", + typeof(string), + TestPropertyAttributes.Hidden, + typeof(TestCase)); + + internal static readonly TestProperty ManagedTypeProperty = TestProperty.Register( + id: ManagedNameConstants.ManagedTypePropertyId, + label: ManagedNameConstants.ManagedTypeLabel, + category: string.Empty, + description: string.Empty, + valueType: typeof(string), + validateValueCallback: o => !string.IsNullOrWhiteSpace(o as string), + attributes: TestPropertyAttributes.Hidden, + owner: typeof(TestCase)); + + internal static readonly TestProperty ManagedMethodProperty = TestProperty.Register( + id: ManagedNameConstants.ManagedMethodPropertyId, + label: ManagedNameConstants.ManagedMethodLabel, + category: string.Empty, + description: string.Empty, + valueType: typeof(string), + validateValueCallback: o => !string.IsNullOrWhiteSpace(o as string), + attributes: TestPropertyAttributes.Hidden, + owner: typeof(TestCase)); + + internal static readonly TestProperty HierarchyProperty = TestProperty.Register( + id: HierarchyConstants.HierarchyPropertyId, + label: HierarchyConstants.HierarchyLabel, + category: string.Empty, + description: string.Empty, + valueType: typeof(string[]), + validateValueCallback: null, + attributes: TestPropertyAttributes.Immutable, + owner: typeof(TestCase)); + } +} diff --git a/src/BenchmarkDotNet/Properties/AssemblyInfo.cs b/src/BenchmarkDotNet/Properties/AssemblyInfo.cs index 5327197aa5..cec4ef220c 100644 --- a/src/BenchmarkDotNet/Properties/AssemblyInfo.cs +++ b/src/BenchmarkDotNet/Properties/AssemblyInfo.cs @@ -16,6 +16,7 @@ [assembly: InternalsVisibleTo("BenchmarkDotNet.Diagnostics.dotTrace,PublicKey=" + BenchmarkDotNetInfo.PublicKey)] [assembly: InternalsVisibleTo("BenchmarkDotNet.IntegrationTests.ManualRunning,PublicKey=" + BenchmarkDotNetInfo.PublicKey)] [assembly: InternalsVisibleTo("BenchmarkDotNet.IntegrationTests.ManualRunning.MultipleFrameworks,PublicKey=" + BenchmarkDotNetInfo.PublicKey)] +[assembly: InternalsVisibleTo("BenchmarkDotNet.TestAdapter,PublicKey=" + BenchmarkDotNetInfo.PublicKey)] #else [assembly: InternalsVisibleTo("BenchmarkDotNet.Tests")] [assembly: InternalsVisibleTo("BenchmarkDotNet.IntegrationTests")] @@ -23,4 +24,5 @@ [assembly: InternalsVisibleTo("BenchmarkDotNet.Diagnostics.dotTrace")] [assembly: InternalsVisibleTo("BenchmarkDotNet.IntegrationTests.ManualRunning")] [assembly: InternalsVisibleTo("BenchmarkDotNet.IntegrationTests.ManualRunning.MultipleFrameworks")] +[assembly: InternalsVisibleTo("BenchmarkDotNet.TestAdapter")] #endif \ No newline at end of file From 7bce341c2e9409a0c7efdb5158fda7a3e2134f4d Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Tue, 12 Dec 2023 12:12:56 +1000 Subject: [PATCH 02/10] Address PR comments --- .../BenchmarkCaseExtensions.cs | 48 ++++++----------- .../BenchmarkEnumerator.cs | 17 +++--- .../BenchmarkExecutor.cs | 10 ++-- .../Remoting/BenchmarkEnumeratorWrapper.cs | 12 ++--- .../Remoting/BenchmarkExecutorWrapper.cs | 4 +- .../Remoting/SerializationHelpers.cs | 8 ++- .../VSTestAdapter.cs | 36 ++++++------- .../VSTestLogger.cs | 4 +- .../VSTestProperties.cs | 53 +++---------------- 9 files changed, 70 insertions(+), 122 deletions(-) diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs index 80c554b6df..9558dfa98b 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs @@ -4,10 +4,8 @@ using BenchmarkDotNet.Extensions; using BenchmarkDotNet.Running; using Microsoft.TestPlatform.AdapterUtilities; -using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using System; -using System.Linq; namespace BenchmarkDotNet.TestAdapter { @@ -20,36 +18,29 @@ internal static class BenchmarkCaseExtensions /// Converts a BDN BenchmarkCase to a VSTest TestCase. /// /// The BenchmarkCase to convert. - /// The dll or exe of the benchmark project. + /// The dll or exe of the benchmark project. /// Whether or not the display name should include the job name. /// The VSTest TestCase. - internal static TestCase ToVSTestCase(this BenchmarkCase benchmarkCase, string source, bool includeJobInName=false) + internal static TestCase ToVSTestCase(this BenchmarkCase benchmarkCase, string assemblyPath, bool includeJobInName=false) { var benchmarkMethod = benchmarkCase.Descriptor.WorkloadMethod; - var fullClassName = benchmarkCase.Descriptor.Type.FullName; - var benchmarkMethodName = benchmarkCase.Descriptor.WorkloadMethodDisplayInfo; + var fullClassName = benchmarkCase.Descriptor.Type.GetCorrectCSharpTypeName(); + var benchmarkMethodName = benchmarkCase.Descriptor.WorkloadMethod.Name; var benchmarkFullName = $"{fullClassName}.{benchmarkMethodName}"; - ManagedNameHelper.GetManagedName(benchmarkMethod, out var managedType, out var managedMethod, out var hierarchyValues); - hierarchyValues[HierarchyConstants.Levels.ContainerIndex] = null; // Gets set by the test explorer window to the test project name + // Display name has arguments as well. + var displayMethodName = FullNameProvider.GetMethodName(benchmarkCase); if (includeJobInName) - { - hierarchyValues[HierarchyConstants.Levels.TestGroupIndex] += $" [{benchmarkCase.GetUnrandomizedJobDisplayInfo()}]"; - } + displayMethodName += $" [{benchmarkCase.GetUnrandomizedJobDisplayInfo()}]"; - var hasManagedMethodAndTypeProperties = !string.IsNullOrWhiteSpace(managedType) && !string.IsNullOrWhiteSpace(managedMethod); + var displayName = $"{fullClassName}.{displayMethodName}"; - var vsTestCase = new TestCase(benchmarkFullName, VSTestAdapter.ExecutorUri, source) + var vsTestCase = new TestCase(benchmarkFullName, VSTestAdapter.ExecutorUri, assemblyPath) { - DisplayName = FullNameProvider.GetBenchmarkName(benchmarkCase), - Id = GetTestCaseId(benchmarkCase), + DisplayName = displayName, + Id = GetTestCaseId(benchmarkCase) }; - if (includeJobInName) - { - vsTestCase.DisplayName += $" [{benchmarkCase.GetUnrandomizedJobDisplayInfo()}]"; - } - var benchmarkAttribute = benchmarkMethod.ResolveAttribute(); if (benchmarkAttribute != null) { @@ -57,18 +48,11 @@ internal static TestCase ToVSTestCase(this BenchmarkCase benchmarkCase, string s vsTestCase.LineNumber = benchmarkAttribute.SourceCodeLineNumber; } - vsTestCase.SetPropertyValue(VSTestProperties.HierarchyProperty, hierarchyValues.ToArray()); - vsTestCase.SetPropertyValue(VSTestProperties.TestCategoryProperty, benchmarkCase.Descriptor.Categories); - if (hasManagedMethodAndTypeProperties) - { - vsTestCase.SetPropertyValue(VSTestProperties.ManagedTypeProperty, managedType); - vsTestCase.SetPropertyValue(VSTestProperties.ManagedMethodProperty, managedMethod); - vsTestCase.SetPropertyValue(VSTestProperties.TestClassNameProperty, managedType); - } - else - { - vsTestCase.SetPropertyValue(VSTestProperties.TestClassNameProperty, fullClassName); - } + var categories = DefaultCategoryDiscoverer.Instance.GetCategories(benchmarkMethod); + foreach (var category in categories) + vsTestCase.Traits.Add("Category", category); + + vsTestCase.Traits.Add("", "BenchmarkDotNet"); return vsTestCase; } diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs index a64fc23017..dc3746689f 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs @@ -1,26 +1,29 @@ using BenchmarkDotNet.Extensions; using BenchmarkDotNet.Helpers; using BenchmarkDotNet.Running; +using System; using System.Linq; using System.Reflection; namespace BenchmarkDotNet.TestAdapter { /// - /// A class used for enumerating all the benchmarks in a source. + /// A class used for enumerating all the benchmarks in an assembly. /// internal static class BenchmarkEnumerator { /// - /// Returns all the BenchmarkRunInfo objects from a given source. + /// Returns all the BenchmarkRunInfo objects from a given assembly. /// - /// The dll or exe of the benchmark project. - /// The benchmarks inside the source. - public static BenchmarkRunInfo[] GetBenchmarksFromSource(string source) + /// The dll or exe of the benchmark project. + /// The benchmarks inside the assembly. + public static BenchmarkRunInfo[] GetBenchmarksFromAssemblyPath(string assemblyPath) { - var assembly = Assembly.LoadFrom(source); + var assembly = Assembly.LoadFrom(assemblyPath); + + if (assembly.IsDebug() ?? false) + return Array.Empty(); - // TODO: Allow for defining a base config inside the BDN project that is used by the VSTest Adapter. return GenericBenchmarksBuilder.GetRunnableBenchmarks(assembly.GetRunnableBenchmarks()) .Select(type => BenchmarkConverter.TypeToBenchmarks(type)) .Where(runInfo => runInfo.BenchmarksCases.Length > 0) diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs index 4eb8231e18..0a96f3b3cd 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs @@ -17,17 +17,17 @@ internal class BenchmarkExecutor private readonly CancellationTokenSource cts = new (); /// - /// Runs all the benchmarks in the given source, updating the TestExecutionRecorder as they get run. + /// Runs all the benchmarks in the given assembly, updating the TestExecutionRecorder as they get run. /// - /// The dll or exe of the benchmark project. + /// The dll or exe of the benchmark project. /// The interface used to record the current test execution progress. /// /// An optional list of benchmark IDs specifying which benchmarks to run. /// These IDs are the same as the ones generated for the VSTest TestCase. /// - public void RunBenchmarks(string source, TestExecutionRecorderWrapper recorder, HashSet? benchmarkIds = null) + public void RunBenchmarks(string assemblyPath, TestExecutionRecorderWrapper recorder, HashSet? benchmarkIds = null) { - var benchmarks = BenchmarkEnumerator.GetBenchmarksFromSource(source); + var benchmarks = BenchmarkEnumerator.GetBenchmarksFromAssemblyPath(assemblyPath); var testCases = new List(); var filteredBenchmarks = new List(); @@ -41,7 +41,7 @@ public void RunBenchmarks(string source, TestExecutionRecorderWrapper recorder, if (benchmarkIds != null && benchmarkIds.Contains(testId)) { filteredCases.Add(benchmarkCase); - testCases.Add(benchmarkCase.ToVSTestCase(source, needsJobInfo)); + testCases.Add(benchmarkCase.ToVSTestCase(assemblyPath, needsJobInfo)); } } diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs index d6de5178ea..3f9b72944a 100644 --- a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs @@ -10,21 +10,21 @@ namespace BenchmarkDotNet.TestAdapter.Remoting internal class BenchmarkEnumeratorWrapper : MarshalByRefObject { /// - /// Gets a list of VSTest TestCases from the given source. - /// Each test case is serialize into a string so that it can be used across AppDomain boundaries. + /// Gets a list of VSTest TestCases from the given assembly. + /// Each test case is serialized into a string so that it can be used across AppDomain boundaries. /// - /// The dll or exe of the benchmark project. + /// The dll or exe of the benchmark project. /// The serialized test cases. - public List GetTestCasesFromSourceSerialized(string source) + public List GetTestCasesFromAssemblyPathSerialized(string assemblyPath) { var serializedTestCases = new List(); - foreach (var runInfo in BenchmarkEnumerator.GetBenchmarksFromSource(source)) + foreach (var runInfo in BenchmarkEnumerator.GetBenchmarksFromAssemblyPath(assemblyPath)) { // If all the benchmarks have the same job, then no need to include job info. var needsJobInfo = runInfo.BenchmarksCases.Select(c => c.Job.DisplayInfo).Distinct().Count() > 1; foreach (var benchmarkCase in runInfo.BenchmarksCases) { - var testCase = benchmarkCase.ToVSTestCase(source, needsJobInfo); + var testCase = benchmarkCase.ToVSTestCase(assemblyPath, needsJobInfo); serializedTestCases.Add(SerializationHelpers.Serialize(testCase)); } } diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs index b94e7aa603..646ae2f8be 100644 --- a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkExecutorWrapper.cs @@ -10,9 +10,9 @@ internal class BenchmarkExecutorWrapper : MarshalByRefObject { private readonly BenchmarkExecutor benchmarkExecutor = new (); - public void RunBenchmarks(string source, TestExecutionRecorderWrapper recorder, HashSet? benchmarkIds = null) + public void RunBenchmarks(string assemblyPath, TestExecutionRecorderWrapper recorder, HashSet? benchmarkIds = null) { - benchmarkExecutor.RunBenchmarks(source, recorder, benchmarkIds); + benchmarkExecutor.RunBenchmarks(assemblyPath, recorder, benchmarkIds); } public void Cancel() diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs index 1c1945b236..aeefbedba8 100644 --- a/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs @@ -7,14 +7,18 @@ namespace BenchmarkDotNet.TestAdapter.Remoting /// internal static class SerializationHelpers { + // Version number of the VSTest protocol that the adapter supports. Only needs to be updated when + // the VSTest protocol has a change and this test adapter wishes to take a dependency on it. + private const int VSTestProtocolVersion = 7; + public static string Serialize(T data) { - return JsonDataSerializer.Instance.Serialize(data, version: 7); + return JsonDataSerializer.Instance.Serialize(data, version: VSTestProtocolVersion); } public static T Deserialize(string data) { - return JsonDataSerializer.Instance.Deserialize(data, version: 7)!; + return JsonDataSerializer.Instance.Deserialize(data, version: VSTestProtocolVersion)!; } } } diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs b/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs index 5fa6a13024..de01da907d 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs @@ -44,8 +44,8 @@ public void DiscoverTests( { foreach (var source in sources) { - ValidateSourceOrThrow(source); - foreach (var testCase in GetVSTestCasesFromSource(source, logger)) + ValidateSourceIsAssemblyOrThrow(source); + foreach (var testCase in GetVSTestCasesFromAssembly(source, logger)) { discoverySink.SendTestCase(testCase); } @@ -67,8 +67,8 @@ public void RunTests(IEnumerable? tests, IRunContext? runContext, IFra cts ??= new CancellationTokenSource(); - foreach (var testsPerSource in tests.GroupBy(t => t.Source)) - RunBenchmarks(testsPerSource.Key, frameworkHandle, testsPerSource); + foreach (var testsPerAssembly in tests.GroupBy(t => t.Source)) + RunBenchmarks(testsPerAssembly.Key, frameworkHandle, testsPerAssembly); cts = null; } @@ -103,21 +103,19 @@ public void Cancel() } /// - /// Gets the VSTest test cases in the given source. + /// Gets the VSTest test cases in the given assembly. /// - /// The dll or exe of the benchmark project. + /// The dll or exe of the benchmark project. /// A logger that sends logs to VSTest. - /// The VSTest test cases inside the given source. - private static List GetVSTestCasesFromSource(string source, IMessageLogger logger) + /// The VSTest test cases inside the given assembly. + private static List GetVSTestCasesFromAssembly(string assemblyPath, IMessageLogger logger) { - ValidateSourceOrThrow(source); - try { // Ensure that the test enumeration is done inside the context of the source directory. - var enumerator = (BenchmarkEnumeratorWrapper)CreateIsolatedType(typeof(BenchmarkEnumeratorWrapper), source); + var enumerator = (BenchmarkEnumeratorWrapper)CreateIsolatedType(typeof(BenchmarkEnumeratorWrapper), assemblyPath); var testCases = enumerator - .GetTestCasesFromSourceSerialized(source) + .GetTestCasesFromAssemblyPathSerialized(assemblyPath) .Select(SerializationHelpers.Deserialize) .ToList(); @@ -135,7 +133,7 @@ private static List GetVSTestCasesFromSource(string source, IMessageLo } catch (Exception ex) { - logger.SendMessage(TestMessageLevel.Error, $"Failed to load benchmarks from source\n{ex}"); + logger.SendMessage(TestMessageLevel.Error, $"Failed to load benchmarks from assembly\n{ex}"); throw; } } @@ -151,7 +149,7 @@ private static List GetVSTestCasesFromSource(string source, IMessageLo /// private void RunBenchmarks(string source, IFrameworkHandle frameworkHandle, IEnumerable? testCases = null) { - ValidateSourceOrThrow(source); + ValidateSourceIsAssemblyOrThrow(source); // Create a HashSet of all the TestCase IDs to be run if specified. var caseIds = testCases == null ? null : new HashSet(testCases.Select(c => c.Id)); @@ -166,7 +164,7 @@ private void RunBenchmarks(string source, IFrameworkHandle frameworkHandle, IEnu } catch (Exception ex) { - frameworkHandle.SendMessage(TestMessageLevel.Error, $"Failed to run benchmarks in source\n{ex}"); + frameworkHandle.SendMessage(TestMessageLevel.Error, $"Failed to run benchmarks in assembly\n{ex}"); throw; } } @@ -176,12 +174,12 @@ private void RunBenchmarks(string source, IFrameworkHandle frameworkHandle, IEnu /// If not in the .NET Framework, it will use the current /// /// The type to create. - /// The dll or exe of the benchmark project. + /// The dll or exe of the benchmark project. /// The created object. - private static object CreateIsolatedType(Type type, string source) + private static object CreateIsolatedType(Type type, string assemblyPath) { #if NETFRAMEWORK - var appBase = Path.GetDirectoryName(source); + var appBase = Path.GetDirectoryName(assemblyPath); var setup = new AppDomainSetup { ApplicationBase = appBase }; var domainName = $"Isolated Domain for {type.Name}"; var appDomain = AppDomain.CreateDomain(domainName, null, setup); @@ -192,7 +190,7 @@ private static object CreateIsolatedType(Type type, string source) #endif } - private static void ValidateSourceOrThrow(string source) + private static void ValidateSourceIsAssemblyOrThrow(string source) { if (string.IsNullOrEmpty(source)) throw new ArgumentException($"'{nameof(source)}' cannot be null or whitespace.", nameof(source)); diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs b/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs index ab514004bd..e1a4d71e36 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs @@ -7,7 +7,7 @@ namespace BenchmarkDotNet.TestAdapter /// /// A class to send logs from BDN to the VSTest output log. /// - internal class VSTestLogger : ILogger + internal sealed class VSTestLogger : ILogger { private readonly IMessageLogger messageLogger; private readonly StringBuilder currentLine = new StringBuilder(); @@ -31,7 +31,7 @@ public void Write(LogKind logKind, string text) { currentLine.Append(text); - // Assume that if the log kind if an error, that the whole line is treated as an error + // Assume that if the log kind is an error, that the whole line is treated as an error // The level will be reset to Informational when WriteLine() is called. if (logKind == LogKind.Error) currentLevel = TestMessageLevel.Error; diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs b/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs index d35aad5234..42cd8d1f2e 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs @@ -1,63 +1,22 @@ -using Microsoft.TestPlatform.AdapterUtilities; -using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; namespace BenchmarkDotNet.TestAdapter { /// - /// A class that contains all the properties that can be set on VSTest TestCase and TestResults. + /// A class that contains all the custom properties that can be set on VSTest TestCase and TestResults. /// Some of these properties are well known as they are also used by VSTest adapters for other test libraries. /// internal static class VSTestProperties { + /// + /// A test property used for storing the test results so that they could be accessed + /// programmatically from a custom VSTest runner. + /// internal static readonly TestProperty Measurement = TestProperty.Register( "BenchmarkDotNet.TestAdapter.Measurements", "Measurements", typeof(string[]), TestPropertyAttributes.Hidden, typeof(TestResult)); - - internal static readonly TestProperty TestCategoryProperty = TestProperty.Register( - "BenchmarkDotNet.TestAdapter.TestCategory", - "TestCategory", - typeof(string[]), - TestPropertyAttributes.Hidden, - typeof(TestCase)); - - internal static readonly TestProperty TestClassNameProperty = TestProperty.Register( - "BenchmarkDotNet.TestAdapter.TestClassName", - "ClassName", - typeof(string), - TestPropertyAttributes.Hidden, - typeof(TestCase)); - - internal static readonly TestProperty ManagedTypeProperty = TestProperty.Register( - id: ManagedNameConstants.ManagedTypePropertyId, - label: ManagedNameConstants.ManagedTypeLabel, - category: string.Empty, - description: string.Empty, - valueType: typeof(string), - validateValueCallback: o => !string.IsNullOrWhiteSpace(o as string), - attributes: TestPropertyAttributes.Hidden, - owner: typeof(TestCase)); - - internal static readonly TestProperty ManagedMethodProperty = TestProperty.Register( - id: ManagedNameConstants.ManagedMethodPropertyId, - label: ManagedNameConstants.ManagedMethodLabel, - category: string.Empty, - description: string.Empty, - valueType: typeof(string), - validateValueCallback: o => !string.IsNullOrWhiteSpace(o as string), - attributes: TestPropertyAttributes.Hidden, - owner: typeof(TestCase)); - - internal static readonly TestProperty HierarchyProperty = TestProperty.Register( - id: HierarchyConstants.HierarchyPropertyId, - label: HierarchyConstants.HierarchyLabel, - category: string.Empty, - description: string.Empty, - valueType: typeof(string[]), - validateValueCallback: null, - attributes: TestPropertyAttributes.Immutable, - owner: typeof(TestCase)); } } From 53173842e474372d94ba6c4cfc183fc328b05eec Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Fri, 15 Dec 2023 05:28:45 +1000 Subject: [PATCH 03/10] Address further PR comments --- .../BenchmarkCaseExtensions.cs | 8 ++++---- .../BenchmarkExecutor.cs | 6 +++--- .../Remoting/BenchmarkEnumeratorWrapper.cs | 2 +- .../Remoting/MessageLoggerWrapper.cs | 2 +- .../Remoting/SerializationHelpers.cs | 8 +++++--- .../VSTestAdapter.cs | 17 ++++++++++++----- .../VSTestEventProcessor.cs | 6 +++--- src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs | 6 +++--- .../VSTestProperties.cs | 2 +- 9 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs index 9558dfa98b..dec7aae8c1 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkCaseExtensions.cs @@ -21,12 +21,12 @@ internal static class BenchmarkCaseExtensions /// The dll or exe of the benchmark project. /// Whether or not the display name should include the job name. /// The VSTest TestCase. - internal static TestCase ToVSTestCase(this BenchmarkCase benchmarkCase, string assemblyPath, bool includeJobInName=false) + internal static TestCase ToVsTestCase(this BenchmarkCase benchmarkCase, string assemblyPath, bool includeJobInName = false) { var benchmarkMethod = benchmarkCase.Descriptor.WorkloadMethod; var fullClassName = benchmarkCase.Descriptor.Type.GetCorrectCSharpTypeName(); var benchmarkMethodName = benchmarkCase.Descriptor.WorkloadMethod.Name; - var benchmarkFullName = $"{fullClassName}.{benchmarkMethodName}"; + var benchmarkFullMethodName = $"{fullClassName}.{benchmarkMethodName}"; // Display name has arguments as well. var displayMethodName = FullNameProvider.GetMethodName(benchmarkCase); @@ -35,7 +35,7 @@ internal static TestCase ToVSTestCase(this BenchmarkCase benchmarkCase, string a var displayName = $"{fullClassName}.{displayMethodName}"; - var vsTestCase = new TestCase(benchmarkFullName, VSTestAdapter.ExecutorUri, assemblyPath) + var vsTestCase = new TestCase(benchmarkFullMethodName, VsTestAdapter.ExecutorUri, assemblyPath) { DisplayName = displayName, Id = GetTestCaseId(benchmarkCase) @@ -84,7 +84,7 @@ internal static string GetUnrandomizedJobDisplayInfo(this BenchmarkCase benchmar internal static Guid GetTestCaseId(this BenchmarkCase benchmarkCase) { var testIdProvider = new TestIdProvider(); - testIdProvider.AppendString(VSTestAdapter.ExecutorUriString); + testIdProvider.AppendString(VsTestAdapter.ExecutorUriString); testIdProvider.AppendString(benchmarkCase.Descriptor.DisplayInfo); testIdProvider.AppendString(benchmarkCase.GetUnrandomizedJobDisplayInfo()); testIdProvider.AppendString(benchmarkCase.Parameters.DisplayInfo); diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs index 0a96f3b3cd..b13a4eaf4a 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkExecutor.cs @@ -41,7 +41,7 @@ public void RunBenchmarks(string assemblyPath, TestExecutionRecorderWrapper reco if (benchmarkIds != null && benchmarkIds.Contains(testId)) { filteredCases.Add(benchmarkCase); - testCases.Add(benchmarkCase.ToVSTestCase(assemblyPath, needsJobInfo)); + testCases.Add(benchmarkCase.ToVsTestCase(assemblyPath, needsJobInfo)); } } @@ -57,10 +57,10 @@ public void RunBenchmarks(string assemblyPath, TestExecutionRecorderWrapper reco return; // Create an event processor which will subscribe to events and push them to VSTest - var eventProcessor = new VSTestEventProcessor(testCases, recorder, cts.Token); + var eventProcessor = new VsTestEventProcessor(testCases, recorder, cts.Token); // Create a logger which will forward all log messages in BDN to the VSTest logger. - var logger = new VSTestLogger(recorder.GetLogger()); + var logger = new VsTestLogger(recorder.GetLogger()); // Modify all the benchmarks so that the event process and logger is added. benchmarks = benchmarks diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs index 3f9b72944a..b3ad68bb23 100644 --- a/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/BenchmarkEnumeratorWrapper.cs @@ -24,7 +24,7 @@ public List GetTestCasesFromAssemblyPathSerialized(string assemblyPath) var needsJobInfo = runInfo.BenchmarksCases.Select(c => c.Job.DisplayInfo).Distinct().Count() > 1; foreach (var benchmarkCase in runInfo.BenchmarksCases) { - var testCase = benchmarkCase.ToVSTestCase(assemblyPath, needsJobInfo); + var testCase = benchmarkCase.ToVsTestCase(assemblyPath, needsJobInfo); serializedTestCases.Add(SerializationHelpers.Serialize(testCase)); } } diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs index db603a98cf..00c4f5325f 100644 --- a/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/MessageLoggerWrapper.cs @@ -1,7 +1,7 @@ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using System; -namespace BenchmarkDotNet.TestAdapter +namespace BenchmarkDotNet.TestAdapter.Remoting { /// /// A wrapper around an IMessageLogger that works across AppDomain boundaries. diff --git a/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs b/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs index aeefbedba8..5b13bd5175 100644 --- a/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs +++ b/src/BenchmarkDotNet.TestAdapter/Remoting/SerializationHelpers.cs @@ -9,16 +9,18 @@ internal static class SerializationHelpers { // Version number of the VSTest protocol that the adapter supports. Only needs to be updated when // the VSTest protocol has a change and this test adapter wishes to take a dependency on it. - private const int VSTestProtocolVersion = 7; + // A list of protocol versions and a summary of the changes that were made in them can be found here: + // https://github.com/microsoft/vstest/blob/main/docs/Overview.md#protocolversion-request + private const int VsTestProtocolVersion = 7; public static string Serialize(T data) { - return JsonDataSerializer.Instance.Serialize(data, version: VSTestProtocolVersion); + return JsonDataSerializer.Instance.Serialize(data, version: VsTestProtocolVersion); } public static T Deserialize(string data) { - return JsonDataSerializer.Instance.Deserialize(data, version: VSTestProtocolVersion)!; + return JsonDataSerializer.Instance.Deserialize(data, version: VsTestProtocolVersion)!; } } } diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs b/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs index de01da907d..eb6695de1b 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestAdapter.cs @@ -18,7 +18,7 @@ namespace BenchmarkDotNet.TestAdapter [DefaultExecutorUri(ExecutorUriString)] [FileExtension(".dll")] [FileExtension(".exe")] - public class VSTestAdapter : ITestExecutor, ITestDiscoverer + public class VsTestAdapter : ITestExecutor, ITestDiscoverer { // This URI is used to identify the adapter. internal const string ExecutorUriString = "executor://BenchmarkDotNet.TestAdapter"; @@ -45,7 +45,7 @@ public void DiscoverTests( foreach (var source in sources) { ValidateSourceIsAssemblyOrThrow(source); - foreach (var testCase in GetVSTestCasesFromAssembly(source, logger)) + foreach (var testCase in GetVsTestCasesFromAssembly(source, logger)) { discoverySink.SendTestCase(testCase); } @@ -108,7 +108,7 @@ public void Cancel() /// The dll or exe of the benchmark project. /// A logger that sends logs to VSTest. /// The VSTest test cases inside the given assembly. - private static List GetVSTestCasesFromAssembly(string assemblyPath, IMessageLogger logger) + private static List GetVsTestCasesFromAssembly(string assemblyPath, IMessageLogger logger) { try { @@ -171,13 +171,20 @@ private void RunBenchmarks(string source, IFrameworkHandle frameworkHandle, IEnu /// /// This will create the given type in a child AppDomain when used in .NET Framework. - /// If not in the .NET Framework, it will use the current + /// If not in the .NET Framework, it will use the current AppDomain. /// /// The type to create. /// The dll or exe of the benchmark project. /// The created object. private static object CreateIsolatedType(Type type, string assemblyPath) { + // .NET Framework runs require a custom AppDomain to be set up to run the benchmarks in because otherwise, + // all the assemblies will be loaded from the VSTest console rather than from the directory that the BDN + // program under test lives in. .NET Core assembly resolution is smarter and will correctly load the right + // assembly versions as needed and does not require a custom AppDomain. Unfortunately, the APIs needed to + // create the AppDomain for .NET Framework are not part of .NET Standard, and so a multi-targeting solution + // such as this is required to get this to work. This same approach is also used by other .NET unit testing + // libraries as well, further justifying this approach to solving how to get the correct assemblies loaded. #if NETFRAMEWORK var appBase = Path.GetDirectoryName(assemblyPath); var setup = new AppDomainSetup { ApplicationBase = appBase }; @@ -199,7 +206,7 @@ private static void ValidateSourceIsAssemblyOrThrow(string source) throw new NotSupportedException($"Missing extension on source '{source}', must have the extension '.dll' or '.exe'."); var extension = Path.GetExtension(source); - if (!string.Equals(extension, ".dll") && !string.Equals(extension, ".exe")) + if (!string.Equals(extension, ".dll", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".exe", StringComparison.OrdinalIgnoreCase)) throw new NotSupportedException($"Unsupported extension on source '{source}', must have the extension '.dll' or '.exe'."); } } diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs b/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs index 6a17016db6..8ebd239972 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs @@ -18,7 +18,7 @@ namespace BenchmarkDotNet.TestAdapter /// /// An event processor which will pass on benchmark execution information to VSTest. /// - internal class VSTestEventProcessor : EventProcessor + internal class VsTestEventProcessor : EventProcessor { private readonly Dictionary cases; private readonly TestExecutionRecorderWrapper recorder; @@ -27,7 +27,7 @@ internal class VSTestEventProcessor : EventProcessor private readonly Dictionary testResults = new (); private readonly HashSet sentTestResults = new (); - public VSTestEventProcessor( + public VsTestEventProcessor( List cases, TestExecutionRecorderWrapper recorder, CancellationToken cancellationToken) @@ -118,7 +118,7 @@ public override void OnEndRunBenchmark(BenchmarkCase benchmarkCase, BenchmarkRep var resultRuns = report.GetResultRuns(); // Provide the raw result runs data. - testResult.SetPropertyValue(VSTestProperties.Measurement, resultRuns.Select(m => m.Nanoseconds.ToString()).ToArray()); + testResult.SetPropertyValue(VsTestProperties.Measurement, resultRuns.Select(m => m.Nanoseconds.ToString()).ToArray()); // Add a message to the TestResult which contains the results summary. testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, report.BenchmarkCase.DisplayInfo + "\n")); diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs b/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs index e1a4d71e36..28fc54995c 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestLogger.cs @@ -7,18 +7,18 @@ namespace BenchmarkDotNet.TestAdapter /// /// A class to send logs from BDN to the VSTest output log. /// - internal sealed class VSTestLogger : ILogger + internal sealed class VsTestLogger : ILogger { private readonly IMessageLogger messageLogger; private readonly StringBuilder currentLine = new StringBuilder(); private TestMessageLevel currentLevel = TestMessageLevel.Informational; - public VSTestLogger(IMessageLogger logger) + public VsTestLogger(IMessageLogger logger) { messageLogger = logger; } - public string Id => nameof(VSTestLogger); + public string Id => nameof(VsTestLogger); public int Priority => 0; diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs b/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs index 42cd8d1f2e..6bcbdcf299 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestProperties.cs @@ -6,7 +6,7 @@ namespace BenchmarkDotNet.TestAdapter /// A class that contains all the custom properties that can be set on VSTest TestCase and TestResults. /// Some of these properties are well known as they are also used by VSTest adapters for other test libraries. /// - internal static class VSTestProperties + internal static class VsTestProperties { /// /// A test property used for storing the test results so that they could be accessed From b2e45a983e9c8acdb5babe69f74743dbc321ddf2 Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Fri, 15 Dec 2023 05:58:30 +1000 Subject: [PATCH 04/10] Put histogram first in test result output Allow benchmarks to be run in Debug when in-process toolchain is used --- .../BenchmarkEnumerator.cs | 21 ++++++++++++++++--- .../VSTestEventProcessor.cs | 15 +++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs index dc3746689f..1beefb8bb8 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs @@ -1,7 +1,9 @@ using BenchmarkDotNet.Extensions; using BenchmarkDotNet.Helpers; using BenchmarkDotNet.Running; +using BenchmarkDotNet.Toolchains; using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -21,11 +23,24 @@ public static BenchmarkRunInfo[] GetBenchmarksFromAssemblyPath(string assemblyPa { var assembly = Assembly.LoadFrom(assemblyPath); - if (assembly.IsDebug() ?? false) - return Array.Empty(); + var isDebugAssembly = assembly.IsDebug() ?? false; return GenericBenchmarksBuilder.GetRunnableBenchmarks(assembly.GetRunnableBenchmarks()) - .Select(type => BenchmarkConverter.TypeToBenchmarks(type)) + .Select(type => + { + var benchmarkRunInfo = BenchmarkConverter.TypeToBenchmarks(type); + if (isDebugAssembly) + { + // If the assembly is a debug assembly, then only display them if they will run in-process + // This will allow people to debug their benchmarks using VSTest if they wish. + benchmarkRunInfo = new BenchmarkRunInfo( + benchmarkRunInfo.BenchmarksCases.Where(c => c.GetToolchain().IsInProcess).ToArray(), + benchmarkRunInfo.Type, + benchmarkRunInfo.Config); + } + + return benchmarkRunInfo; + }) .Where(runInfo => runInfo.BenchmarksCases.Length > 0) .ToArray(); } diff --git a/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs b/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs index 8ebd239972..85c93069e1 100644 --- a/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs +++ b/src/BenchmarkDotNet.TestAdapter/VSTestEventProcessor.cs @@ -6,11 +6,13 @@ using BenchmarkDotNet.Toolchains.Results; using BenchmarkDotNet.Validators; using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Perfolizer.Mathematics.Histograms; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; +using System.Text; using System.Threading; namespace BenchmarkDotNet.TestAdapter @@ -127,8 +129,17 @@ public override void OnEndRunBenchmark(BenchmarkCase benchmarkCase, BenchmarkRep var statistics = resultRuns.GetStatistics(); var cultureInfo = CultureInfo.InvariantCulture; var formatter = statistics.CreateNanosecondFormatter(cultureInfo); - var statisticsOutput = statistics.ToString(cultureInfo, formatter, calcHistogram: true); - testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, statisticsOutput)); + + var builder = new StringBuilder(); + var histogram = HistogramBuilder.Adaptive.Build(statistics.OriginalValues); + builder.AppendLine("-------------------- Histogram --------------------"); + builder.AppendLine(histogram.ToString(formatter)); + builder.AppendLine("---------------------------------------------------"); + + var statisticsOutput = statistics.ToString(cultureInfo, formatter, calcHistogram: false); + builder.AppendLine(statisticsOutput); + + testResult.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, builder.ToString())); RecordEnd(testResult.TestCase, testResult.Outcome); RecordResult(testResult); From 494f2cec2cd823bfebad0313cee72b1e87f00852 Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Wed, 20 Dec 2023 23:08:26 +1000 Subject: [PATCH 05/10] Add Auto-Generated Entry Point --- .../BenchmarkDotNet.TestAdapter.csproj | 6 ++++++ .../BenchmarkEnumerator.cs | 2 +- .../Package/BenchmarkDotNet.TestAdapter.props | 12 ++++++++++++ .../Package/EntryPoint.cs | 7 +++++++ .../Package/EntryPoint.fs | 8 ++++++++ .../Package/EntryPoint.vb | 10 ++++++++++ 6 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props create mode 100644 src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.cs create mode 100644 src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs create mode 100644 src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj b/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj index dc8664400b..b0eb8bfc3a 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkDotNet.TestAdapter.csproj @@ -19,4 +19,10 @@ + + + + + + diff --git a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs index 1beefb8bb8..daf3e2222e 100644 --- a/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs +++ b/src/BenchmarkDotNet.TestAdapter/BenchmarkEnumerator.cs @@ -23,7 +23,7 @@ public static BenchmarkRunInfo[] GetBenchmarksFromAssemblyPath(string assemblyPa { var assembly = Assembly.LoadFrom(assemblyPath); - var isDebugAssembly = assembly.IsDebug() ?? false; + var isDebugAssembly = assembly.IsJitOptimizationDisabled() ?? false; return GenericBenchmarksBuilder.GetRunnableBenchmarks(assembly.GetRunnableBenchmarks()) .Select(type => diff --git a/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props b/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props new file mode 100644 index 0000000000..bb7992372d --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props @@ -0,0 +1,12 @@ + + + + false + $(MSBuildThisFileDirectory)..\entrypoints\ + + + + + + + \ No newline at end of file diff --git a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.cs b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.cs new file mode 100644 index 0000000000..ec2a5f87dd --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.cs @@ -0,0 +1,7 @@ +using BenchmarkDotNet.Running; +using System.Reflection; + +public class __AutoGeneratedEntryPointClass +{ + public static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(__AutoGeneratedEntryPointClass).Assembly).Run(args); +} diff --git a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs new file mode 100644 index 0000000000..d63ae28d34 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs @@ -0,0 +1,8 @@ +module __AutoGeneratedEntryPointClass +open System.Reflection; +open BenchmarkDotNet.Running + +[] +let main argv = + BenchmarkSwitcher.FromAssembly(Assembly.GetEntryAssembly()).Run(argv) |> ignore + 0 // return an integer exit code diff --git a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb new file mode 100644 index 0000000000..138200cdd5 --- /dev/null +++ b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb @@ -0,0 +1,10 @@ +Imports System.Reflection +Imports BenchmarkDotNet.Running + +Namespace Global + Module __AutoGeneratedEntryPointClass + Sub Main(args As String()) + Dim summary = BenchmarkSwitcher.FromAssembly(Assembly.GetEntryAssembly()).Run(args) + End Sub + End Module +End Namespace \ No newline at end of file From 7c8fb190893478a7944b02cfbf407c192abf78fc Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Thu, 21 Dec 2023 06:34:10 +1000 Subject: [PATCH 06/10] Add comments to samples csproj Update F# and VB entry points to use alternative approach to get current assembly --- .../BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj | 5 +++++ src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs | 3 ++- src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj index dbf2b5f49d..498a78d496 100644 --- a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj +++ b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj @@ -11,6 +11,10 @@ AnyCPU true $(NoWarn);CA1018;CA5351;CA1825 + false @@ -20,6 +24,7 @@ + diff --git a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs index d63ae28d34..e5870cd8f3 100644 --- a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs +++ b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.fs @@ -2,7 +2,8 @@ open System.Reflection; open BenchmarkDotNet.Running +type internal __Marker = interface end // Used to help locale current assembly [] let main argv = - BenchmarkSwitcher.FromAssembly(Assembly.GetEntryAssembly()).Run(argv) |> ignore + BenchmarkSwitcher.FromAssembly(typeof<__Marker>.Assembly).Run(argv) |> ignore 0 // return an integer exit code diff --git a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb index 138200cdd5..4bed7a0109 100644 --- a/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb +++ b/src/BenchmarkDotNet.TestAdapter/Package/EntryPoint.vb @@ -4,7 +4,7 @@ Imports BenchmarkDotNet.Running Namespace Global Module __AutoGeneratedEntryPointClass Sub Main(args As String()) - Dim summary = BenchmarkSwitcher.FromAssembly(Assembly.GetEntryAssembly()).Run(args) + Dim summary = BenchmarkSwitcher.FromAssembly(MethodBase.GetCurrentMethod().Module.Assembly).Run(args) End Sub End Module End Namespace \ No newline at end of file From f8fa9ad2a13f96b3970f243b4ccdc971dc5af0d0 Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Thu, 21 Dec 2023 07:05:40 +1000 Subject: [PATCH 07/10] Change default for GenerateBDNEntryPoint --- .../Package/BenchmarkDotNet.TestAdapter.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props b/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props index bb7992372d..0a981dfc79 100644 --- a/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props +++ b/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props @@ -4,7 +4,7 @@ false $(MSBuildThisFileDirectory)..\entrypoints\ - + From 0c1b27552edce9fb7610b1a1ce642638b563d952 Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Thu, 21 Dec 2023 08:03:07 +1000 Subject: [PATCH 08/10] Reuse GenerateProgramFile property --- .../BenchmarkDotNet.Samples.csproj | 5 +--- .../Package/BenchmarkDotNet.TestAdapter.props | 25 +++++++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj index 498a78d496..1af13f61c3 100644 --- a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj +++ b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj @@ -11,10 +11,7 @@ AnyCPU true $(NoWarn);CA1018;CA5351;CA1825 - + false diff --git a/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props b/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props index 0a981dfc79..a9e8340b30 100644 --- a/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props +++ b/src/BenchmarkDotNet.TestAdapter/Package/BenchmarkDotNet.TestAdapter.props @@ -1,12 +1,21 @@ - + - - false $(MSBuildThisFileDirectory)..\entrypoints\ - - - - - + + + + + + + + + + false + + \ No newline at end of file From c432f887d274e9aa7f902ed75353a0d99615c804 Mon Sep 17 00:00:00 2001 From: Cameron Aavik Date: Thu, 21 Dec 2023 18:32:07 +1000 Subject: [PATCH 09/10] Add documentation of VSTest --- docs/articles/features/toc.yml | 4 +- docs/articles/features/vstest.md | 75 +++++++++++++++++++++++++++ docs/images/vs-testexplorer-demo.png | Bin 0 -> 183050 bytes 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 docs/articles/features/vstest.md create mode 100644 docs/images/vs-testexplorer-demo.png diff --git a/docs/articles/features/toc.yml b/docs/articles/features/toc.yml index fe55761610..ac29397743 100644 --- a/docs/articles/features/toc.yml +++ b/docs/articles/features/toc.yml @@ -11,4 +11,6 @@ - name: EtwProfiler href: etwprofiler.md - name: EventPipeProfiler - href: event-pipe-profiler.md \ No newline at end of file + href: event-pipe-profiler.md +- name: VSTest + href: vstest.md \ No newline at end of file diff --git a/docs/articles/features/vstest.md b/docs/articles/features/vstest.md new file mode 100644 index 0000000000..3429f10560 --- /dev/null +++ b/docs/articles/features/vstest.md @@ -0,0 +1,75 @@ +--- +uid: docs.baselines +name: Running with VSTest +--- + +# Running with VSTest +BenchmarkDotNet has support for discovering and executing benchmarks through VSTest. This provides an alternative user experience to running benchmarks with the CLI and may be preferable for those who like their IDE's VSTest integrations that they may have used when running unit tests. + +Below is an example showing the experience of running some benchmarks in the BenchmarkDotNet samples project in Visual Studio's Test Explorer. + +![](../../images/vs-testexplorer-demo.png) + +## About VSTest + +VSTest is one of the most popular test platforms in use in the .NET ecosystem, with test frameworks such as MSTest, xUnit, and NUnit providing support for it. Many IDEs, including Visual Studio and Rider, provide UIs for running tests through VSTest which some users may find more accessible than running them through the command line. + +It may seem counterintuitive to run performance tests on a platform that is designed for unit tests that expect a boolean outcome of "Passed" or "Failed", however VSTest provides good value as a protocol for discovering and executing tests. In addition, we can still make use of this boolean output to indicate if the benchmark had validation errors that caused them to fail to run. + +## Caveats and things to know +- The VSTest adapter will not call your application's entry point. + - If you use the entry point to customize how your benchmarks are run, you will need to do this through other means such as an assembly-level `IConfigSource`. + - For more about this, please read: [Setting a default configuration](#setting-a-default-configuration). +- The benchmark measurements may be affected by the VSTest host and your IDE + - If you want to have more accurate performance results, it is recommended to run benchmarks through the CLI instead without other processes on the machine impacting performance. + - This does not mean that the measurements are useless though, it will still be able to provide useful measurements during development when comparing different approaches. +- The test adapter will not display or execute benchmarks if optimizations are disabled. + - Please ensure you are compiling in Release mode or with `Optimize` set to true. + - Using an `InProcess` toolchain will let you run your benchmarks with optimizations disabled and will let you attach the debugger as well. +- The test adapter will generate an entry point for you automatically + - The generated entry point will pass the command line arguments and the current assembly into `BenchmarkSwitcher`, so you can still use it in your CLI as well as in VSTest. + - This means you can delete your entry point and only need to define your benchmarks. + - If you want to use a custom entry point, you can still do so by setting `GenerateProgramFile` to `false` in your project file. + +## How to use it + +You need to install two packages into your benchmark project: + +- `BenchmarkDotNet.TestAdapter`: Implements the VSTest protocol for BenchmarkDotNet +- `Microsoft.NET.Test.Sdk`: Includes all the pieces needed for the VSTest host to run and load the VSTest adapter. + +As mentioned in the caveats section, `BenchmarkDotNet.TestAdapter` will generate an entry point for you automatically, so if you have an entry point already you will either need to delete it or set `GenerateProgramFile` to `false` in your project file to continue using your existing one. + +After doing this, you can set your build configuration to `Release`, run a build, and you should be able to see the benchmarks in your IDE's VSTest integration. + +## Setting a default configuration + +Previously, it was common for the default configuration to be defined inside the entry point. Since the entry point is not used when running benchmarks through VSTest, the default configuration must be specified using a custom `IConfigSource` attribute instead that is set on the assembly. + +First, create a custom attribute that implements `IConfigSource` like below, making sure that it has `Assembly` as one of the attribute targets: + +```csharp +class MyDefaultConfigSourceAttribute : Attribute, IConfigSource +{ + public IConfig Config { get; } + + public MyDefaultConfigSourceAttribute() + { + // define your config here + Config = ManualConfig.CreateEmpty().AddJob(...); + } +} +``` + +Then, set an assembly attribute with the following. + +```csharp +[assembly: MyDefaultConfigSource] +``` + +By convention, assembly attributes are usually defined inside `AssemblyInfo.cs` in a directory called `Properties`. + +## Viewing the results +The full output from BenchmarkDotNet that you would have been used to seeing in the past will be sent to the "Tests" Output of your IDE. Use this view if you want to see the tabular view that compares multiple benchmarks with each other, or if you want to see the results for each individual iteration. + +One more place where you can view the results is in each individual test's output messages. In Visual Studio this can be viewed by clicking on the test in the Test Explorer after running it, and looking at the Test Detail Summary. Since this only displays statistics for a single benchmark case, it does not show the tabulated view that compares multiple benchmark cases, but instead displays a histogram and various other useful statistics \ No newline at end of file diff --git a/docs/images/vs-testexplorer-demo.png b/docs/images/vs-testexplorer-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..91232e30d6b6d8702b98c605d4f4f48cb537f44f GIT binary patch literal 183050 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%0DyLZk!Z{TXZwWy?4eJqf;xH#8S!PBg0*SMa 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
qnYxjhL~p}vs07_K9(8Xe=^yA5R`P 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 Date: Sat, 23 Dec 2023 14:07:13 +1000 Subject: [PATCH 10/10] Update docs to use Config attribute instead --- docs/articles/features/vstest.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/articles/features/vstest.md b/docs/articles/features/vstest.md index 3429f10560..cdeac5fa7c 100644 --- a/docs/articles/features/vstest.md +++ b/docs/articles/features/vstest.md @@ -6,7 +6,7 @@ name: Running with VSTest # Running with VSTest BenchmarkDotNet has support for discovering and executing benchmarks through VSTest. This provides an alternative user experience to running benchmarks with the CLI and may be preferable for those who like their IDE's VSTest integrations that they may have used when running unit tests. -Below is an example showing the experience of running some benchmarks in the BenchmarkDotNet samples project in Visual Studio's Test Explorer. +Below is an example of running some benchmarks from the BenchmarkDotNet samples project in Visual Studio's Test Explorer. ![](../../images/vs-testexplorer-demo.png) @@ -44,19 +44,18 @@ After doing this, you can set your build configuration to `Release`, run a build ## Setting a default configuration -Previously, it was common for the default configuration to be defined inside the entry point. Since the entry point is not used when running benchmarks through VSTest, the default configuration must be specified using a custom `IConfigSource` attribute instead that is set on the assembly. +Previously, it was common for the default configuration to be defined inside the entry point. Since the entry point is not used when running benchmarks through VSTest, the default configuration must be specified using a `Config` attribute instead that is set on the assembly. -First, create a custom attribute that implements `IConfigSource` like below, making sure that it has `Assembly` as one of the attribute targets: +First, create a class that extends `ManualConfig` or `IConfig` which sets the default configuration you want: ```csharp -class MyDefaultConfigSourceAttribute : Attribute, IConfigSource +class MyDefaultConfig : ManualConfig { - public IConfig Config { get; } - - public MyDefaultConfigSourceAttribute() + public MyDefaultConfig() { - // define your config here - Config = ManualConfig.CreateEmpty().AddJob(...); + AddJob(Job.Dry); + AddLogger(Loggers.ConsoleLogger.Default); + AddValidator(JitOptimizationsValidator.DontFailOnError); } } ``` @@ -64,12 +63,12 @@ class MyDefaultConfigSourceAttribute : Attribute, IConfigSource Then, set an assembly attribute with the following. ```csharp -[assembly: MyDefaultConfigSource] +[assembly: Config(typeof(MyDefaultConfig))] ``` By convention, assembly attributes are usually defined inside `AssemblyInfo.cs` in a directory called `Properties`. ## Viewing the results -The full output from BenchmarkDotNet that you would have been used to seeing in the past will be sent to the "Tests" Output of your IDE. Use this view if you want to see the tabular view that compares multiple benchmarks with each other, or if you want to see the results for each individual iteration. +The full output from BenchmarkDotNet that you would have been used to seeing in the past will be sent to the "Tests" output of your IDE. Use this view if you want to see the tabular view that compares multiple benchmarks with each other, or if you want to see the results for each individual iteration. -One more place where you can view the results is in each individual test's output messages. In Visual Studio this can be viewed by clicking on the test in the Test Explorer after running it, and looking at the Test Detail Summary. Since this only displays statistics for a single benchmark case, it does not show the tabulated view that compares multiple benchmark cases, but instead displays a histogram and various other useful statistics \ No newline at end of file +One more place where you can view the results is in each individual test's output messages. In Visual Studio this can be viewed by clicking on the test in the Test Explorer after running it, and looking at the Test Detail Summary. Since this only displays statistics for a single benchmark case, it does not show the tabulated view that compares multiple benchmark cases, but instead displays a histogram and various other useful statistics. Not all IDEs support displaying these output messages, so you may only be able to view the results using the "Tests" output. \ No newline at end of file