/// <summary> /// Call this method to suppress expensive blocking Gen 2 garbage GCs in /// scenarios where high-latency is unacceptable (e.g. processing typing input). /// /// Blocking GCs will be re-enabled automatically after a short duration unless /// UseLowLatencyModeForProcessingUserInput is called again. /// </summary> internal static void UseLowLatencyModeForProcessingUserInput() { if (s_delayMilliseconds <= 0) { // The registry key to opt out of Roslyn's SustainedLowLatency is set, or // we haven't yet initialized the value. return; } var currentMode = GCSettings.LatencyMode; var currentDelay = s_delay; if (currentMode != GCLatencyMode.SustainedLowLatency) { GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; // Restore the LatencyMode a short duration after the // last request to UseLowLatencyModeForProcessingUserInput. currentDelay = new ResettableDelay(s_delayMilliseconds, AsynchronousOperationListenerProvider.NullListener); currentDelay.Task.SafeContinueWith(_ => RestoreGCLatencyMode(currentMode), TaskScheduler.Default); s_delay = currentDelay; } if (currentDelay != null) { currentDelay.Reset(); } }
public TaskCenterSolutionAnalysisProgressReporter( SVsTaskStatusCenterService taskStatusCenterService, IDiagnosticService diagnosticService, VisualStudioWorkspace workspace) { _lastTimeReported = DateTimeOffset.UtcNow; _resettableDelay = null; ResetProgressStatus(); _taskCenterService = (IVsTaskStatusCenterService)taskStatusCenterService; _options = new TaskHandlerOptions() { Title = ServicesVSResources.Running_low_priority_background_processes, ActionsAfterCompletion = CompletionActions.None }; var crawlerService = workspace.Services.GetService <ISolutionCrawlerService>(); var reporter = crawlerService.GetProgressReporter(workspace); StartedOrStopped(reporter.InProgress); // no event unsubscription since it will remain alive until VS shutdown reporter.ProgressChanged += OnSolutionCrawlerProgressChanged; }
private static void RestoreGCLatencyMode(GCLatencyMode originalMode) { GCSettings.LatencyMode = originalMode; s_delay = null; // hint to the GC that if it postponed a gen 2 collection, now might be a good time to do it. GC.Collect(2, GCCollectionMode.Optimized); }
private void ProgressUpdated() { // we prefer showing evaluating if progress is flipping between evaluate and pause // in short period of time. var forceUpdate = _lastShownProgressStatus == ProgressStatus.Paused && _lastProgressStatus == ProgressStatus.Evaluating; var current = DateTimeOffset.UtcNow; if (!forceUpdate && current - _lastTimeReported < s_minimumInterval) { // make sure we are not flooding UI. // this is just presentation, fine to not updating UI right away especially since // at the end, this notification will go away automatically // but to make UI to be updated to right status eventually if task takes long time to finish // we enqueue refresh task. EnqueueRefresh(); return; } _lastShownProgressStatus = _lastProgressStatus; _lastTimeReported = current; ChangeProgress(_taskHandler, GetMessage()); string GetMessage() { var statusMessage = (_lastProgressStatus == ProgressStatus.Paused) ? ServicesVSResources.Paused_0_tasks_in_queue : ServicesVSResources.Evaluating_0_tasks_in_queue; return(string.Format(statusMessage, _lastPendingItemCount)); } void EnqueueRefresh() { if (_resettableDelay != null) { _resettableDelay.Reset(); return; } _resettableDelay = new ResettableDelay((int)s_minimumInterval.TotalMilliseconds, AsynchronousOperationListenerProvider.NullListener); _resettableDelay.Task.SafeContinueWith(_ => { _resettableDelay = null; ProgressUpdated(); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } }
private void PostUpdate(Solution solution) { _delay = null; lock (_gate) { // See if each context is still alive. It's possible it's already been GC'ed meaning we should stop caring about the query _trackedQueries.RemoveAll(t => !IsTrackingContext(t.Item1)); if (_trackedQueries.IsEmpty()) { _workspace.WorkspaceChanged -= OnWorkspaceChanged; return; } } EnqueueUpdateIfSolutionIsStale(solution); }
private WorkspaceChangeTracker( RemoteEndPoint endPoint, Workspace workspace, DocumentId documentId, VersionStamp dependentVersion, CancellationToken cancellationToken) { _gate = new object(); _eventSubscribed = false; _endPoint = endPoint; _workspace = workspace; _documentId = documentId; _cancellationToken = cancellationToken; _lastVersion = dependentVersion; _resettableDelay = ResettableDelay.CompletedDelay; ConnectEvents(subscription: true); }
private void EnqueueUpdate() { const int WorkspaceUpdateDelay = 1500; var delay = _delay; if (delay == null) { var newDelay = new ResettableDelay(WorkspaceUpdateDelay, _asyncListener); if (Interlocked.CompareExchange(ref _delay, newDelay, null) == null) { var asyncToken = _asyncListener.BeginAsyncOperation("WorkspaceGraphQueryManager.EnqueueUpdate"); newDelay.Task.SafeContinueWithFromAsync(_ => UpdateAsync(), CancellationToken.None, TaskScheduler.Default) .CompletesAsyncOperation(asyncToken); } return; } delay.Reset(); }
private WorkspaceChangeTracker( CodeAnalysisService owner, Workspace workspace, DocumentId documentId, VersionStamp dependentVersion, CancellationToken cancellationToken) { _gate = new object(); _eventSubscribed = false; _owner = owner; _workspace = workspace; _documentId = documentId; _cancellationToken = cancellationToken; _lastVersion = dependentVersion; _resettableDelay = ResettableDelay.CompletedDelay; ConnectEvents(subscription: true); }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { // workspace event is serialized events. and reset delay only get updated here if (!_resettableDelay.Task.IsCompleted) { _resettableDelay.Reset(); return; } var delay = new ResettableDelay((int)s_delay.TotalMilliseconds, expeditableDelaySource: AsynchronousOperationListenerProvider.NullListener); _resettableDelay = delay; delay.Task.ContinueWith(InvalidateAsync, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); async Task InvalidateAsync(Task _) { var document = _workspace.CurrentSolution.GetDocument(_documentId); if (document == null) { return; } var newVersion = await document.Project.GetDependentVersionAsync(CancellationToken.None).ConfigureAwait(false); if (newVersion == _lastVersion) { return; } // fire and forget. // ignore any exception such as rpc already disposed (disconnected) _lastVersion = newVersion; await _endPoint.InvokeAsync( nameof(IRemoteCodeLensDataPoint.Invalidate), Array.Empty <object>(), CancellationToken.None).ConfigureAwait(false); } }
public Task <bool> IsFullyLoadedAsync(CancellationToken cancellationToken) { if (_workspace.Options.GetOption(ExperimentationOptions.SolutionStatusService_ForceDelay)) { // this is for prototype/mock for people/teams trying partial solution load prototyping // it shouldn't concern anyone outside of that group. // // "experimentationService.IsExperimentEnabled(WellKnownExperimentNames.PartialLoadMode)" check above // make sure this part of code "Service : IWorkspaceStatusService" is not exposed anyone outside of // the partial solution load group. // // for ones that is in the group, one can try lightbulb behavior through internal option page // such as moving around caret on lines where LB should show up. // // it works as below // 1. when this is first called, we return false and start timer to change its status in delayInMS // 2. once delayInMs passed, we clear the delay and return true. // 3. if it is called before the timeout, we reset the timer and return false if (_lastTimeCalled == null) { var delay = _workspace.Options.GetOption(ExperimentationOptions.SolutionStatusService_DelayInMS); _lastTimeCalled = new ResettableDelay(delayInMilliseconds: delay, AsynchronousOperationListenerProvider.NullListener); _ = _lastTimeCalled.Task.SafeContinueWith(_ => StatusChanged?.Invoke(this, true), TaskScheduler.Default); return(SpecializedTasks.False); } if (_lastTimeCalled.Task.IsCompleted) { _lastTimeCalled = null; return(SpecializedTasks.True); } _lastTimeCalled.Reset(); return(SpecializedTasks.False); } // we are using this API for now, until platform provide us new API for prototype return(KnownUIContexts.SolutionExistsAndFullyLoadedContext.IsActive ? SpecializedTasks.True : SpecializedTasks.False); }
private static void RestoreGCLatencyMode(GCLatencyMode originalMode) { GCSettings.LatencyMode = originalMode; s_delay = null; }