diff --git a/OpenTelemetry.AutoInstrumentation.sln b/OpenTelemetry.AutoInstrumentation.sln index bb8686b9e..f6332abb7 100644 --- a/OpenTelemetry.AutoInstrumentation.sln +++ b/OpenTelemetry.AutoInstrumentation.sln @@ -153,6 +153,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.MultipleApp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.Quartz", "test\test-applications\integrations\TestApplication.Quartz\TestApplication.Quartz.csproj", "{B48780CE-8AAB-44D3-9CD1-8491584352B5}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "test\Benchmarks\Benchmarks.csproj", "{B1E71654-E784-4A39-BE45-8671E027B6D7}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.EntityFrameworkCore", "test\test-applications\integrations\TestApplication.EntityFrameworkCore\TestApplication.EntityFrameworkCore.csproj", "{036A56A4-4EEF-42E3-9857-B9B00D302BF9}" EndProject Global @@ -723,6 +725,18 @@ Global {B48780CE-8AAB-44D3-9CD1-8491584352B5}.Release|x64.Build.0 = Release|x64 {B48780CE-8AAB-44D3-9CD1-8491584352B5}.Release|x86.ActiveCfg = Release|x86 {B48780CE-8AAB-44D3-9CD1-8491584352B5}.Release|x86.Build.0 = Release|x86 + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Debug|x64.ActiveCfg = Debug|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Debug|x64.Build.0 = Debug|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Debug|x86.ActiveCfg = Debug|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Debug|x86.Build.0 = Debug|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Release|Any CPU.Build.0 = Release|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Release|x64.ActiveCfg = Release|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Release|x64.Build.0 = Release|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Release|x86.ActiveCfg = Release|Any CPU + {B1E71654-E784-4A39-BE45-8671E027B6D7}.Release|x86.Build.0 = Release|Any CPU {036A56A4-4EEF-42E3-9857-B9B00D302BF9}.Debug|Any CPU.ActiveCfg = Debug|x64 {036A56A4-4EEF-42E3-9857-B9B00D302BF9}.Debug|Any CPU.Build.0 = Debug|x64 {036A56A4-4EEF-42E3-9857-B9B00D302BF9}.Debug|x64.ActiveCfg = Debug|x64 @@ -791,6 +805,7 @@ Global {5FDB5603-21D3-446A-8B50-36DACCF7C2FF} = {E409ADD3-9574-465C-AB09-4324D205CC7C} {A0338846-2AF8-4D96-ADA7-EBD4F010D08F} = {E409ADD3-9574-465C-AB09-4324D205CC7C} {B48780CE-8AAB-44D3-9CD1-8491584352B5} = {E409ADD3-9574-465C-AB09-4324D205CC7C} + {B1E71654-E784-4A39-BE45-8671E027B6D7} = {5C915382-C886-457D-8641-9E766D8E5A17} {036A56A4-4EEF-42E3-9857-B9B00D302BF9} = {E409ADD3-9574-465C-AB09-4324D205CC7C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/build/Build.Steps.cs b/build/Build.Steps.cs index 083ca7224..50d166bbe 100644 --- a/build/Build.Steps.cs +++ b/build/Build.Steps.cs @@ -150,6 +150,17 @@ partial class Build } }); + Target CompileBenchmarks => _ => _ + .Description("Compiles the Benchmarks project in the test directory") + .After(CompileManagedSrc) + .Executes(() => + { + DotNetBuild(x => x + .SetProjectFile(Solution.GetBenchmarks()) + .SetConfiguration(BuildConfiguration) + .EnableNoRestore()); + }); + Target CompileNativeSrc => _ => _ .Description("Compiles the native loader") .DependsOn(CompileNativeSrcWindows) diff --git a/build/Build.cs b/build/Build.cs index f02066b96..881edc049 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -77,7 +77,8 @@ partial class Build : NukeBuild .DependsOn(BuildTracer) .DependsOn(CompileExamples) .DependsOn(NativeTests) - .DependsOn(ManagedTests); + .DependsOn(ManagedTests) + .DependsOn(CompileBenchmarks); Target BuildTracer => _ => _ .Description("Builds the native and managed src, and publishes the tracer home directory") diff --git a/build/Projects.cs b/build/Projects.cs index f85849fd4..2ad887d85 100644 --- a/build/Projects.cs +++ b/build/Projects.cs @@ -12,6 +12,11 @@ public static class Projects public const string AutoInstrumentationMock = "OpenTelemetry.AutoInstrumentation.Mock"; } + public static class Benchmarks + { + public const string AutoInstrumentationBenchmarks = "Benchmarks"; + } + public static class Tests { public const string AutoInstrumentationNativeTests = "OpenTelemetry.AutoInstrumentation.Native.Tests"; diff --git a/build/ProjectsHelper.cs b/build/ProjectsHelper.cs index 07ff661c8..cd3bbc10f 100644 --- a/build/ProjectsHelper.cs +++ b/build/ProjectsHelper.cs @@ -72,6 +72,11 @@ public static class ProjectsHelper return solution.GetProject(Projects.Mocks.AutoInstrumentationMock); } + public static Project GetBenchmarks(this Solution solution) + { + return solution.GetProject(Projects.Benchmarks.AutoInstrumentationBenchmarks); + } + public static IEnumerable GetWindowsOnlyTestApplications(this Solution solution) { return solution @@ -96,7 +101,8 @@ public static class ProjectsHelper return solution.GetManagedSrcProjects() .Concat(solution.GetManagedTestProjects()) .Concat(solution.GetCrossPlatformTestApplications()) - .Concat(new[] { solution.GetTestMock() }); + .Concat(new[] { solution.GetTestMock() }) + .Concat(new[] { solution.GetBenchmarks() }); } public static IEnumerable GetNativeProjects(this Solution solution) diff --git a/src/OpenTelemetry.AutoInstrumentation.Loader/Properties/AssemblyInfo.cs b/src/OpenTelemetry.AutoInstrumentation.Loader/Properties/AssemblyInfo.cs index 8b2ac04a7..0094607e4 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Loader/Properties/AssemblyInfo.cs +++ b/src/OpenTelemetry.AutoInstrumentation.Loader/Properties/AssemblyInfo.cs @@ -16,4 +16,5 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Benchmarks")] [assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.Loader.Tests")] diff --git a/src/OpenTelemetry.AutoInstrumentation.Loader/StartupLogger.cs b/src/OpenTelemetry.AutoInstrumentation.Loader/StartupLogger.cs index 851147986..3e1b88aee 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Loader/StartupLogger.cs +++ b/src/OpenTelemetry.AutoInstrumentation.Loader/StartupLogger.cs @@ -77,6 +77,49 @@ internal static class StartupLogger } } + internal static string? SetStartupLogFilePath() + { + if (LogDirectory == null) + { + return null; + } + + try + { + // Pick up the parts used to build the log file name and minimize the chances + // of file name conflict with other processes. + using var process = Process.GetCurrentProcess(); + + // AppDomain friendly name can contain characters that are invalid in file names, + // remove any of those. For the first assembly loaded by the process this is typically + // expected to be name of the file with the application entry point. + var appDomainFriendlyName = AppDomain.CurrentDomain.FriendlyName; + var invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); + var sb = new StringBuilder(appDomainFriendlyName); + for (int i = 0; i < sb.Length; i++) + { + if (invalidChars.IndexOf(sb[i]) != -1) + { + sb[i] = '_'; + } + } + + appDomainFriendlyName = sb.ToString(); + + // AppDomain friendly name may not be unique in the same process, use also the id. + // Per documentation the id is an integer that uniquely identifies the application + // domain within the process. + var appDomainId = AppDomain.CurrentDomain.Id; + + return Path.Combine(LogDirectory, $"otel-dotnet-auto-loader-{appDomainFriendlyName}-{appDomainId}-{process?.Id}.log"); + } + catch + { + // We can't get the process info + return Path.Combine(LogDirectory, $"otel-dotnet-auto-loader-{Guid.NewGuid()}.log"); + } + } + private static string? GetLogDirectory() { string? logDirectory = null; @@ -131,49 +174,6 @@ internal static class StartupLogger } } - private static string? SetStartupLogFilePath() - { - if (LogDirectory == null) - { - return null; - } - - try - { - // Pick up the parts used to build the log file name and minimize the chances - // of file name conflict with other processes. - using var process = Process.GetCurrentProcess(); - - // AppDomain friendly name can contain characters that are invalid in file names, - // remove any of those. For the first assembly loaded by the process this is typically - // expected to be name of the file with the application entry point. - var appDomainFriendlyName = AppDomain.CurrentDomain.FriendlyName; - var invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); - var sb = new StringBuilder(appDomainFriendlyName); - for (int i = 0; i < sb.Length; i++) - { - if (invalidChars.IndexOf(sb[i]) != -1) - { - sb[i] = '_'; - } - } - - appDomainFriendlyName = sb.ToString(); - - // AppDomain friendly name may not be unique in the same process, use also the id. - // Per documentation the id is an integer that uniquely identifies the application - // domain within the process. - var appDomainId = AppDomain.CurrentDomain.Id; - - return Path.Combine(LogDirectory, $"otel-dotnet-auto-loader-{appDomainFriendlyName}-{appDomainId}-{process?.Id}.log"); - } - catch - { - // We can't get the process info - return Path.Combine(LogDirectory, $"otel-dotnet-auto-loader-{Guid.NewGuid()}.log"); - } - } - private static FileSink? SetLogFileSink() { if (StartupLogFilePath == null) diff --git a/test/Benchmarks/Benchmarks.csproj b/test/Benchmarks/Benchmarks.csproj new file mode 100644 index 000000000..ea2c0f96e --- /dev/null +++ b/test/Benchmarks/Benchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + + + + + + + + + + diff --git a/test/Benchmarks/Directory.Build.props b/test/Benchmarks/Directory.Build.props new file mode 100644 index 000000000..0db3fad41 --- /dev/null +++ b/test/Benchmarks/Directory.Build.props @@ -0,0 +1,13 @@ + + + + + + + + + enable + enable + + + diff --git a/test/Benchmarks/Program.cs b/test/Benchmarks/Program.cs new file mode 100644 index 000000000..6fea543ad --- /dev/null +++ b/test/Benchmarks/Program.cs @@ -0,0 +1,24 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using BenchmarkDotNet.Running; + +namespace OpenTelemetry.AutoInstrumentation.Loader.Benchmarks; + +internal class Program +{ + private static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); +} diff --git a/test/Benchmarks/StartupLoggerBenchmarks.cs b/test/Benchmarks/StartupLoggerBenchmarks.cs new file mode 100644 index 000000000..c32309930 --- /dev/null +++ b/test/Benchmarks/StartupLoggerBenchmarks.cs @@ -0,0 +1,42 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using BenchmarkDotNet.Attributes; + +/* +BenchmarkDotNet=v0.13.4, OS=Windows 11 (10.0.22621.1105) +Intel Core i9-10900K CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores +.NET SDK=7.0.200-preview.22628.1 + [Host] : .NET 6.0.13 (6.0.1322.58009), X64 RyuJIT AVX2 + DefaultJob : .NET 6.0.13 (6.0.1322.58009), X64 RyuJIT AVX2 + + +| Method | Mean | Error | StdDev | Gen0 | Allocated | +|---------------------- |---------:|----------:|----------:|-------:|----------:| +| SetStartupLogFilePath | 1.458 us | 0.0133 us | 0.0111 us | 0.2136 | 2.19 KB | + */ + +namespace OpenTelemetry.AutoInstrumentation.Loader.Benchmarks; + +[MemoryDiagnoser] +public class StartupLoggerBenchmarks +{ + [Benchmark] + public void SetStartupLogFilePath() + { + var path = StartupLogger.SetStartupLogFilePath(); + } +} diff --git a/test/Directory.Packages.props b/test/Directory.Packages.props index 4b88a612c..02095a4ec 100644 --- a/test/Directory.Packages.props +++ b/test/Directory.Packages.props @@ -2,6 +2,7 @@ +