Skip to content

Commit 9087936

Browse files
committed
add pause before background work
1 parent 9656fb9 commit 9087936

File tree

6 files changed

+38
-28
lines changed

6 files changed

+38
-28
lines changed

docs/content/queue.fsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ sequentially and in order.
1111
1212
The thread processing these requests can also run a low-priority, interleaved background operation when the
1313
queue is empty. This can be used to implicitly bring the background check of a project "up-to-date".
14-
When the operations queue is empty this background work is run in small incremental fragments.
15-
This work is cooperatively time-sliced to be approximately <50ms, (see `maxTimeShareMilliseconds` in
14+
When the operations queue has been empty for 1 second ,
15+
this background work is run in small incremental fragments. This work is cooperatively time-sliced to be approximately <50ms, (see `maxTimeShareMilliseconds` in
1616
IncrementalBuild.fs). The project to be checked in the background is set implicitly
1717
by calls to ``CheckFileInProject`` and ``ParseAndCheckFileInProject``.
1818
To disable implicit background checking completely, set ``checker.ImplicitlyStartBackgroundWork`` to false.
19+
To change the time before background work starts, set ``checker.PauseBeforeBackgroundWork`` to the required number of milliseconds.
1920
2021
Most calls to the FSharpChecker API enqueue an operation in the FSharpChecker compiler queue. These correspond to the
2122
calls to EnqueueAndAwaitOpAsync in [service.fs](https://github.com/fsharp/FSharp.Compiler.Service/blob/master/src/fsharp/vs/service.fs).

src/fsharp/vs/IncrementalBuild.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ module internal IncrementalFSharpBuild =
10801080
#if SILVERLIGHT
10811081
50L
10821082
#else
1083-
match System.Environment.GetEnvironmentVariable("mFSharp_MaxTimeShare") with
1083+
match System.Environment.GetEnvironmentVariable("FCS_MaxTimeShare") with
10841084
| null | "" -> 50L
10851085
| s -> int64 s
10861086
#endif

src/fsharp/vs/Reactor.fs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ module internal Reactor =
3030
/// There is one global Reactor for the entire language service, no matter how many projects or files
3131
/// are open.
3232
type Reactor() =
33+
static let GetEnvInteger e dflt = match System.Environment.GetEnvironmentVariable(e) with null -> dflt | t -> try int t with _ -> dflt
34+
static let pauseBeforeBackgroundWorkDefault = GetEnvInteger "FCS_PauseBeforeBackgroundWorkMilliseconds" 1000
35+
let mutable pauseBeforeBackgroundWork = pauseBeforeBackgroundWorkDefault
36+
3337
// We need to store the culture for the VS thread that is executing now,
3438
// so that when the reactor picks up a thread from the threadpool we can set the culture
3539
let culture = new CultureInfo(Thread.CurrentThread.CurrentUICulture.LCID)
@@ -38,22 +42,27 @@ module internal Reactor =
3842
let builder =
3943
MailboxProcessor<_>.Start <| fun inbox ->
4044

41-
4245
// Async workflow which receives messages and dispatches to worker functions.
43-
let rec loop (bgOpOpt, onComplete) =
46+
let rec loop (bgOpOpt, onComplete, bg) =
4447
async { Debug.WriteLine("Reactor: receiving..., remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
4548

4649
// Messages always have priority over the background op.
4750
let! msg =
4851
async { match bgOpOpt, onComplete with
49-
| None, None -> let! msg = inbox.Receive() in return Some msg
50-
| _ -> return! inbox.TryReceive(0) }
52+
| None, None ->
53+
let! msg = inbox.Receive()
54+
return Some msg
55+
| _, Some _ ->
56+
return! inbox.TryReceive(0)
57+
| Some _, _ ->
58+
let timeout = (if bg then 0 else pauseBeforeBackgroundWork)
59+
return! inbox.TryReceive(timeout) }
5160
Thread.CurrentThread.CurrentUICulture <- culture
5261

5362
match msg with
5463
| Some (SetBackgroundOp bgOpOpt) ->
5564
Debug.WriteLine("Reactor: --> set background op, remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
56-
return! loop (bgOpOpt, onComplete)
65+
return! loop (bgOpOpt, onComplete, false)
5766
| Some (Op (desc, ct, op, ccont)) ->
5867
if ct.IsCancellationRequested then ccont() else
5968
Debug.WriteLine("Reactor: --> {0}, remaining {1}, mem {2}, gc2 {3}", desc, inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
@@ -62,17 +71,17 @@ module internal Reactor =
6271
let span = System.DateTime.Now - time
6372
//if span.TotalMilliseconds > 100.0 then
6473
Debug.WriteLine("Reactor: <-- {0}, remaining {1}, took {2}ms", desc, inbox.CurrentQueueLength, span.TotalMilliseconds)
65-
return! loop (bgOpOpt, onComplete)
74+
return! loop (bgOpOpt, onComplete, false)
6675
| Some (WaitForBackgroundOpCompletion channel) ->
6776
Debug.WriteLine("Reactor: --> wait for background (debug only), remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
6877
match bgOpOpt with
6978
| None -> ()
7079
| Some bgOp -> while bgOp() do ()
7180
channel.Reply(())
72-
return! loop (None, onComplete)
81+
return! loop (None, onComplete, false)
7382
| Some (CompleteAllQueuedOps channel) ->
7483
Debug.WriteLine("Reactor: --> stop background work and complete all queued ops, remaining {0}, mem {1}, gc2 {2}", inbox.CurrentQueueLength, GC.GetTotalMemory(false)/1000000L, GC.CollectionCount(2))
75-
return! loop (None, Some channel)
84+
return! loop (None, Some channel, false)
7685
| None ->
7786
match bgOpOpt, onComplete with
7887
| _, Some onComplete -> onComplete.Reply()
@@ -83,13 +92,13 @@ module internal Reactor =
8392
let span = System.DateTime.Now - time
8493
//if span.TotalMilliseconds > 100.0 then
8594
Debug.WriteLine("Reactor: <-- background step, remaining {0}, took {1}ms", inbox.CurrentQueueLength, span.TotalMilliseconds)
86-
return! loop ((if res then Some bgOp else None), onComplete)
95+
return! loop ((if res then Some bgOp else None), onComplete, true)
8796
| None, None -> failwith "unreachable, should have used inbox.Receive"
8897
}
8998
async {
9099
while true do
91100
try
92-
do! loop (None, None)
101+
do! loop (None, None, false)
93102
with e ->
94103
Debug.Assert(false,String.Format("unexpected failure in reactor loop {0}, restarting", e))
95104
}
@@ -138,6 +147,7 @@ module internal Reactor =
138147
)
139148
return! resultCell.AsyncResult
140149
}
150+
member __.PauseBeforeBackgroundWork with get() = pauseBeforeBackgroundWork and set v = pauseBeforeBackgroundWork <- v
141151

142152
let theReactor = Reactor()
143153
let Reactor() = theReactor

src/fsharp/vs/Reactor.fsi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ module internal Reactor =
4343
/// Put the operation in the queue, and return an async handle to its result.
4444
member EnqueueAndAwaitOpAsync : description: string * (CancellationToken -> 'T) -> Async<'T>
4545

46+
member PauseBeforeBackgroundWork : int with get, set
47+
4648
/// Get the reactor for FSharp.Compiler.dll
4749
val Reactor : unit -> Reactor
4850

src/fsharp/vs/ServiceDeclarations.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ module EnvMisc2 =
4040
#else
4141
let GetEnvInteger e dflt = match System.Environment.GetEnvironmentVariable(e) with null -> dflt | t -> try int t with _ -> dflt
4242
#endif
43-
let maxMembers = GetEnvInteger "mFSharp_MaxMembersInQuickInfo" 10
43+
let maxMembers = GetEnvInteger "FCS_MaxMembersInQuickInfo" 10
4444

4545
/// dataTipSpinWaitTime limits how long we block the UI thread while a tooltip pops up next to a selected item in an IntelliSense completion list.
4646
/// This time appears to be somewhat amortized by the time it takes the VS completion UI to actually bring up the tooltip after selecting an item in the first place.
47-
let dataTipSpinWaitTime = GetEnvInteger "mFSharp_ToolTipSpinWaitTime" 300
47+
let dataTipSpinWaitTime = GetEnvInteger "FCS_ToolTipSpinWaitTime" 300
4848

4949
//----------------------------------------------------------------------------
5050
// Display characteristics of typechecking items

src/fsharp/vs/service.fs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,17 @@ open ItemDescriptionsImpl
4949

5050
[<AutoOpen>]
5151
module EnvMisc =
52-
#if SILVERLIGHT
53-
let GetEnvInteger e dflt = dflt
54-
#else
5552
let GetEnvInteger e dflt = match System.Environment.GetEnvironmentVariable(e) with null -> dflt | t -> try int t with _ -> dflt
56-
#endif
57-
let getToolTipTextSize = GetEnvInteger "mFSharp_RecentForegroundTypeCheckCacheSize" 5
58-
let maxTypeCheckErrorsOutOfProjectContext = GetEnvInteger "mFSharp_MaxErrorsOutOfProjectContext" 3
59-
let braceMatchCacheSize = GetEnvInteger "mFSharp_BraceMatchCacheSize" 5
60-
let parseFileInProjectCacheSize = GetEnvInteger "mFSharp_ParseFileInProjectCacheSize" 2
61-
let incrementalTypeCheckCacheSize = GetEnvInteger "mFSharp_IncrementalTypeCheckCacheSize" 5
53+
let getToolTipTextSize = GetEnvInteger "FCS_RecentForegroundTypeCheckCacheSize" 5
54+
let maxTypeCheckErrorsOutOfProjectContext = GetEnvInteger "FCS_MaxErrorsOutOfProjectContext" 3
55+
let braceMatchCacheSize = GetEnvInteger "FCS_BraceMatchCacheSize" 5
56+
let parseFileInProjectCacheSize = GetEnvInteger "FCS_ParseFileInProjectCacheSize" 2
57+
let incrementalTypeCheckCacheSize = GetEnvInteger "FCS_IncrementalTypeCheckCacheSize" 5
6258

63-
let projectCacheSizeDefault = GetEnvInteger "mFSharp_ProjectCacheSizeDefault" 3
64-
let frameworkTcImportsCacheStrongSize = GetEnvInteger "mFSharp_frameworkTcImportsCacheStrongSizeDefault" 8
65-
let maxMBDefault = GetEnvInteger "mFSharp_maxMB" 1000000 // a million MB = 1TB = disabled
66-
//let maxMBDefault = GetEnvInteger "mFSharp_maxMB" (if sizeof<int> = 4 then 1700 else 3400)
59+
let projectCacheSizeDefault = GetEnvInteger "FCS_ProjectCacheSizeDefault" 3
60+
let frameworkTcImportsCacheStrongSize = GetEnvInteger "FCS_frameworkTcImportsCacheStrongSizeDefault" 8
61+
let maxMBDefault = GetEnvInteger "FCS_MaxMB" 1000000 // a million MB = 1TB = disabled
62+
//let maxMBDefault = GetEnvInteger "FCS_maxMB" (if sizeof<int> = 4 then 1700 else 3400)
6763

6864
//----------------------------------------------------------------------------
6965
// Methods
@@ -2663,6 +2659,7 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
26632659

26642660
member __.FrameworkImportsCache = frameworkTcImportsCache
26652661
member __.ImplicitlyStartBackgroundWork with get() = implicitlyStartBackgroundWork and set v = implicitlyStartBackgroundWork <- v
2662+
member __.PauseBeforeBackgroundWork with get() = Reactor.Reactor().PauseBeforeBackgroundWork and set v = Reactor.Reactor().PauseBeforeBackgroundWork <- v
26662663
static member GlobalForegroundParseCountStatistic = foregroundParseCount
26672664
static member GlobalForegroundTypeCheckCountStatistic = foregroundTypeCheckCount
26682665

0 commit comments

Comments
 (0)