Skip to content
This repository was archived by the owner on Nov 4, 2024. It is now read-only.

Commit 6db6dc7

Browse files
author
Mikhail Arkhipov
authored
Drop file content to conserve memory (microsoft#1133)
* Remove local variables * Drop file content to save memory * Cache PEP hints * Test fixes * Add options to keep data in memory
1 parent 4dc6edc commit 6db6dc7

File tree

10 files changed

+69
-3
lines changed

10 files changed

+69
-3
lines changed

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Hints.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,15 @@ namespace Microsoft.Python.Analysis.Analyzer.Evaluation {
2626
/// and types in a chain of scopes during analysis.
2727
/// </summary>
2828
internal sealed partial class ExpressionEval {
29+
private const string _pepHintKey = "PEP Hint";
30+
2931
public IPythonType GetTypeFromPepHint(Node node) {
32+
if (Ast.TryGetAttribute(node, _pepHintKey, out var typeStringObject) && typeStringObject is string typeString) {
33+
return GetTypeFromString(typeString);
34+
}
35+
3036
var location = GetLocationInfo(node);
37+
3138
var content = (Module as IDocument)?.Content;
3239
if (string.IsNullOrEmpty(content) || !location.EndLine.HasValue) {
3340
return null;
@@ -79,7 +86,9 @@ public IPythonType GetTypeFromPepHint(Node node) {
7986
}
8087

8188
// Type alone is not a valid syntax, so we need to simulate the annotation.
82-
var typeString = content.Substring(hintStart, i - hintStart).Trim();
89+
typeString = content.Substring(hintStart, i - hintStart).Trim();
90+
Ast.SetAttribute(node, _pepHintKey, typeString);
91+
8392
return GetTypeFromString(typeString);
8493
}
8594

src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ public override void Evaluate() {
7979
if (ctor || annotationType.IsUnknown() || Module.ModuleType == ModuleType.User) {
8080
// Return type from the annotation is sufficient for libraries and stubs, no need to walk the body.
8181
FunctionDefinition.Body?.Walk(this);
82+
// For libraries remove declared local function variables to free up some memory.
83+
var optionsProvider = Eval.Services.GetService<IAnalysisOptionsProvider>();
84+
if (Module.ModuleType != ModuleType.User && optionsProvider?.Options.KeepLibraryLocalVariables != true) {
85+
((VariableCollection)Eval.CurrentScope.Variables).Clear();
86+
}
8287
}
8388
}
8489
Result = _function;

src/Analysis/Ast/Impl/Definitions/AnalysisOptions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,18 @@
1616
namespace Microsoft.Python.Analysis {
1717
public class AnalysisOptions {
1818
public bool LintingEnabled { get; set; }
19+
20+
/// <summary>
21+
/// Keep in memory information on local variables declared in
22+
/// functions in libraries. Provides ability to navigate to
23+
/// symbols used in function bodies in packages and libraries.
24+
/// </summary>
25+
public bool KeepLibraryLocalVariables { get; set; }
26+
27+
/// <summary>
28+
/// Keep in memory AST of library source code. May somewhat
29+
/// improve performance when library code has to be re-analyzed.
30+
/// </summary>
31+
public bool KeepLibraryAst { get; set; }
1932
}
2033
}

src/Analysis/Ast/Impl/Modules/PythonModule.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ public void NotifyAnalysisComplete(IDocumentAnalysis analysis) {
438438
// as declare additional variables, etc.
439439
OnAnalysisComplete();
440440
ContentState = State.Analyzed;
441+
442+
if (ModuleType != ModuleType.User) {
443+
_buffer.Reset(_buffer.Version, string.Empty);
444+
}
441445
}
442446

443447
// Do not report issues with libraries or stubs

src/Analysis/Ast/Impl/Values/VariableCollection.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,11 @@ internal void RemoveVariable(string name) {
122122
_variables.Remove(name);
123123
}
124124
}
125+
126+
internal void Clear() {
127+
lock (_syncObj) {
128+
_variables.Clear();
129+
}
130+
}
125131
}
126132
}

src/LanguageServer/Impl/Definitions/ServerSettings.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ public class PythonAnalysisOptions {
2929
public string[] warnings { get; private set; } = Array.Empty<string>();
3030
public string[] information { get; private set; } = Array.Empty<string>();
3131
public string[] disabled { get; private set; } = Array.Empty<string>();
32+
33+
public class AnalysisMemoryOptions {
34+
/// <summary>
35+
/// Keep in memory information on local variables declared in
36+
/// functions in libraries. Provides ability to navigate to
37+
/// symbols used in function bodies in packages and libraries.
38+
/// </summary>
39+
public bool keepLibraryLocalVariables;
40+
41+
/// <summary>
42+
/// Keep in memory AST of library source code. May somewhat
43+
/// improve performance when library code has to be re-analyzed.
44+
/// </summary>
45+
public bool keepLibraryAst;
46+
}
47+
public AnalysisMemoryOptions memory;
3248
}
3349
public readonly PythonAnalysisOptions analysis = new PythonAnalysisOptions();
3450

src/LanguageServer/Impl/Implementation/Server.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ private bool HandleConfigurationChanges(ServerSettings newSettings) {
212212
return true;
213213
}
214214

215+
if(newSettings.analysis?.memory?.keepLibraryAst != oldSettings.analysis?.memory?.keepLibraryAst ||
216+
newSettings.analysis?.memory?.keepLibraryLocalVariables != oldSettings.analysis?.memory?.keepLibraryLocalVariables) {
217+
return true;
218+
}
219+
215220
return false;
216221
}
217222

src/LanguageServer/Impl/LanguageServer.Configuration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ private void HandleDiagnosticsChanges(JToken pythonSection, LanguageServerSettin
7373

7474
var linting = pythonSection["linting"];
7575
HandleLintingOnOff(_services, GetSetting(linting, "enabled", true));
76+
77+
var memory = analysis["memory"];
78+
var optionsProvider = _services.GetService<IAnalysisOptionsProvider>();
79+
optionsProvider.Options.KeepLibraryLocalVariables = GetSetting(memory, "keepLibraryLocalVariables", false);
80+
optionsProvider.Options.KeepLibraryAst = GetSetting(memory, "keepLibraryAst", false);
7681
}
7782

7883
internal static void HandleLintingOnOff(IServiceContainer services, bool linterEnabled) {

src/LanguageServer/Test/GoToDefinitionTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ def foo(self):
332332
var mainPath = TestData.GetTestSpecificUri("main.py");
333333
var doc = rdt.OpenDocument(mainPath, code);
334334

335+
var analyzer = Services.GetService<IPythonAnalyzer>();
336+
await analyzer.WaitForCompleteAnalysisAsync();
337+
335338
var analysis = await doc.GetAnalysisAsync(Timeout.Infinite);
336339
var ds = new DefinitionSource(Services);
337340

src/Parsing/Impl/Ast/PythonAst.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ public override async Task WalkAsync(PythonWalkerAsync walker, CancellationToken
9696

9797
public PythonLanguageVersion LanguageVersion { get; }
9898

99-
internal bool TryGetAttribute(Node node, object key, out object value) {
99+
public bool TryGetAttribute(Node node, object key, out object value) {
100100
if (_attributes.TryGetValue(node, out var nodeAttrs)) {
101101
return nodeAttrs.TryGetValue(key, out value);
102102
}
103103
value = null;
104104
return false;
105105
}
106106

107-
internal void SetAttribute(Node node, object key, object value) {
107+
public void SetAttribute(Node node, object key, object value) {
108108
if (!_attributes.TryGetValue(node, out var nodeAttrs)) {
109109
nodeAttrs = _attributes[node] = new Dictionary<object, object>();
110110
}

0 commit comments

Comments
 (0)