Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb6dfbb6

Browse files
authored
Reduce resident memory for VS tokenization and other caches (dotnet#4590)
* improve tokenizer memory performance* add comments* use Memory Cache with sliding window for tokeniztion information* use MemoryCache
1 parent75e435e commitb6dfbb6

File tree

14 files changed

+243
-147
lines changed

14 files changed

+243
-147
lines changed

‎src/fsharp/service/ServiceDeclarationLists.fs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ type FSharpMethodGroup( name: string, unsortedMethods: FSharpMethodGroupItem[] )
736736
// BUG 413009 : [ParameterInfo] takes about 3 seconds to move from one overload parameter to another
737737
// cache allows to avoid recomputing parameterinfo for the same item
738738
#if!FX_NO_WEAKTABLE
739-
static letmethodOverloadsCache= System.Runtime.CompilerServices.ConditionalWeakTable()
739+
static letmethodOverloadsCache= System.Runtime.CompilerServices.ConditionalWeakTable<ItemWithInst, FSharpMethodGroupItem[]>()
740740
#endif
741741

742742
letmethods=

‎src/fsharp/service/ServiceLexing.fs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ module FSharpTokenTag =
7777
letSTRUCT= tagOfToken STRUCT
7878
letCLASS= tagOfToken CLASS
7979
letTRY= tagOfToken TRY
80+
letNEW= tagOfToken NEW
81+
letWITH= tagOfToken WITH
82+
letOWITH= tagOfToken OWITH
8083

8184

8285
/// This corresponds to a token categorization originally used in Visual Studio 2003.

‎src/fsharp/service/ServiceLexing.fsi‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ module FSharpTokenTag =
182182
valCLASS:int
183183
/// Indicates the token is keyword `try`
184184
valTRY:int
185+
/// Indicates the token is keyword `with`
186+
valWITH:int
187+
/// Indicates the token is keyword `with` in #light
188+
valOWITH:int
189+
/// Indicates the token is keyword `new`
190+
valNEW:int
185191

186192
/// Information about a particular token from the tokenizer
187193
typeFSharpTokenInfo=

‎vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type internal InterfaceState =
2222
{ InterfaceData:InterfaceData
2323
EndPosOfWith:pos option
2424
AppendBracketAt:int option
25-
Tokens:FSharpTokenInfo list}
25+
Tokens:Tokenizer.SavedTokenInfo[]}
2626

2727
[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name="ImplementInterface"); Shared>]
2828
typeinternalFSharpImplementInterfaceCodeFixProvider
@@ -36,15 +36,15 @@ type internal FSharpImplementInterfaceCodeFixProvider
3636
letchecker= checkerProvider.Checker
3737
static letuserOpName="ImplementInterfaceCodeFixProvider"
3838

39-
letqueryInterfaceState appendBracketAt(pos:pos)tokens(ast:Ast.ParsedInput)=
39+
letqueryInterfaceState appendBracketAt(pos:pos)(tokens:Tokenizer.SavedTokenInfo[])(ast:Ast.ParsedInput)=
4040
asyncMaybe{
4141
letline= pos.Line-1
4242
letcolumn= pos.Column
4343
let!iface= InterfaceStubGenerator.tryFindInterfaceDeclaration pos ast
4444
letendPosOfWidth=
4545
tokens
46-
|>List.tryPick(fun(t:FSharpTokenInfo)->
47-
if t.CharClass=FSharpTokenCharKind.Keyword&& t.LeftColumn>= column&& t.TokenName="WITH"then
46+
|>Array.tryPick(fun(t:Tokenizer.SavedTokenInfo)->
47+
if t.Tag=FSharpTokenTag.WITH|| t.Tag= FSharpTokenTag.OWITHthen
4848
Some(Pos.fromZ line(t.RightColumn+1))
4949
else None)
5050
letappendBracketAt=
@@ -70,8 +70,8 @@ type internal FSharpImplementInterfaceCodeFixProvider
7070
getLineIdent lineStr+ indentSize
7171
| InterfaceData.ObjExpr_as iface->
7272
state.Tokens
73-
|>List.tryPick(fun(t:FSharpTokenInfo)->
74-
if t.CharClass=FSharpTokenCharKind.Keyword&& t.TokenName="NEW"then
73+
|>Array.tryPick(fun(t:Tokenizer.SavedTokenInfo)->
74+
if t.Tag=FSharpTokenTag.NEWthen
7575
Some(t.LeftColumn+ indentSize)
7676
else None)
7777
// There is no reference point, we indent the content at the start column of the interface
@@ -149,18 +149,18 @@ type internal FSharpImplementInterfaceCodeFixProvider
149149
// That's why we tokenize the line and try to find the last successive identifier token
150150
lettokens= Tokenizer.tokenizeLine(context.Document.Id, sourceText, context.Span.Start, context.Document.FilePath, defines)
151151
letstartLeftColumn= context.Span.Start- textLine.Start
152-
let rectryFindIdentifierToken acc tokens=
153-
match tokenswith
154-
| t:: remainingTokenswhen t.LeftColumn< startLeftColumn->
152+
let rectryFindIdentifierToken acc i=
153+
if i>= tokens.Lengththen accelse
154+
match tokens.[i]with
155+
| twhen t.LeftColumn< startLeftColumn->
155156
// Skip all the tokens starting before the context
156-
tryFindIdentifierToken acc remainingTokens
157-
| t:: remainingTokenswhen t.Tag= FSharpTokenTag.Identifier->
158-
tryFindIdentifierToken(Some t) remainingTokens
159-
| t:: remainingTokenswhen t.Tag= FSharpTokenTag.DOT|| Option.isNone acc->
160-
tryFindIdentifierToken acc remainingTokens
161-
|_::_
162-
|[]-> acc
163-
let!token= tryFindIdentifierToken None tokens
157+
tryFindIdentifierToken acc(i+1)
158+
| twhen t.Tag= FSharpTokenTag.Identifier->
159+
tryFindIdentifierToken(Some t)(i+1)
160+
| twhen t.Tag= FSharpTokenTag.DOT|| Option.isNone acc->
161+
tryFindIdentifierToken acc(i+1)
162+
|_-> acc
163+
let!token= tryFindIdentifierToken None0
164164
letfixupPosition= textLine.Start+ token.RightColumn
165165
letinterfacePos= Pos.fromZ textLine.LineNumber token.RightColumn
166166
// We rely on the observation that the lastChar of the context should be '}' if that character is present

‎vsintegration/src/FSharp.Editor/Common/Extensions.fs‎

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -147,27 +147,22 @@ module Option =
147147
else
148148
None
149149

150+
[<RequireQualifiedAccess>]
151+
moduleSeq=
152+
openSystem.Collections.Immutable
153+
154+
lettoImmutableArray(xs:seq<'a>):ImmutableArray<'a>= xs.ToImmutableArray()
150155

151156
[<RequireQualifiedAccess>]
152-
moduleList=
153-
letfoldi(folder:'State->int->'T->'State)(state:'State)(xs:'T list)=
157+
moduleArray=
158+
letfoldi(folder:'State->int->'T->'State)(state:'State)(xs:'T[])=
154159
let mutablestate= state
155160
let mutablei=0
156161
for xin xsdo
157162
state<- folder state i x
158163
i<- i+1
159164
state
160165

161-
162-
[<RequireQualifiedAccess>]
163-
moduleSeq=
164-
openSystem.Collections.Immutable
165-
166-
lettoImmutableArray(xs:seq<'a>):ImmutableArray<'a>= xs.ToImmutableArray()
167-
168-
169-
[<RequireQualifiedAccess>]
170-
moduleArray=
171166
/// Optimized arrays equality. ~100x faster than `array1 = array2` on strings.
172167
/// ~2x faster for floats
173168
/// ~0.8x slower for ints
@@ -178,12 +173,12 @@ module Array =
178173
|null,_|_,null->false
179174
|_when xs.Length<> ys.Length->false
180175
|_->
181-
let mutablebreak'=false
176+
let mutablestop=false
182177
let mutablei=0
183178
let mutableresult=true
184-
while i< xs.Length&&notbreak'do
179+
while i< xs.Length&&notstopdo
185180
if xs.[i]<> ys.[i]then
186-
break'<-true
181+
stop<-true
187182
result<-false
188183
i<- i+1
189184
result

‎vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs‎

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ open Microsoft.VisualStudio.Shell.Interop
2020
openMicrosoft.FSharp.Compiler
2121
openMicrosoft.FSharp.Compiler.Range
2222
openMicrosoft.FSharp.Compiler.SourceCodeServices
23+
openSystem.Runtime.Caching
2324

2425
typeinternalFSharpCompletionProvider
2526
(
@@ -33,7 +34,8 @@ type internal FSharpCompletionProvider
3334
inherit CompletionProvider()
3435

3536
static letuserOpName="CompletionProvider"
36-
static letdeclarationItemsCache= ConditionalWeakTable<string, FSharpDeclarationListItem>()
37+
// Save the backing data in a memory cache held in a sliding window
38+
static letdeclarationItemsCache=new MemoryCache("FSharp.Editor."+ userOpName)
3739
static let [<Literal>]NameInCodePropName="NameInCode"
3840
static let [<Literal>]FullNamePropName="FullName"
3941
static let [<Literal>]IsExtensionMemberPropName="IsExtensionMember"
@@ -138,15 +140,15 @@ type internal FSharpCompletionProvider
138140

139141
letmaxHints=if mruItems.Values.Count=0then0else Seq.max mruItems.Values
140142

141-
sortedDeclItems|> Array.iteri(fun numberdeclItem->
142-
letglyph= Tokenizer.FSharpGlyphToRoslynGlyph(declItem.Glyph,declItem.Accessibility)
143+
sortedDeclItems|> Array.iteri(fun numberdeclarationItem->
144+
letglyph= Tokenizer.FSharpGlyphToRoslynGlyph(declarationItem.Glyph,declarationItem.Accessibility)
143145
letname=
144-
matchdeclItem.NamespaceToOpenwith
145-
| Some namespaceToOpen-> sprintf"%s (open%s)"declItem.Name namespaceToOpen
146-
|_->declItem.Name
146+
matchdeclarationItem.NamespaceToOpenwith
147+
| Some namespaceToOpen-> sprintf"%s (open%s)"declarationItem.Name namespaceToOpen
148+
|_->declarationItem.Name
147149

148150
letfilterText=
149-
matchdeclItem.NamespaceToOpen,declItem.Name.Split'.'with
151+
matchdeclarationItem.NamespaceToOpen,declarationItem.Name.Split'.'with
150152
// There is no namespace to open and the item name does not contain dots, so we don't need to pass special FilterText to Roslyn.
151153
| None,[|_|]->null
152154
// Either we have a namespace to open ("DateTime (open System)") or item name contains dots ("Array.map"), or both.
@@ -155,39 +157,37 @@ type internal FSharpCompletionProvider
155157

156158
letcompletionItem=
157159
CommonCompletionItem.Create(name, glyph= Nullable glyph, rules= getRules(), filterText= filterText)
158-
.AddProperty(FullNamePropName,declItem.FullName)
160+
.AddProperty(FullNamePropName,declarationItem.FullName)
159161

160162
letcompletionItem=
161-
matchdeclItem.Kindwith
163+
matchdeclarationItem.Kindwith
162164
| CompletionItemKind.Method(isExtension=true)->
163165
completionItem.AddProperty(IsExtensionMemberPropName,"")
164166
|_-> completionItem
165167

166168
letcompletionItem=
167-
if name<>declItem.NameInCodethen
168-
completionItem.AddProperty(NameInCodePropName,declItem.NameInCode)
169+
if name<>declarationItem.NameInCodethen
170+
completionItem.AddProperty(NameInCodePropName,declarationItem.NameInCode)
169171
else completionItem
170172

171173
letcompletionItem=
172-
matchdeclItem.NamespaceToOpenwith
174+
matchdeclarationItem.NamespaceToOpenwith
173175
| Some ns-> completionItem.AddProperty(NamespaceToOpenPropName, ns)
174176
| None-> completionItem
175177

176178
letpriority=
177-
match mruItems.TryGetValuedeclItem.FullNamewith
179+
match mruItems.TryGetValuedeclarationItem.FullNamewith
178180
|true, hints-> maxHints- hints
179181
|_-> number+ maxHints+1
180182

181183
letsortText= sprintf"%06d" priority
182184

183-
//#if DEBUG
184-
//Logging.Logging.logInfof "***** %s => %s" name sortText
185-
//#endif
186-
187185
letcompletionItem= completionItem.WithSortText(sortText)
188186

189-
declarationItemsCache.Remove(completionItem.DisplayText)|> ignore// clear out stale entries if they exist
190-
declarationItemsCache.Add(completionItem.DisplayText, declItem)
187+
letkey= completionItem.DisplayText
188+
letcacheItem= CacheItem(key, declarationItem)
189+
letpolicy= CacheItemPolicy(SlidingExpiration=DefaultTuning.PerDocumentSavedDataSlidingWindow)
190+
declarationItemsCache.Set(cacheItem, policy)
191191
results.Add(completionItem))
192192

193193
if results.Count>0&&not declarations.IsForType&&not declarations.IsError&& List.isEmpty partialName.QualifyingIdentsthen
@@ -234,15 +234,15 @@ type internal FSharpCompletionProvider
234234

235235
overridethis.GetDescriptionAsync(_:Document,completionItem:Completion.CompletionItem,cancellationToken:CancellationToken):Task<CompletionDescription>=
236236
async{
237-
letexists,declarationItem=declarationItemsCache.TryGetValue(completionItem.DisplayText)
238-
if existsthen
237+
matchdeclarationItemsCache.Get(completionItem.DisplayText)with
238+
|:? FSharpDeclarationListItem as declarationItem->
239239
let!description= declarationItem.StructuredDescriptionTextAsync
240240
letdocumentation= List()
241241
letcollector= RoslynHelpers.CollectTaggedText documentation
242242
// mix main description and xmldoc by using one collector
243243
XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description)
244244
return CompletionDescription.Create(documentation.ToImmutableArray())
245-
else
245+
|_->
246246
return CompletionDescription.Empty
247247
}|> RoslynHelpers.StartAsyncAsTask cancellationToken
248248

‎vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ open Microsoft.CodeAnalysis.Diagnostics
1414
openMicrosoft.FSharp.Compiler
1515
openMicrosoft.FSharp.Compiler.Range
1616
openMicrosoft.FSharp.Compiler.SourceCodeServices
17+
openSystem.Runtime.Caching
1718

1819
typeprivateTextVersionHash= int
20+
typeprivatePerDocumentSavedData={ Hash:int; Diagnostics:ImmutableArray<Diagnostic>}
1921

2022
[<DiagnosticAnalyzer(FSharpConstants.FSharpLanguageName)>]
2123
typeinternalSimplifyNameDiagnosticAnalyzer()=
@@ -25,7 +27,7 @@ type internal SimplifyNameDiagnosticAnalyzer() =
2527
letgetProjectInfoManager(document:Document)= document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().FSharpProjectOptionsManager
2628
letgetChecker(document:Document)= document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().Checker
2729
letgetPlidLength(plid:string list)=(plid|> List.sumBy String.length)+ plid.Length
28-
static letcache=ConditionalWeakTable<DocumentId, TextVersionHash* ImmutableArray<Diagnostic>>()
30+
static letcache=new MemoryCache("FSharp.Editor."+ userOpName)
2931
// Make sure only one document is being analyzed at a time, to be nice
3032
static letguard=new SemaphoreSlim(1)
3133

@@ -54,8 +56,9 @@ type internal SimplifyNameDiagnosticAnalyzer() =
5456
lettextVersionHash= textVersion.GetHashCode()
5557
let!_= guard.WaitAsync(cancellationToken)|> Async.AwaitTask|> liftAsync
5658
try
57-
match cache.TryGetValue document.Idwith
58-
|true,(oldTextVersionHash, diagnostics)when oldTextVersionHash= textVersionHash->return diagnostics
59+
letkey= document.Id.ToString()
60+
match cache.Get(key)with
61+
|:? PerDocumentSavedData as data when data.Hash= textVersionHash-> return data.Diagnostics
5962
|_->
6063
let!sourceText= document.GetTextAsync()
6164
letchecker= getChecker document
@@ -116,8 +119,11 @@ type internal SimplifyNameDiagnosticAnalyzer() =
116119
properties=(dict[SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey, relativeName]).ToImmutableDictionary()))
117120

118121
letdiagnostics= result.ToImmutableArray()
119-
cache.Remove(document.Id)|> ignore
120-
cache.Add(document.Id,(textVersionHash, diagnostics))
122+
cache.Remove(key)|> ignore
123+
letdata={ Hash= textVersionHash; Diagnostics=diagnostics}
124+
letcacheItem= CacheItem(key, data)
125+
letpolicy= CacheItemPolicy(SlidingExpiration=DefaultTuning.PerDocumentSavedDataSlidingWindow)
126+
cache.Set(cacheItem, policy)
121127
return diagnostics
122128
finally guard.Release()|> ignore
123129
}

‎vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespaceMicrosoft.VisualStudio.FSharp.Editor
44

55
openSystem
6+
openSystem.Runtime.CompilerServices
7+
openSystem.Runtime.Caching
68
openSystem.Text.RegularExpressions
79
openInternal.Utilities.Collections
810
openEnvDTE
@@ -413,6 +415,6 @@ module internal XmlDocumentation =
413415
letBuildMethodParamText(documentationProvider,xmlCollector,xml,paramName)=
414416
AppendXmlComment(documentationProvider, TextSanitizingCollector(xmlCollector), TextSanitizingCollector(xmlCollector), xml,false,true, Some paramName)
415417

416-
letdocumentationBuilderCache=System.Runtime.CompilerServices.ConditionalWeakTable<IVsXMLMemberIndexService, IDocumentationBuilder>()
418+
letdocumentationBuilderCache= ConditionalWeakTable<IVsXMLMemberIndexService, IDocumentationBuilder>()
417419
letCreateDocumentationBuilder(xmlIndexService:IVsXMLMemberIndexService,dte:DTE)=
418420
documentationBuilderCache.GetValue(xmlIndexService,(fun _-> Provider(xmlIndexService, dte):> IDocumentationBuilder))

‎vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
<ReferenceInclude="System.ComponentModel.Composition" />
110110
<ReferenceInclude="System.Drawing" />
111111
<ReferenceInclude="System.Windows.Forms" />
112+
<ReferenceInclude="System.Runtime.Caching" />
112113
<ReferenceInclude="System.Xaml" />
113114
<ReferenceInclude="System.Xml" />
114115
<ReferenceInclude="System.Xml.Linq" />

‎vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ type internal FSharpEditorFormattingService
4444

4545
let!firstMeaningfulToken=
4646
tokens
47-
|>List.tryFind(fun x->
47+
|>Array.tryFind(fun x->
4848
x.Tag<> FSharpTokenTag.WHITESPACE&&
4949
x.Tag<> FSharpTokenTag.COMMENT&&
5050
x.Tag<> FSharpTokenTag.LINE_COMMENT)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp