Feature Complete
- Add remaining test scenarios - Refactor implementation - Add gitignore entry for optimization profiles
This commit is contained in:
parent
94e620088e
commit
304434433b
5 changed files with 165 additions and 30 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,6 +3,9 @@
|
||||||
# Test results
|
# Test results
|
||||||
*-testResults.xml
|
*-testResults.xml
|
||||||
|
|
||||||
|
# Multicore JIT Optimization profiles
|
||||||
|
**/optimizationdata/dotnet
|
||||||
|
|
||||||
# NuGet keeps dropping
|
# NuGet keeps dropping
|
||||||
Library/
|
Library/
|
||||||
|
|
||||||
|
|
46
src/dotnet/MulticoreJitActivator.cs
Normal file
46
src/dotnet/MulticoreJitActivator.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Loader;
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Microsoft.DotNet.Tools.Common;
|
||||||
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Cli
|
||||||
|
{
|
||||||
|
public class MulticoreJitActivator
|
||||||
|
{
|
||||||
|
public bool TryActivateMulticoreJit()
|
||||||
|
{
|
||||||
|
var disableMulticoreJit = IsMulticoreJitDisabled();
|
||||||
|
|
||||||
|
if (disableMulticoreJit)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartCliProfileOptimization();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsMulticoreJitDisabled()
|
||||||
|
{
|
||||||
|
return Environment.GetEnvironmentVariable("DOTNET_DISABLE_MULTICOREJIT") == "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartCliProfileOptimization()
|
||||||
|
{
|
||||||
|
var profileOptimizationRootPath = new MulticoreJitProfilePathCalculator().MulticoreJitProfilePath;
|
||||||
|
|
||||||
|
PathUtility.EnsureDirectory(profileOptimizationRootPath);
|
||||||
|
|
||||||
|
AssemblyLoadContext.Default.SetProfileOptimizationRoot(profileOptimizationRootPath);
|
||||||
|
|
||||||
|
AssemblyLoadContext.Default.StartProfileOptimization("dotnet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,11 +42,9 @@ namespace Microsoft.DotNet.Cli
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
DebugHelper.HandleDebugSwitch(ref args);
|
DebugHelper.HandleDebugSwitch(ref args);
|
||||||
|
|
||||||
AssemblyLoadContext.Default.SetProfileOptimizationRoot(
|
new MulticoreJitActivator().TryActivateMulticoreJit();
|
||||||
new MulticoreJitProfilePathCalculator().MulticoreJitProfilePath);
|
|
||||||
AssemblyLoadContext.Default.StartProfileOptimization("dotnet");
|
|
||||||
|
|
||||||
if (Env.GetEnvironmentVariableAsBool("DOTNET_CLI_CAPTURE_TIMING", false))
|
if (Env.GetEnvironmentVariableAsBool("DOTNET_CLI_CAPTURE_TIMING", false))
|
||||||
{
|
{
|
||||||
PerfTrace.Enabled = true;
|
PerfTrace.Enabled = true;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
using Microsoft.DotNet.Cli.Utils;
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Microsoft.DotNet.TestFramework;
|
||||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
using System;
|
using System;
|
||||||
|
@ -16,52 +17,101 @@ namespace Microsoft.DotNet.Tests
|
||||||
public class GivenThatIWantToManageMulticoreJIT : TestBase
|
public class GivenThatIWantToManageMulticoreJIT : TestBase
|
||||||
{
|
{
|
||||||
ITestOutputHelper _output;
|
ITestOutputHelper _output;
|
||||||
private const string OptimizationProfileFileName = "dotnet.";
|
private const string OptimizationProfileFileName = "dotnet";
|
||||||
private readonly string _optimizationProfileFilePath;
|
|
||||||
|
|
||||||
public GivenThatIWantToManageMulticoreJIT(ITestOutputHelper output)
|
public GivenThatIWantToManageMulticoreJIT(ITestOutputHelper output)
|
||||||
{
|
{
|
||||||
_output = output;
|
_output = output;
|
||||||
_optimizationProfileFilePath = GetOptimizationProfileFilePath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void When_invoked_it_writes_optimization_data_to_the_profile_root()
|
public void When_invoked_then_dotnet_writes_optimization_data_to_the_profile_root()
|
||||||
{
|
{
|
||||||
var testStartTime = DateTime.UtcNow;
|
var testDirectory = TestAssetsManager.CreateTestDirectory();
|
||||||
|
var testStartTime = GetTruncatedDateTime();
|
||||||
|
|
||||||
new TestCommand("dotnet")
|
new TestCommand("dotnet")
|
||||||
.Execute("--version");
|
.WithUserProfileRoot(testDirectory.Path)
|
||||||
|
.ExecuteWithCapturedOutput("--help");
|
||||||
|
|
||||||
|
|
||||||
File.Exists(_optimizationProfileFilePath)
|
var optimizationProfileFilePath = GetOptimizationProfileFilePath(testDirectory.Path);
|
||||||
|
|
||||||
|
File.Exists(optimizationProfileFilePath)
|
||||||
.Should().BeTrue("Because dotnet CLI creates it after each run");
|
.Should().BeTrue("Because dotnet CLI creates it after each run");
|
||||||
|
|
||||||
File.GetLastWriteTimeUtc(_optimizationProfileFilePath)
|
File.GetLastWriteTimeUtc(optimizationProfileFilePath)
|
||||||
.Should().BeOnOrAfter(testStartTime, "Because dotnet CLI was executed after that time.");
|
.Should().BeOnOrAfter(testStartTime, "Because dotnet CLI was executed after that time");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetOptimizationProfileFilePath()
|
[Fact]
|
||||||
|
public void When_invoked_with_MulticoreJit_disabled_then_dotnet_does_not_writes_optimization_data_to_the_profile_root()
|
||||||
{
|
{
|
||||||
Console.WriteLine(GetOptimizationRootPath(GetDotnetVersion()));
|
var testDirectory = TestAssetsManager.CreateTestDirectory();
|
||||||
return Path.Combine(GetOptimizationRootPath(GetDotnetVersion()),
|
var testStartTime = GetTruncatedDateTime();
|
||||||
|
|
||||||
|
new TestCommand("dotnet")
|
||||||
|
.WithUserProfileRoot(testDirectory.Path)
|
||||||
|
.WithEnvironmentVariable("DOTNET_DISABLE_MULTICOREJIT", "1")
|
||||||
|
.ExecuteWithCapturedOutput("--help");
|
||||||
|
|
||||||
|
|
||||||
|
var optimizationProfileFilePath = GetOptimizationProfileFilePath(testDirectory.Path);
|
||||||
|
|
||||||
|
File.Exists(optimizationProfileFilePath)
|
||||||
|
.Should().BeFalse("Because multicore JIT is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void When_the_profile_root_is_undefined_then_dotnet_does_not_crash()
|
||||||
|
{
|
||||||
|
var testDirectory = TestAssetsManager.CreateTestDirectory();
|
||||||
|
var testStartTime = GetTruncatedDateTime();
|
||||||
|
|
||||||
|
var optimizationProfileFilePath = GetOptimizationProfileFilePath(testDirectory.Path);
|
||||||
|
|
||||||
|
new TestCommand("dotnet")
|
||||||
|
.WithUserProfileRoot("")
|
||||||
|
.ExecuteWithCapturedOutput("--help")
|
||||||
|
.Should().Pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void When_cli_repo_builds_then_dotnet_writes_optimization_data_to_the_default_profile_root()
|
||||||
|
{
|
||||||
|
var optimizationProfileFilePath = GetOptimizationProfileFilePath();
|
||||||
|
|
||||||
|
File.Exists(optimizationProfileFilePath)
|
||||||
|
.Should().BeTrue("Because the dotnet building dotnet writes to the default root");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetOptimizationProfileFilePath(string userHomePath = null)
|
||||||
|
{
|
||||||
|
return Path.Combine(
|
||||||
|
GetUserProfileRoot(userHomePath),
|
||||||
|
GetOptimizationRootPath(GetDotnetVersion()),
|
||||||
OptimizationProfileFileName);
|
OptimizationProfileFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetUserProfileRoot(string overrideUserProfileRoot = null)
|
||||||
|
{
|
||||||
|
if (overrideUserProfileRoot != null)
|
||||||
|
{
|
||||||
|
return overrideUserProfileRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||||
|
? Environment.GetEnvironmentVariable("LocalAppData")
|
||||||
|
: Environment.GetEnvironmentVariable("HOME");
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetOptimizationRootPath(string version)
|
private static string GetOptimizationRootPath(string version)
|
||||||
{
|
{
|
||||||
|
var rid = PlatformServices.Default.Runtime.GetRuntimeIdentifier();
|
||||||
|
|
||||||
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||||
? GetWindowsProfileRoot(version)
|
? $@"Microsoft\dotnet\sdk\{version}{rid}\optimizationdata"
|
||||||
: GetNonWindowsProfileRoot(version);
|
: $@".dotnet/sdk/{version}/{rid}/optimizationdata";
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetWindowsProfileRoot(string version)
|
|
||||||
{
|
|
||||||
return $@"{(Environment.GetEnvironmentVariable("LocalAppData"))}\Microsoft\dotnet\sdk\{version}\optimizationdata";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetNonWindowsProfileRoot(string version)
|
|
||||||
{
|
|
||||||
return $"{(Environment.GetEnvironmentVariable("HOME"))}/.dotnet/sdk/{version}/optimizationdata";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDotnetVersion()
|
private static string GetDotnetVersion()
|
||||||
|
@ -72,5 +122,12 @@ namespace Microsoft.DotNet.Tests
|
||||||
.StdOut
|
.StdOut
|
||||||
.Trim();
|
.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DateTime GetTruncatedDateTime()
|
||||||
|
{
|
||||||
|
var dt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, 0, dt.Kind);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
31
test/dotnet.Tests/TestCommandExtensions.cs
Normal file
31
test/dotnet.Tests/TestCommandExtensions.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||||
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Tests
|
||||||
|
{
|
||||||
|
public static class TestCommandExtensions
|
||||||
|
{
|
||||||
|
public static TestCommand WithUserProfileRoot(this TestCommand testCommand, string path)
|
||||||
|
{
|
||||||
|
var userProfileEnvironmentVariableName = GetUserProfileEnvironmentVariableName();
|
||||||
|
return testCommand.WithEnvironmentVariable(userProfileEnvironmentVariableName, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetUserProfileEnvironmentVariableName()
|
||||||
|
{
|
||||||
|
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||||
|
? "LocalAppData"
|
||||||
|
: "HOME";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue