diff --git a/BenchmarkDotNet.sln b/BenchmarkDotNet.sln index d51cb4e029..779871f1d1 100644 --- a/BenchmarkDotNet.sln +++ b/BenchmarkDotNet.sln @@ -47,13 +47,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "templates", "templates", "{ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkDotNet.Templates", "templates\BenchmarkDotNet.Templates.csproj", "{B620D10A-CD8E-4A34-8B27-FD6257E63AD0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkDotNet.Diagnostics.dotTrace", "src\BenchmarkDotNet.Diagnostics.dotTrace\BenchmarkDotNet.Diagnostics.dotTrace.csproj", "{C5BDA61F-3A56-4B59-901D-0A17E78F4076}" -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 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.Diagnostics.dotMemory", "src\BenchmarkDotNet.Diagnostics.dotMemory\BenchmarkDotNet.Diagnostics.dotMemory.csproj", "{2E2283A3-6DA6-4482-8518-99D6D9F689AB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JetBrains", "JetBrains", "{AD5887B3-2F6C-48B6-B338-A4E286AFFBBD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.Diagnostics.dotMemory", "src\JetBrains\BenchmarkDotNet.Diagnostics.dotMemory\BenchmarkDotNet.Diagnostics.dotMemory.csproj", "{777D5767-4B68-4E83-A445-D1ABAE272718}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkDotNet.Diagnostics.dotTrace", "src\JetBrains\BenchmarkDotNet.Diagnostics.dotTrace\BenchmarkDotNet.Diagnostics.dotTrace.csproj", "{EA2E4258-E639-4C14-9147-B4B062769DFE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -133,10 +135,6 @@ Global {B620D10A-CD8E-4A34-8B27-FD6257E63AD0}.Debug|Any CPU.Build.0 = Debug|Any CPU {B620D10A-CD8E-4A34-8B27-FD6257E63AD0}.Release|Any CPU.ActiveCfg = Release|Any CPU {B620D10A-CD8E-4A34-8B27-FD6257E63AD0}.Release|Any CPU.Build.0 = Release|Any CPU - {C5BDA61F-3A56-4B59-901D-0A17E78F4076}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C5BDA61F-3A56-4B59-901D-0A17E78F4076}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C5BDA61F-3A56-4B59-901D-0A17E78F4076}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C5BDA61F-3A56-4B59-901D-0A17E78F4076}.Release|Any CPU.Build.0 = Release|Any CPU {AACA2C63-A85B-47AB-99FC-72C3FF408B14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {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 @@ -145,10 +143,14 @@ Global {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 - {2E2283A3-6DA6-4482-8518-99D6D9F689AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E2283A3-6DA6-4482-8518-99D6D9F689AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E2283A3-6DA6-4482-8518-99D6D9F689AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E2283A3-6DA6-4482-8518-99D6D9F689AB}.Release|Any CPU.Build.0 = Release|Any CPU + {777D5767-4B68-4E83-A445-D1ABAE272718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {777D5767-4B68-4E83-A445-D1ABAE272718}.Debug|Any CPU.Build.0 = Debug|Any CPU + {777D5767-4B68-4E83-A445-D1ABAE272718}.Release|Any CPU.ActiveCfg = Release|Any CPU + {777D5767-4B68-4E83-A445-D1ABAE272718}.Release|Any CPU.Build.0 = Release|Any CPU + {EA2E4258-E639-4C14-9147-B4B062769DFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA2E4258-E639-4C14-9147-B4B062769DFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA2E4258-E639-4C14-9147-B4B062769DFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA2E4258-E639-4C14-9147-B4B062769DFE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -172,10 +174,11 @@ Global {B4405781-40D3-42B8-B168-00E711FABA15} = {14195214-591A-45B7-851A-19D3BA2413F9} {D9F5065B-6190-431B-850C-117E3D64AB33} = {D6597E3A-6892-4A68-8E14-042FC941FDA2} {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} - {2E2283A3-6DA6-4482-8518-99D6D9F689AB} = {D6597E3A-6892-4A68-8E14-042FC941FDA2} + {AD5887B3-2F6C-48B6-B338-A4E286AFFBBD} = {D6597E3A-6892-4A68-8E14-042FC941FDA2} + {777D5767-4B68-4E83-A445-D1ABAE272718} = {AD5887B3-2F6C-48B6-B338-A4E286AFFBBD} + {EA2E4258-E639-4C14-9147-B4B062769DFE} = {AD5887B3-2F6C-48B6-B338-A4E286AFFBBD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4D9AF12B-1F7F-45A7-9E8C-E4E46ADCBD1F} diff --git a/build/BenchmarkDotNet.Build/BuildContext.cs b/build/BenchmarkDotNet.Build/BuildContext.cs index 0a165721e0..d8f6335147 100644 --- a/build/BenchmarkDotNet.Build/BuildContext.cs +++ b/build/BenchmarkDotNet.Build/BuildContext.cs @@ -137,6 +137,13 @@ public BuildContext(ICakeContext context) .GetSubDirectories(RootDirectory.Combine("src")) .Select(directoryPath => directoryPath.GetDirectoryName()) .Where(name => !name.Contains("Disassembler", StringComparison.OrdinalIgnoreCase))); + + var jetBrainsNugetPackages = this + .GetSubDirectories(RootDirectory.Combine("src/JetBrains")) + .Select(directoryPath => directoryPath.GetDirectoryName()) + .Where(name => name != "Shared"); + nuGetPackageNames.AddRange(jetBrainsNugetPackages); + nuGetPackageNames.Add("BenchmarkDotNet.Templates"); nuGetPackageNames.Sort(); NuGetPackageNames = nuGetPackageNames; diff --git a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj index 36c3f60b32..ab7928a940 100644 --- a/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj +++ b/samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj @@ -25,8 +25,8 @@ - - + + diff --git a/src/BenchmarkDotNet.Diagnostics.dotMemory/Progress.cs b/src/BenchmarkDotNet.Diagnostics.dotMemory/Progress.cs deleted file mode 100644 index 738997bb6d..0000000000 --- a/src/BenchmarkDotNet.Diagnostics.dotMemory/Progress.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Diagnostics; -using BenchmarkDotNet.Loggers; - -namespace BenchmarkDotNet.Diagnostics.dotMemory -{ - public class Progress : IProgress - { - private static readonly TimeSpan ReportInterval = TimeSpan.FromSeconds(0.1); - - private readonly ILogger logger; - private readonly string title; - - public Progress(ILogger logger, string title) - { - this.logger = logger; - this.title = title; - } - - private int lastProgress; - private Stopwatch? stopwatch; - - public void Report(double value) - { - int progress = (int)Math.Floor(value); - bool needToReport = stopwatch == null || - (stopwatch != null && stopwatch?.Elapsed > ReportInterval) || - progress == 100; - - if (lastProgress != progress && needToReport) - { - logger.WriteLineInfo($"{title}: {progress}%"); - lastProgress = progress; - stopwatch = Stopwatch.StartNew(); - } - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceToolBase.cs b/src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceToolBase.cs deleted file mode 100644 index f2f07625fa..0000000000 --- a/src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceToolBase.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.IO; -using System.Reflection; -using BenchmarkDotNet.Diagnosers; -using BenchmarkDotNet.Helpers; -using BenchmarkDotNet.Loggers; -using JetBrains.Profiler.SelfApi; - -namespace BenchmarkDotNet.Diagnostics.dotTrace -{ - internal abstract class DotTraceToolBase - { - private readonly ILogger logger; - private readonly Uri? nugetUrl; - private readonly NuGetApi nugetApi; - private readonly string? downloadTo; - - protected DotTraceToolBase(ILogger logger, Uri? nugetUrl = null, NuGetApi nugetApi = NuGetApi.V3, string? downloadTo = null) - { - this.logger = logger; - this.nugetUrl = nugetUrl; - this.nugetApi = nugetApi; - this.downloadTo = downloadTo; - } - - public void Init(DiagnoserActionParameters parameters) - { - try - { - logger.WriteLineInfo("Ensuring that dotTrace prerequisite is installed..."); - var progress = new Progress(logger, "Installing DotTrace"); - DotTrace.EnsurePrerequisiteAsync(progress, nugetUrl, nugetApi, downloadTo).Wait(); - logger.WriteLineInfo("dotTrace prerequisite is installed"); - logger.WriteLineInfo($"dotTrace runner path: {GetRunnerPath()}"); - } - catch (Exception e) - { - logger.WriteLineError(e.ToString()); - } - } - - protected abstract bool AttachOnly { get; } - protected abstract void Attach(DiagnoserActionParameters parameters, string snapshotFile); - protected abstract void StartCollectingData(); - protected abstract void SaveData(); - protected abstract void Detach(); - - public string Start(DiagnoserActionParameters parameters) - { - string snapshotFile = ArtifactFileNameHelper.GetFilePath(parameters, "snapshots", DateTime.Now, "dtp", ".0000".Length); - string? snapshotDirectory = Path.GetDirectoryName(snapshotFile); - logger.WriteLineInfo($"Target snapshot file: {snapshotFile}"); - if (!Directory.Exists(snapshotDirectory) && snapshotDirectory != null) - { - try - { - Directory.CreateDirectory(snapshotDirectory); - } - catch (Exception e) - { - logger.WriteLineError($"Failed to create directory: {snapshotDirectory}"); - logger.WriteLineError(e.ToString()); - } - } - - try - { - logger.WriteLineInfo("Attaching dotTrace to the process..."); - Attach(parameters, snapshotFile); - logger.WriteLineInfo("dotTrace is successfully attached"); - } - catch (Exception e) - { - logger.WriteLineError(e.ToString()); - return snapshotFile; - } - - if (!AttachOnly) - { - try - { - logger.WriteLineInfo("Start collecting data using dataTrace..."); - StartCollectingData(); - logger.WriteLineInfo("Data collecting is successfully started"); - } - catch (Exception e) - { - logger.WriteLineError(e.ToString()); - } - } - - return snapshotFile; - } - - public void Stop(DiagnoserActionParameters parameters) - { - if (!AttachOnly) - { - try - { - logger.WriteLineInfo("Saving dotTrace snapshot..."); - SaveData(); - logger.WriteLineInfo("dotTrace snapshot is successfully saved to the artifact folder"); - } - catch (Exception e) - { - logger.WriteLineError(e.ToString()); - } - - try - { - logger.WriteLineInfo("Detaching dotTrace from the process..."); - Detach(); - logger.WriteLineInfo("dotTrace is successfully detached"); - } - catch (Exception e) - { - logger.WriteLineError(e.ToString()); - } - } - } - - protected string GetRunnerPath() - { - var consoleRunnerPackageField = typeof(DotTrace).GetField("ConsoleRunnerPackage", BindingFlags.NonPublic | BindingFlags.Static); - if (consoleRunnerPackageField == null) - throw new InvalidOperationException("Field 'ConsoleRunnerPackage' not found."); - - object? consoleRunnerPackage = consoleRunnerPackageField.GetValue(null); - if (consoleRunnerPackage == null) - throw new InvalidOperationException("Unable to get value of 'ConsoleRunnerPackage'."); - - var consoleRunnerPackageType = consoleRunnerPackage.GetType(); - var getRunnerPathMethod = consoleRunnerPackageType.GetMethod("GetRunnerPath"); - if (getRunnerPathMethod == null) - throw new InvalidOperationException("Method 'GetRunnerPath' not found."); - - string? runnerPath = getRunnerPathMethod.Invoke(consoleRunnerPackage, null) as string; - if (runnerPath == null) - throw new InvalidOperationException("Unable to invoke 'GetRunnerPath'."); - - return runnerPath; - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/ExternalDotTraceTool.cs b/src/BenchmarkDotNet.Diagnostics.dotTrace/ExternalDotTraceTool.cs deleted file mode 100644 index c7f1cf18c8..0000000000 --- a/src/BenchmarkDotNet.Diagnostics.dotTrace/ExternalDotTraceTool.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading.Tasks; -using BenchmarkDotNet.Diagnosers; -using BenchmarkDotNet.Loggers; -using JetBrains.Profiler.SelfApi; -using ILogger = BenchmarkDotNet.Loggers.ILogger; - -namespace BenchmarkDotNet.Diagnostics.dotTrace -{ - internal class ExternalDotTraceTool : DotTraceToolBase - { - private static readonly TimeSpan AttachTimeout = TimeSpan.FromMinutes(5); - - public ExternalDotTraceTool(ILogger logger, Uri? nugetUrl = null, NuGetApi nugetApi = NuGetApi.V3, string? downloadTo = null) : - base(logger, nugetUrl, nugetApi, downloadTo) { } - - protected override bool AttachOnly => true; - - protected override void Attach(DiagnoserActionParameters parameters, string snapshotFile) - { - var logger = parameters.Config.GetCompositeLogger(); - - string runnerPath = GetRunnerPath(); - int pid = parameters.Process.Id; - string arguments = $"attach {pid} --save-to=\"{snapshotFile}\" --service-output=on"; - - logger.WriteLineInfo($"Starting process: '{runnerPath} {arguments}'"); - - var processStartInfo = new ProcessStartInfo - { - FileName = runnerPath, - WorkingDirectory = "", - Arguments = arguments, - UseShellExecute = false, - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true - }; - - var attachWaitingTask = new TaskCompletionSource(); - var process = new Process { StartInfo = processStartInfo }; - try - { - process.OutputDataReceived += (_, args) => - { - string? content = args.Data; - if (content != null) - { - logger.WriteLineInfo("[dotTrace] " + content); - if (content.Contains("##dotTrace[\"started\"")) - attachWaitingTask.TrySetResult(true); - } - }; - process.ErrorDataReceived += (_, args) => - { - string? content = args.Data; - if (content != null) - logger.WriteLineError("[dotTrace] " + args.Data); - }; - process.Exited += (_, _) => { attachWaitingTask.TrySetResult(false); }; - process.Start(); - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - } - catch (Exception e) - { - attachWaitingTask.TrySetResult(false); - logger.WriteLineError(e.ToString()); - } - - if (!attachWaitingTask.Task.Wait(AttachTimeout)) - throw new Exception($"Failed to attach dotTrace to the target process (timeout: {AttachTimeout.TotalSeconds} sec)"); - if (!attachWaitingTask.Task.Result) - throw new Exception($"Failed to attach dotTrace to the target process (ExitCode={process.ExitCode})"); - } - - protected override void StartCollectingData() { } - - protected override void SaveData() { } - - protected override void Detach() { } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/InProcessDotTraceTool.cs b/src/BenchmarkDotNet.Diagnostics.dotTrace/InProcessDotTraceTool.cs deleted file mode 100644 index a02c9c1995..0000000000 --- a/src/BenchmarkDotNet.Diagnostics.dotTrace/InProcessDotTraceTool.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using BenchmarkDotNet.Diagnosers; -using BenchmarkDotNet.Loggers; -using JetBrains.Profiler.SelfApi; - -namespace BenchmarkDotNet.Diagnostics.dotTrace -{ - internal class InProcessDotTraceTool : DotTraceToolBase - { - public InProcessDotTraceTool(ILogger logger, Uri? nugetUrl = null, NuGetApi nugetApi = NuGetApi.V3, string? downloadTo = null) : - base(logger, nugetUrl, nugetApi, downloadTo) { } - - protected override bool AttachOnly => false; - - protected override void Attach(DiagnoserActionParameters parameters, string snapshotFile) - { - var config = new DotTrace.Config(); - config.SaveToFile(snapshotFile); - DotTrace.Attach(config); - } - - protected override void StartCollectingData() => DotTrace.StartCollectingData(); - - protected override void SaveData() => DotTrace.SaveData(); - - protected override void Detach() => DotTrace.Detach(); - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotMemory/BenchmarkDotNet.Diagnostics.dotMemory.csproj b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/BenchmarkDotNet.Diagnostics.dotMemory.csproj similarity index 73% rename from src/BenchmarkDotNet.Diagnostics.dotMemory/BenchmarkDotNet.Diagnostics.dotMemory.csproj rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/BenchmarkDotNet.Diagnostics.dotMemory.csproj index 23261abb24..d418341924 100644 --- a/src/BenchmarkDotNet.Diagnostics.dotMemory/BenchmarkDotNet.Diagnostics.dotMemory.csproj +++ b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/BenchmarkDotNet.Diagnostics.dotMemory.csproj @@ -1,5 +1,5 @@ - + net6.0;net462;netcoreapp3.1 $(NoWarn);1591 @@ -10,7 +10,11 @@ - + + + + + diff --git a/src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs similarity index 59% rename from src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs index 46789b518c..16ae55eb41 100644 --- a/src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs +++ b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs @@ -6,9 +6,9 @@ using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Engines; using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.JetBrains; using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Portability; using BenchmarkDotNet.Reports; using BenchmarkDotNet.Running; using BenchmarkDotNet.Validators; @@ -77,60 +77,7 @@ public IEnumerable Validate(ValidationParameters validationPara } } - internal static bool IsSupported(RuntimeMoniker runtimeMoniker) - { - switch (runtimeMoniker) - { - case RuntimeMoniker.HostProcess: - case RuntimeMoniker.Net461: - case RuntimeMoniker.Net462: - case RuntimeMoniker.Net47: - case RuntimeMoniker.Net471: - case RuntimeMoniker.Net472: - case RuntimeMoniker.Net48: - case RuntimeMoniker.Net481: - case RuntimeMoniker.Net50: - case RuntimeMoniker.Net60: - case RuntimeMoniker.Net70: - case RuntimeMoniker.Net80: - case RuntimeMoniker.Net90: - return true; - case RuntimeMoniker.NotRecognized: - case RuntimeMoniker.Mono: - case RuntimeMoniker.NativeAot60: - case RuntimeMoniker.NativeAot70: - case RuntimeMoniker.NativeAot80: - case RuntimeMoniker.NativeAot90: - case RuntimeMoniker.Wasm: - case RuntimeMoniker.WasmNet50: - case RuntimeMoniker.WasmNet60: - case RuntimeMoniker.WasmNet70: - case RuntimeMoniker.WasmNet80: - case RuntimeMoniker.WasmNet90: - case RuntimeMoniker.MonoAOTLLVM: - case RuntimeMoniker.MonoAOTLLVMNet60: - case RuntimeMoniker.MonoAOTLLVMNet70: - case RuntimeMoniker.MonoAOTLLVMNet80: - case RuntimeMoniker.MonoAOTLLVMNet90: - case RuntimeMoniker.Mono60: - case RuntimeMoniker.Mono70: - case RuntimeMoniker.Mono80: - case RuntimeMoniker.Mono90: -#pragma warning disable CS0618 // Type or member is obsolete - case RuntimeMoniker.NetCoreApp50: -#pragma warning restore CS0618 // Type or member is obsolete - return false; - case RuntimeMoniker.NetCoreApp20: - case RuntimeMoniker.NetCoreApp21: - case RuntimeMoniker.NetCoreApp22: - return RuntimeInformation.IsWindows(); - case RuntimeMoniker.NetCoreApp30: - case RuntimeMoniker.NetCoreApp31: - return RuntimeInformation.IsWindows() || RuntimeInformation.IsLinux(); - default: - throw new ArgumentOutOfRangeException(nameof(runtimeMoniker), runtimeMoniker, $"Runtime moniker {runtimeMoniker} is not supported"); - } - } + internal static bool IsSupported(RuntimeMoniker runtimeMoniker) => Helper.IsSupported(runtimeMoniker); public IEnumerable ProcessResults(DiagnoserResults results) => ImmutableArray.Empty; diff --git a/src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoserAttribute.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoserAttribute.cs similarity index 100% rename from src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoserAttribute.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoserAttribute.cs diff --git a/src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryTool.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryTool.cs similarity index 75% rename from src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryTool.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryTool.cs index 1e640d6708..3e0cd342f2 100644 --- a/src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryTool.cs +++ b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryTool.cs @@ -1,11 +1,11 @@ using System; using System.Diagnostics; using System.IO; -using System.Reflection; using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Helpers; using BenchmarkDotNet.Loggers; using JetBrains.Profiler.SelfApi; +using BenchmarkDotNet.JetBrains; namespace BenchmarkDotNet.Diagnostics.dotMemory { @@ -32,7 +32,7 @@ public void Init() var progress = new Progress(logger, "Installing DotMemory"); DotMemory.EnsurePrerequisiteAsync(progress, nugetUrl, nugetApi, downloadTo).Wait(); logger.WriteLineInfo("dotMemory prerequisite is installed"); - logger.WriteLineInfo($"dotMemory runner path: {GetRunnerPath()}"); + logger.WriteLineInfo($"dotMemory runner path: {Helper.GetRunnerPath(typeof(DotMemory))}"); } catch (Exception e) { @@ -114,27 +114,5 @@ private void Attach(DiagnoserActionParameters parameters, string snapshotFile) private void Snapshot() => DotMemory.GetSnapshot(); private void Detach() => DotMemory.Detach(); - - private string GetRunnerPath() - { - var consoleRunnerPackageField = typeof(DotMemory).GetField("ConsoleRunnerPackage", BindingFlags.NonPublic | BindingFlags.Static); - if (consoleRunnerPackageField == null) - throw new InvalidOperationException("Field 'ConsoleRunnerPackage' not found."); - - object? consoleRunnerPackage = consoleRunnerPackageField.GetValue(null); - if (consoleRunnerPackage == null) - throw new InvalidOperationException("Unable to get value of 'ConsoleRunnerPackage'."); - - var consoleRunnerPackageType = consoleRunnerPackage.GetType(); - var getRunnerPathMethod = consoleRunnerPackageType.GetMethod("GetRunnerPath"); - if (getRunnerPathMethod == null) - throw new InvalidOperationException("Method 'GetRunnerPath' not found."); - - string? runnerPath = getRunnerPathMethod.Invoke(consoleRunnerPackage, null) as string; - if (runnerPath == null) - throw new InvalidOperationException("Unable to invoke 'GetRunnerPath'."); - - return runnerPath; - } } } \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotMemory/Properties/AssemblyInfo.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/Properties/AssemblyInfo.cs similarity index 100% rename from src/BenchmarkDotNet.Diagnostics.dotMemory/Properties/AssemblyInfo.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotMemory/Properties/AssemblyInfo.cs diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/BenchmarkDotNet.Diagnostics.dotTrace.csproj b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/BenchmarkDotNet.Diagnostics.dotTrace.csproj similarity index 73% rename from src/BenchmarkDotNet.Diagnostics.dotTrace/BenchmarkDotNet.Diagnostics.dotTrace.csproj rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/BenchmarkDotNet.Diagnostics.dotTrace.csproj index aa8c7af1e4..e6e1cb5ef9 100644 --- a/src/BenchmarkDotNet.Diagnostics.dotTrace/BenchmarkDotNet.Diagnostics.dotTrace.csproj +++ b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/BenchmarkDotNet.Diagnostics.dotTrace.csproj @@ -1,5 +1,5 @@ - + net6.0;net462;netcoreapp3.1 $(NoWarn);1591 @@ -10,7 +10,11 @@ - + + + + + diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs similarity index 51% rename from src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs index 2aada424b7..19f8773343 100644 --- a/src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs +++ b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs @@ -6,12 +6,11 @@ using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Engines; using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.JetBrains; using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Portability; using BenchmarkDotNet.Reports; using BenchmarkDotNet.Running; -using BenchmarkDotNet.Toolchains; using BenchmarkDotNet.Validators; using RunMode = BenchmarkDotNet.Diagnosers.RunMode; @@ -19,6 +18,8 @@ namespace BenchmarkDotNet.Diagnostics.dotTrace { public class DotTraceDiagnoser(Uri? nugetUrl = null, string? toolsDownloadFolder = null) : IProfiler { + private DotTraceTool? tool; + public IEnumerable Ids => new[] { "DotTrace" }; public string ShortName => "dotTrace"; @@ -32,11 +33,7 @@ public RunMode GetRunMode(BenchmarkCase benchmarkCase) public void Handle(HostSignal signal, DiagnoserActionParameters parameters) { var job = parameters.BenchmarkCase.Job; - bool isInProcess = job.GetToolchain().IsInProcess; var logger = parameters.Config.GetCompositeLogger(); - DotTraceToolBase tool = isInProcess - ? new InProcessDotTraceTool(logger, nugetUrl, downloadTo: toolsDownloadFolder) - : new ExternalDotTraceTool(logger, nugetUrl, downloadTo: toolsDownloadFolder); var runtimeMoniker = job.Environment.GetRuntime().RuntimeMoniker; if (!IsSupported(runtimeMoniker)) @@ -48,13 +45,21 @@ public void Handle(HostSignal signal, DiagnoserActionParameters parameters) switch (signal) { case HostSignal.BeforeAnythingElse: - tool.Init(parameters); + if (tool is not null) + throw new InvalidOperationException("dotTrace tool is already initialized"); + tool = new DotTraceTool(logger, nugetUrl, downloadTo: toolsDownloadFolder); + tool.Init(); break; case HostSignal.BeforeActualRun: + if (tool is null) + throw new InvalidOperationException("dotTrace tool is not initialized"); snapshotFilePaths.Add(tool.Start(parameters)); break; case HostSignal.AfterActualRun: - tool.Stop(parameters); + if (tool is null) + throw new InvalidOperationException("dotTrace tool is not initialized"); + tool.Stop(); + tool = null; break; } } @@ -72,60 +77,7 @@ public IEnumerable Validate(ValidationParameters validationPara } } - internal static bool IsSupported(RuntimeMoniker runtimeMoniker) - { - switch (runtimeMoniker) - { - case RuntimeMoniker.HostProcess: - case RuntimeMoniker.Net461: - case RuntimeMoniker.Net462: - case RuntimeMoniker.Net47: - case RuntimeMoniker.Net471: - case RuntimeMoniker.Net472: - case RuntimeMoniker.Net48: - case RuntimeMoniker.Net481: - case RuntimeMoniker.Net50: - case RuntimeMoniker.Net60: - case RuntimeMoniker.Net70: - case RuntimeMoniker.Net80: - case RuntimeMoniker.Net90: - return true; - case RuntimeMoniker.NotRecognized: - case RuntimeMoniker.Mono: - case RuntimeMoniker.NativeAot60: - case RuntimeMoniker.NativeAot70: - case RuntimeMoniker.NativeAot80: - case RuntimeMoniker.NativeAot90: - case RuntimeMoniker.Wasm: - case RuntimeMoniker.WasmNet50: - case RuntimeMoniker.WasmNet60: - case RuntimeMoniker.WasmNet70: - case RuntimeMoniker.WasmNet80: - case RuntimeMoniker.WasmNet90: - case RuntimeMoniker.MonoAOTLLVM: - case RuntimeMoniker.MonoAOTLLVMNet60: - case RuntimeMoniker.MonoAOTLLVMNet70: - case RuntimeMoniker.MonoAOTLLVMNet80: - case RuntimeMoniker.MonoAOTLLVMNet90: - case RuntimeMoniker.Mono60: - case RuntimeMoniker.Mono70: - case RuntimeMoniker.Mono80: - case RuntimeMoniker.Mono90: -#pragma warning disable CS0618 // Type or member is obsolete - case RuntimeMoniker.NetCoreApp50: -#pragma warning restore CS0618 // Type or member is obsolete - return false; - case RuntimeMoniker.NetCoreApp20: - case RuntimeMoniker.NetCoreApp21: - case RuntimeMoniker.NetCoreApp22: - return RuntimeInformation.IsWindows(); - case RuntimeMoniker.NetCoreApp30: - case RuntimeMoniker.NetCoreApp31: - return RuntimeInformation.IsWindows() || RuntimeInformation.IsLinux(); - default: - throw new ArgumentOutOfRangeException(nameof(runtimeMoniker), runtimeMoniker, $"Runtime moniker {runtimeMoniker} is not supported"); - } - } + internal static bool IsSupported(RuntimeMoniker runtimeMoniker) => Helper.IsSupported(runtimeMoniker); public IEnumerable ProcessResults(DiagnoserResults results) => ImmutableArray.Empty; diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoserAttribute.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoserAttribute.cs similarity index 100% rename from src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoserAttribute.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoserAttribute.cs diff --git a/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceTool.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceTool.cs new file mode 100644 index 0000000000..1214b3b92e --- /dev/null +++ b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceTool.cs @@ -0,0 +1,131 @@ +using System; +using System.Diagnostics; +using System.IO; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Helpers; +using BenchmarkDotNet.Loggers; +using JetBrains.Profiler.SelfApi; +using BenchmarkDotNet.JetBrains; + +namespace BenchmarkDotNet.Diagnostics.dotTrace +{ + internal sealed class DotTraceTool + { + private readonly ILogger logger; + private readonly Uri? nugetUrl; + private readonly NuGetApi nugetApi; + private readonly string? downloadTo; + + public DotTraceTool(ILogger logger, Uri? nugetUrl = null, NuGetApi nugetApi = NuGetApi.V3, string? downloadTo = null) + { + this.logger = logger; + this.nugetUrl = nugetUrl; + this.nugetApi = nugetApi; + this.downloadTo = downloadTo; + } + + public void Init() + { + try + { + logger.WriteLineInfo("Ensuring that dotTrace prerequisite is installed..."); + var progress = new Progress(logger, "Installing DotTrace"); + DotTrace.EnsurePrerequisiteAsync(progress, nugetUrl, nugetApi, downloadTo).Wait(); + logger.WriteLineInfo("dotTrace prerequisite is installed"); + logger.WriteLineInfo($"dotTrace runner path: {Helper.GetRunnerPath(typeof(DotTrace))}"); + } + catch (Exception e) + { + logger.WriteLineError(e.ToString()); + } + } + + public string Start(DiagnoserActionParameters parameters) + { + string snapshotFile = ArtifactFileNameHelper.GetFilePath(parameters, "snapshots", DateTime.Now, "dtp", ".0000".Length); + string? snapshotDirectory = Path.GetDirectoryName(snapshotFile); + logger.WriteLineInfo($"Target snapshot file: {snapshotFile}"); + if (!Directory.Exists(snapshotDirectory) && snapshotDirectory != null) + { + try + { + Directory.CreateDirectory(snapshotDirectory); + } + catch (Exception e) + { + logger.WriteLineError($"Failed to create directory: {snapshotDirectory}"); + logger.WriteLineError(e.ToString()); + } + } + + try + { + logger.WriteLineInfo("Attaching dotTrace to the process..."); + Attach(parameters, snapshotFile); + logger.WriteLineInfo("dotTrace is successfully attached"); + } + catch (Exception e) + { + logger.WriteLineError(e.ToString()); + return snapshotFile; + } + + try + { + logger.WriteLineInfo("Start collecting data using dotTrace..."); + StartCollectingData(); + logger.WriteLineInfo("Data collection has successfully started"); + } + catch (Exception e) + { + logger.WriteLineError(e.ToString()); + } + + return snapshotFile; + } + + public void Stop() + { + try + { + logger.WriteLineInfo("Saving dotTrace snapshot..."); + SaveData(); + logger.WriteLineInfo("dotTrace snapshot is successfully saved to the artifact folder"); + } + catch (Exception e) + { + logger.WriteLineError(e.ToString()); + } + + try + { + logger.WriteLineInfo("Detaching dotTrace from the process..."); + Detach(); + logger.WriteLineInfo("dotTrace is successfully detached"); + } + catch (Exception e) + { + logger.WriteLineError(e.ToString()); + } + } + + private void Attach(DiagnoserActionParameters parameters, string snapshotFile) + { + var config = new DotTrace.Config(); + + var pid = parameters.Process.Id; + var currentPid = Process.GetCurrentProcess().Id; + if (pid != currentPid) + config = config.ProfileExternalProcess(pid); + + config = config.SaveToFile(snapshotFile); + DotTrace.Attach(config); + } + + private void StartCollectingData() => DotTrace.StartCollectingData(); + + private void SaveData() => DotTrace.SaveData(); + + private void Detach() => DotTrace.Detach(); + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/Properties/AssemblyInfo.cs b/src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/Properties/AssemblyInfo.cs similarity index 100% rename from src/BenchmarkDotNet.Diagnostics.dotTrace/Properties/AssemblyInfo.cs rename to src/JetBrains/BenchmarkDotNet.Diagnostics.dotTrace/Properties/AssemblyInfo.cs diff --git a/src/JetBrains/Shared/Helper.cs b/src/JetBrains/Shared/Helper.cs new file mode 100644 index 0000000000..020b659a6c --- /dev/null +++ b/src/JetBrains/Shared/Helper.cs @@ -0,0 +1,87 @@ +using System; +using System.Reflection; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Portability; + +namespace BenchmarkDotNet.JetBrains +{ + internal static class Helper + { + internal static bool IsSupported(RuntimeMoniker runtimeMoniker) + { + switch (runtimeMoniker) + { + case RuntimeMoniker.HostProcess: + case RuntimeMoniker.Net461: + case RuntimeMoniker.Net462: + case RuntimeMoniker.Net47: + case RuntimeMoniker.Net471: + case RuntimeMoniker.Net472: + case RuntimeMoniker.Net48: + case RuntimeMoniker.Net481: + case RuntimeMoniker.Net50: + case RuntimeMoniker.Net60: + case RuntimeMoniker.Net70: + case RuntimeMoniker.Net80: + case RuntimeMoniker.Net90: + return true; + case RuntimeMoniker.NotRecognized: + case RuntimeMoniker.Mono: + case RuntimeMoniker.NativeAot60: + case RuntimeMoniker.NativeAot70: + case RuntimeMoniker.NativeAot80: + case RuntimeMoniker.NativeAot90: + case RuntimeMoniker.Wasm: + case RuntimeMoniker.WasmNet50: + case RuntimeMoniker.WasmNet60: + case RuntimeMoniker.WasmNet70: + case RuntimeMoniker.WasmNet80: + case RuntimeMoniker.WasmNet90: + case RuntimeMoniker.MonoAOTLLVM: + case RuntimeMoniker.MonoAOTLLVMNet60: + case RuntimeMoniker.MonoAOTLLVMNet70: + case RuntimeMoniker.MonoAOTLLVMNet80: + case RuntimeMoniker.MonoAOTLLVMNet90: + case RuntimeMoniker.Mono60: + case RuntimeMoniker.Mono70: + case RuntimeMoniker.Mono80: + case RuntimeMoniker.Mono90: +#pragma warning disable CS0618 // Type or member is obsolete + case RuntimeMoniker.NetCoreApp50: +#pragma warning restore CS0618 // Type or member is obsolete + return false; + case RuntimeMoniker.NetCoreApp20: + case RuntimeMoniker.NetCoreApp21: + case RuntimeMoniker.NetCoreApp22: + return RuntimeInformation.IsWindows(); + case RuntimeMoniker.NetCoreApp30: + case RuntimeMoniker.NetCoreApp31: + return RuntimeInformation.IsWindows() || RuntimeInformation.IsLinux(); + default: + throw new ArgumentOutOfRangeException(nameof(runtimeMoniker), runtimeMoniker, $"Runtime moniker {runtimeMoniker} is not supported"); + } + } + + internal static string GetRunnerPath(Type type) + { + var consoleRunnerPackageField = type.GetField("ConsoleRunnerPackage", BindingFlags.NonPublic | BindingFlags.Static); + if (consoleRunnerPackageField == null) + throw new InvalidOperationException("Field 'ConsoleRunnerPackage' not found."); + + object? consoleRunnerPackage = consoleRunnerPackageField.GetValue(null); + if (consoleRunnerPackage == null) + throw new InvalidOperationException("Unable to get value of 'ConsoleRunnerPackage'."); + + var consoleRunnerPackageType = consoleRunnerPackage.GetType(); + var getRunnerPathMethod = consoleRunnerPackageType.GetMethod("GetRunnerPath"); + if (getRunnerPathMethod == null) + throw new InvalidOperationException("Method 'GetRunnerPath' not found."); + + string? runnerPath = getRunnerPathMethod.Invoke(consoleRunnerPackage, null) as string; + if (runnerPath == null) + throw new InvalidOperationException("Unable to invoke 'GetRunnerPath'."); + + return runnerPath; + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet.Diagnostics.dotTrace/Progress.cs b/src/JetBrains/Shared/Progress.cs similarity index 91% rename from src/BenchmarkDotNet.Diagnostics.dotTrace/Progress.cs rename to src/JetBrains/Shared/Progress.cs index c353939f1f..f09371412f 100644 --- a/src/BenchmarkDotNet.Diagnostics.dotTrace/Progress.cs +++ b/src/JetBrains/Shared/Progress.cs @@ -2,9 +2,9 @@ using System.Diagnostics; using BenchmarkDotNet.Loggers; -namespace BenchmarkDotNet.Diagnostics.dotTrace +namespace BenchmarkDotNet.JetBrains { - public class Progress : IProgress + internal sealed class Progress : IProgress { private static readonly TimeSpan ReportInterval = TimeSpan.FromSeconds(0.1); diff --git a/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj b/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj index a928af1424..d16cfcb9cb 100644 --- a/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj +++ b/tests/BenchmarkDotNet.IntegrationTests/BenchmarkDotNet.IntegrationTests.csproj @@ -28,8 +28,8 @@ - - + + diff --git a/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj b/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj index fcdc416bbf..f03cf5e344 100755 --- a/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj +++ b/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj @@ -35,8 +35,8 @@ - - + +