Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit 76c8f18

Browse files
authored
enable tiered compilation and use latest C# lang version (#1722)
* enable tiered compilation, move to .netstandard 2.1 and use latest C# lang we should take advantage of ProfileOptimization (https://docs.microsoft.com/en-us/dotnet/api/system.runtime.profileoptimization?view=netcore-3.0) to make starting time faster once we move to .netstandard 3.0 * enable profile optimization to enable background JIT * put user name at the path of profile if user name exist * revert back .net standard to 2.0 since we are used in VS for PTVS which is still on .net fx moved where we enable profile optimization back to the point where the server is initialized. lang version is still left as latest even though it is "unsupported", according to .net people, it is common that people use latest with 2.0 and make sure some language features that doesnt work such as default interface implementation are not used. * refactor a bit so that we can set up cache at initialize and start profiling on initialize * removed PythonAnalyzer IServiceManager dependency since it no longer register services * addressed PR feedback * abstract out profile optimization
1 parent c88abfb commit 76c8f18

20 files changed

+183
-37
lines changed

src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
using System.Runtime.ExceptionServices;
2121
using System.Threading;
2222
using System.Threading.Tasks;
23-
using Microsoft.Python.Analysis.Caching;
2423
using Microsoft.Python.Analysis.Dependencies;
2524
using Microsoft.Python.Analysis.Diagnostics;
2625
using Microsoft.Python.Analysis.Documents;
@@ -36,7 +35,7 @@
3635

3736
namespace Microsoft.Python.Analysis.Analyzer {
3837
public sealed class PythonAnalyzer : IPythonAnalyzer, IDisposable {
39-
private readonly IServiceManager _services;
38+
private readonly IServiceContainer _services;
4039
private readonly IDependencyResolver<AnalysisModuleKey, PythonAnalyzerEntry> _dependencyResolver;
4140
private readonly Dictionary<AnalysisModuleKey, PythonAnalyzerEntry> _analysisEntries = new Dictionary<AnalysisModuleKey, PythonAnalyzerEntry>();
4241
private readonly DisposeToken _disposeToken = DisposeToken.Create<PythonAnalyzer>();
@@ -51,17 +50,14 @@ public sealed class PythonAnalyzer : IPythonAnalyzer, IDisposable {
5150
private PythonAnalyzerSession _nextSession;
5251
private bool _forceGCOnNextSession;
5352

54-
public PythonAnalyzer(IServiceManager services, string cacheFolderPath = null) {
53+
public PythonAnalyzer(IServiceContainer services) {
5554
_services = services;
5655
_log = services.GetService<ILogger>();
5756
_dependencyResolver = new DependencyResolver<AnalysisModuleKey, PythonAnalyzerEntry>();
5857
_analysisCompleteEvent.Set();
5958
_startNextSession = StartNextSession;
6059

6160
_progress = new ProgressReporter(services.GetService<IProgressService>());
62-
63-
_services.AddService(new CacheFolderService(_services, cacheFolderPath));
64-
_services.AddService(new StubCache(_services));
6561
}
6662

6763
public void Dispose() {

src/Analysis/Ast/Impl/Analyzer/PythonAnalyzerSession.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
using Microsoft.Python.Analysis.Types;
3030
using Microsoft.Python.Core;
3131
using Microsoft.Python.Core.Logging;
32-
using Microsoft.Python.Core.Services;
3332
using Microsoft.Python.Core.Testing;
3433
using Microsoft.Python.Parsing.Ast;
3534

@@ -42,7 +41,7 @@ internal sealed class PythonAnalyzerSession {
4241
private readonly PythonAnalyzerEntry _entry;
4342
private readonly Action<Task> _startNextSession;
4443
private readonly CancellationToken _analyzerCancellationToken;
45-
private readonly IServiceManager _services;
44+
private readonly IServiceContainer _services;
4645
private readonly IDiagnosticsService _diagnosticsService;
4746
private readonly IProgressReporter _progress;
4847
private readonly IPythonAnalyzer _analyzer;
@@ -65,7 +64,7 @@ public bool IsCompleted {
6564
public int Version { get; }
6665
public int AffectedEntriesCount { get; }
6766

68-
public PythonAnalyzerSession(IServiceManager services,
67+
public PythonAnalyzerSession(IServiceContainer services,
6968
IProgressReporter progress,
7069
Action<Task> startNextSession,
7170
CancellationToken analyzerCancellationToken,

src/Analysis/Ast/Impl/Caching/CacheFolders.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
using System;
1717
using System.Diagnostics;
1818
using System.IO;
19-
using System.Security.Cryptography;
20-
using System.Text;
2119
using Microsoft.Python.Core;
2220
using Microsoft.Python.Core.Logging;
2321
using Microsoft.Python.Core.OS;
@@ -30,14 +28,7 @@ public CacheFolderService(IServiceContainer services, string cacheRootFolder) {
3028

3129
public string CacheFolder { get; }
3230

33-
public string GetFileNameFromContent(string content) {
34-
// File name depends on the content so we can distinguish between different versions.
35-
using (var hash = SHA256.Create()) {
36-
return Convert
37-
.ToBase64String(hash.ComputeHash(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(content)))
38-
.Replace('/', '_').Replace('+', '-');
39-
}
40-
}
31+
public string GetFileNameFromContent(string content) => content.GetHashString();
4132

4233
private static string GetCacheFolder(IServiceContainer services) {
4334
var platform = services.GetService<IOSPlatform>();
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright(c) Microsoft Corporation
2+
// All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the License); you may not use
5+
// this file except in compliance with the License. You may obtain a copy of the
6+
// License at http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
9+
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
10+
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
11+
// MERCHANTABILITY OR NON-INFRINGEMENT.
12+
//
13+
// See the Apache Version 2.0 License for specific language governing
14+
// permissions and limitations under the License.
15+
16+
using System.Diagnostics;
17+
using Microsoft.Python.Core;
18+
using Microsoft.Python.Core.IO;
19+
using Microsoft.Python.Core.Logging;
20+
using Microsoft.Python.Core.Services;
21+
22+
namespace Microsoft.Python.Analysis.Caching {
23+
/// <summary>
24+
/// Register caching services for the given cache folder path
25+
/// </summary>
26+
public static class CacheService {
27+
public static void Register(IServiceManager services, string cacheFolderPath) {
28+
var log = services.GetService<ILogger>();
29+
var fs = services.GetService<IFileSystem>();
30+
31+
// this is not thread safe. this is not supposed to be called concurrently
32+
var cachingService = services.GetService<ICacheFolderService>();
33+
if (cachingService != null) {
34+
return;
35+
}
36+
37+
if (cacheFolderPath != null && !fs.DirectoryExists(cacheFolderPath)) {
38+
log?.Log(TraceEventType.Warning, Resources.Invalid_0_CacheFolder.FormatUI(cacheFolderPath));
39+
cacheFolderPath = null;
40+
}
41+
42+
services.AddService(new CacheFolderService(services, cacheFolderPath));
43+
services.AddService(new StubCache(services));
44+
}
45+
}
46+
}

src/Analysis/Ast/Impl/Microsoft.Python.Analysis.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1701, 1702 - "You may need to supply assembly policy"
1010
-->
1111
<NoWarn>1701;1702;$(NoWarn)</NoWarn>
12-
<LangVersion>7.2</LangVersion>
12+
<TieredCompilation>true</TieredCompilation>
1313
</PropertyGroup>
1414
<Import Project="..\..\..\..\build\NetStandard.settings" />
1515
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

src/Analysis/Ast/Impl/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Analysis/Ast/Impl/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,7 @@
222222
<data name="Analysis_PositionalOnlyArgumentNamed" xml:space="preserve">
223223
<value>Positional only argument '{0}' may not be named.</value>
224224
</data>
225+
<data name="Invalid_0_CacheFolder" xml:space="preserve">
226+
<value>Specified cache folder ('{0}') does not exist. Switching to default.</value>
227+
</data>
225228
</root>

src/Analysis/Ast/Test/AnalysisTestBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using System.Threading.Tasks;
2121
using FluentAssertions;
2222
using Microsoft.Python.Analysis.Analyzer;
23+
using Microsoft.Python.Analysis.Caching;
2324
using Microsoft.Python.Analysis.Core.Interpreter;
2425
using Microsoft.Python.Analysis.Diagnostics;
2526
using Microsoft.Python.Analysis.Documents;
@@ -83,7 +84,9 @@ protected async Task<IServiceManager> CreateServicesAsync(string root, Interpret
8384
}
8485

8586
TestLogger.Log(TraceEventType.Information, "Create PythonAnalyzer");
86-
var analyzer = new PythonAnalyzer(sm, stubCacheFolderPath);
87+
88+
CacheService.Register(sm, stubCacheFolderPath);
89+
var analyzer = new PythonAnalyzer(sm);
8790
sm.AddService(analyzer);
8891

8992
TestLogger.Log(TraceEventType.Information, "Create PythonInterpreter");

src/Analysis/Core/Impl/Microsoft.Python.Analysis.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1701, 1702 - "You may need to supply assembly policy"
1010
-->
1111
<NoWarn>1701;1702;$(NoWarn)</NoWarn>
12-
<LangVersion>7.2</LangVersion>
12+
<TieredCompilation>true</TieredCompilation>
1313
</PropertyGroup>
1414
<Import Project="..\..\..\..\build\NetStandard.settings" />
1515
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

src/Caching/Impl/Microsoft.Python.Analysis.Caching.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<TargetFramework>netstandard2.1</TargetFramework>
3+
<TargetFramework>netstandard2.0</TargetFramework>
44
<RootNamespace>Microsoft.Python.Analysis.Caching</RootNamespace>
55
<AssemblyName>Microsoft.Python.Analysis.Caching</AssemblyName>
66
</PropertyGroup>
@@ -9,7 +9,7 @@
99
1701, 1702 - "You may need to supply assembly policy"
1010
-->
1111
<NoWarn>1701;1702;$(NoWarn)</NoWarn>
12-
<LangVersion>7.2</LangVersion>
12+
<TieredCompilation>true</TieredCompilation>
1313
</PropertyGroup>
1414
<Import Project="..\..\..\build\NetStandard.settings" />
1515
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

src/Core/Impl/Extensions/StringExtensions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
using System.Globalization;
2020
using System.Linq;
2121
using System.Runtime.InteropServices;
22+
using System.Security.Cryptography;
23+
using System.Text;
2224
using System.Text.RegularExpressions;
2325
using Microsoft.Python.Core.Text;
2426

@@ -313,5 +315,19 @@ public static int GetStableHash(this string s) {
313315
return hash;
314316
}
315317
}
318+
319+
/// <summary>
320+
/// return string representation of hash of the input string.
321+
///
322+
/// the string representation of the hash is in the form where it can be used in a file system.
323+
/// </summary>
324+
public static string GetHashString(this string input) {
325+
// File name depends on the content so we can distinguish between different versions.
326+
using (var hash = SHA256.Create()) {
327+
return Convert
328+
.ToBase64String(hash.ComputeHash(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(input)))
329+
.Replace('/', '_').Replace('+', '-');
330+
}
331+
}
316332
}
317333
}

src/Core/Impl/Microsoft.Python.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1701, 1702 - "You may need to supply assembly policy"
1010
-->
1111
<NoWarn>1701;1702;$(NoWarn)</NoWarn>
12-
<LangVersion>7.3</LangVersion>
12+
<TieredCompilation>true</TieredCompilation>
1313
</PropertyGroup>
1414
<Import Project="..\..\..\build\NetStandard.settings" />
1515
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

src/LanguageServer/Impl/Implementation/Server.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,7 @@ public async Task InitializedAsync(InitializedParams @params, CancellationToken
123123

124124
_services.AddService(new DiagnosticsService(_services));
125125

126-
var cacheFolderPath = initializationOptions?.cacheFolderPath;
127-
var fs = _services.GetService<IFileSystem>();
128-
if (cacheFolderPath != null && !fs.DirectoryExists(cacheFolderPath)) {
129-
_log?.Log(TraceEventType.Warning, Resources.Error_InvalidCachePath);
130-
cacheFolderPath = null;
131-
}
132-
133-
var analyzer = new PythonAnalyzer(_services, cacheFolderPath);
126+
var analyzer = new PythonAnalyzer(_services);
134127
_services.AddService(analyzer);
135128

136129
analyzer.AnalysisComplete += OnAnalysisComplete;

src/LanguageServer/Impl/LanguageServer.Lifetime.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
using System.Diagnostics;
1818
using System.Threading;
1919
using System.Threading.Tasks;
20+
using Microsoft.Python.Analysis.Caching;
2021
using Microsoft.Python.Core;
22+
using Microsoft.Python.LanguageServer.Optimization;
2123
using Microsoft.Python.LanguageServer.Protocol;
2224
using Newtonsoft.Json.Linq;
2325
using StreamJsonRpc;
@@ -33,15 +35,20 @@ public partial class LanguageServer {
3335
public async Task<InitializeResult> Initialize(JToken token, CancellationToken cancellationToken) {
3436
_initParams = token.ToObject<InitializeParams>();
3537
MonitorParentProcess(_initParams);
38+
RegisterServices(_initParams);
39+
3640
using (await _prioritizer.InitializePriorityAsync(cancellationToken)) {
3741
// Force the next handled request to be "initialized", where the work actually happens.
3842
_initializedPriorityTask = _prioritizer.InitializePriorityAsync(default);
39-
return await _server.InitializeAsync(_initParams, cancellationToken);
43+
var result = await _server.InitializeAsync(_initParams, cancellationToken);
44+
return result;
4045
}
4146
}
4247

4348
[JsonRpcMethod("initialized")]
4449
public async Task Initialized(JToken token, CancellationToken cancellationToken) {
50+
_services.GetService<IProfileOptimizationService>()?.Profile("Initialized");
51+
4552
using (await _initializedPriorityTask) {
4653
var pythonSection = await GetPythonConfigurationAsync(cancellationToken, 200);
4754
var userConfiguredPaths = GetUserConfiguredPaths(pythonSection);
@@ -117,5 +124,12 @@ private void MonitorParentProcess(InitializeParams p) {
117124
}).DoNotWait();
118125
}
119126
}
127+
128+
private void RegisterServices(InitializeParams initParams) {
129+
// we need to register cache service first.
130+
// optimization service consumes the cache info.
131+
CacheService.Register(_services, initParams?.initializationOptions?.cacheFolderPath);
132+
_services.AddService(new ProfileOptimizationService(_services));
133+
}
120134
}
121135
}

src/LanguageServer/Impl/LanguageServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public sealed partial class LanguageServer : IDisposable {
4545
private readonly CancellationTokenSource _shutdownCts = new CancellationTokenSource();
4646
private readonly AnalysisOptionsProvider _optionsProvider = new AnalysisOptionsProvider();
4747

48-
private IServiceContainer _services;
48+
private IServiceManager _services;
4949
private Server _server;
5050
private ILogger _logger;
5151
private ITelemetryService _telemetry;

src/LanguageServer/Impl/Microsoft.Python.LanguageServer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<DebugType>portable</DebugType>
1212
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
1313
<NoWarn>1701;1702;$(NoWarn)</NoWarn>
14-
<LangVersion>7.2</LangVersion>
14+
<TieredCompilation>true</TieredCompilation>
1515
</PropertyGroup>
1616
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
1717
<CodeAnalysisRuleSet>..\..\PLS.ruleset</CodeAnalysisRuleSet>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Python Tools for Visual Studio
2+
// Copyright(c) Microsoft Corporation
3+
// All rights reserved.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the License); you may not use
6+
// this file except in compliance with the License. You may obtain a copy of the
7+
// License at http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
10+
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
11+
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
12+
// MERCHANTABILITY OR NON-INFRINGEMENT.
13+
//
14+
// See the Apache Version 2.0 License for specific language governing
15+
// permissions and limitations under the License.
16+
17+
using System.Runtime;
18+
19+
namespace Microsoft.Python.LanguageServer.Optimization {
20+
/// <summary>
21+
/// Service to enable profile based optimization
22+
///
23+
/// See <see cref="ProfileOptimization" /> for more detail
24+
/// </summary>
25+
internal interface IProfileOptimizationService {
26+
void Profile(string name);
27+
}
28+
}

0 commit comments

Comments
 (0)