Skip to content

Commit 536dab5

Browse files
committed
Fix caching in background builder and add tracing to reactor queue
1 parent 96a00a9 commit 536dab5

File tree

4 files changed

+245
-183
lines changed

4 files changed

+245
-183
lines changed

src/fsharp/vs/Reactor.fs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
namespace Microsoft.FSharp.Compiler.SourceCodeServices
44
open System
5+
open System.Diagnostics
56
open Microsoft.FSharp.Control
67
open Microsoft.FSharp.Compiler.Lib
78

89
// For internal use only
910
type internal IReactorOperations =
10-
abstract EnqueueAndAwaitOpAsync : (unit -> 'T) -> Async<'T>
11-
abstract EnqueueOp: (unit -> unit) -> unit
11+
abstract EnqueueAndAwaitOpAsync : string * (unit -> 'T) -> Async<'T>
12+
abstract EnqueueOp: string * (unit -> unit) -> unit
1213

1314
module internal Reactor =
1415

@@ -23,7 +24,7 @@ module internal Reactor =
2324
/// Do a bit of work on the given build.
2425
| Step
2526
/// Do some work not synchronized in the mailbox.
26-
| Op of (unit -> unit)
27+
| Op of string * (unit -> unit)
2728
/// Stop building after finishing the current unit of work.
2829
| StopBackgroundOp of AsyncReplyChannel<ResultOrException<unit>>
2930
/// Finish building.
@@ -160,46 +161,73 @@ module internal Reactor =
160161

161162
// Async workflow which receives messages and dispatches to worker functions.
162163
let rec loop (state: ReactorState) =
163-
async { let! msg = inbox.Receive()
164+
async { Debug.WriteLine("Reactor: receiving..., remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
165+
let! msg = inbox.Receive()
164166
System.Threading.Thread.CurrentThread.CurrentUICulture <- culture
165167

166168
let newState =
167169
match msg with
168-
| StartBackgroundOp build -> HandleStartBackgroundOp inbox build state
169-
| Step -> HandleStep inbox state
170-
| Op op -> HandleOp op state
171-
| StopBackgroundOp channel -> HandleStopBackgroundOp channel state
172-
| FinishBackgroundOp channel -> HandleFinishBackgroundO inbox channel state
170+
| StartBackgroundOp build ->
171+
Debug.WriteLine("Reactor: --> start background, remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
172+
HandleStartBackgroundOp inbox build state
173+
| Step ->
174+
Debug.WriteLine("Reactor: --> background step, remaining {0}, mem {1}, gc2 {2}}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
175+
let time = System.DateTime.Now
176+
let res = HandleStep inbox state
177+
let span = System.DateTime.Now - time
178+
//if span.TotalMilliseconds > 100.0 then
179+
Debug.WriteLine("Reactor: <-- background step, remaining {0}, took {1}ms", inbox.CurrentQueueLength, span.TotalMilliseconds)
180+
res
181+
| Op (desc, op) ->
182+
Debug.WriteLine("Reactor: --> {0}, remaining {1}, mem {2}, gc2 {3}", desc, inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
183+
let time = System.DateTime.Now
184+
let res = HandleOp op state
185+
let span = System.DateTime.Now - time
186+
//if span.TotalMilliseconds > 100.0 then
187+
Debug.WriteLine("Reactor: <-- {0}, remaining {1}, took {2}ms", desc, inbox.CurrentQueueLength, span.TotalMilliseconds)
188+
res
189+
190+
| StopBackgroundOp channel ->
191+
Debug.WriteLine("Reactor: --> stop background, remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
192+
HandleStopBackgroundOp channel state
193+
| FinishBackgroundOp channel ->
194+
Debug.WriteLine("Reactor: --> finish background, remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
195+
HandleFinishBackgroundO inbox channel state
173196

174197
return! loop newState
175198
}
176199
loop Idling
177200

178201

179202
// [Foreground Mailbox Accessors] -----------------------------------------------------------
180-
member r.StartBackgroundOp(build) = builder.Post(StartBackgroundOp build)
203+
member r.StartBackgroundOp(build) =
204+
Debug.WriteLine("Reactor: enqueue start background, length {0}", builder.CurrentQueueLength)
205+
builder.Post(StartBackgroundOp build)
181206

182207
member r.StopBackgroundOp() =
208+
Debug.WriteLine("Reactor: enqueue stop background, length {0}", builder.CurrentQueueLength)
183209
match builder.PostAndReply(fun replyChannel->StopBackgroundOp(replyChannel)) with
184210
| Result result->result
185211
| Exception excn->
186212
raise excn
187213

188-
member r.EnqueueOp(op) =
189-
builder.Post(Op(op))
214+
member r.EnqueueOp(desc, op) =
215+
Debug.WriteLine("Reactor: enqueue {0}, length {1}", desc, builder.CurrentQueueLength)
216+
builder.Post(Op(desc, op))
190217

191218
member r.CurrentQueueLength =
192219
builder.CurrentQueueLength
193220

194221
// This is for testing only
195222
member r.WaitForBackgroundOpCompletion() =
223+
Debug.WriteLine("Reactor: enqueue wait for background, length {0}", builder.CurrentQueueLength)
196224
match builder.PostAndReply(fun replyChannel->FinishBackgroundOp(replyChannel)) with
197225
| Result result->result
198226
| Exception excn->raise excn
199227

200-
member r.EnqueueAndAwaitOpAsync f =
228+
member r.EnqueueAndAwaitOpAsync (desc, f) =
201229
let resultCell = AsyncUtil.AsyncResultCell<_>()
202-
r.EnqueueOp(
230+
r.EnqueueOp(desc,
203231
fun () ->
204232
let result =
205233
try

src/fsharp/vs/Reactor.fsi

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ namespace Microsoft.FSharp.Compiler.SourceCodeServices
66
type internal IReactorOperations =
77

88
/// Put the operation in thq queue, and return an async handle to its result.
9-
abstract EnqueueAndAwaitOpAsync : (unit -> 'T) -> Async<'T>
9+
abstract EnqueueAndAwaitOpAsync : description: string * action: (unit -> 'T) -> Async<'T>
1010

1111
/// Enqueue an operation and return immediately.
12-
abstract EnqueueOp: (unit -> unit) -> unit
12+
abstract EnqueueOp: description: string * action: (unit -> unit) -> unit
1313

1414
/// Reactor is intended for long-running but interruptible operations, interleaved
1515
/// with one-off asynchronous operations.
@@ -33,7 +33,7 @@ module internal Reactor =
3333
member WaitForBackgroundOpCompletion : unit -> unit
3434

3535
/// Enqueue an operation and return immediately.
36-
member EnqueueOp : op:(unit -> unit) -> unit
36+
member EnqueueOp : description: string * op:(unit -> unit) -> unit
3737

3838
/// For debug purposes
3939
member CurrentQueueLength : int
@@ -43,7 +43,7 @@ module internal Reactor =
4343
// operation which can be halted part way through.
4444

4545
/// Put the operation in thq queue, and return an async handle to its result.
46-
member EnqueueAndAwaitOpAsync : (unit -> 'T) -> Async<'T>
46+
member EnqueueAndAwaitOpAsync : description: string * (unit -> 'T) -> Async<'T>
4747

4848
/// Get the reactor for FSharp.Compiler.dll
4949
val Reactor : unit -> Reactor

src/fsharp/vs/ServiceDeclarations.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1281,7 +1281,7 @@ type FSharpDeclarationListItem(name, glyph:int, info) =
12811281
match info with
12821282
| Choice1Of2 (items, infoReader, m, denv, reactor:IReactorOperations, checkAlive) ->
12831283
// reactor causes the lambda to execute on the background compiler thread, through the Reactor
1284-
reactor.EnqueueAndAwaitOpAsync (fun () ->
1284+
reactor.EnqueueAndAwaitOpAsync ("DescriptionTextAsync", fun () ->
12851285
// This is where we do some work which may touch TAST data structures owned by the IncrementalBuilder - infoReader, item etc.
12861286
// It is written to be robust to a disposal of an IncrementalBuilder, in which case it will just return the empty string.
12871287
// It is best to think of this as a "weak reference" to the IncrementalBuilder, i.e. this code is written to be robust to its

0 commit comments

Comments
 (0)