diff --git a/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs b/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs index d99a98d12116880bb603f2ad98dc85b5fe2d6ce4..c6cdfe76b04f8b69d44137ba2ba11913793fa59e 100644 --- a/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs +++ b/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs @@ -31,7 +31,7 @@ public async void Register(Workspace workspace) { try { - var workerBackOffTimeSpanInMS = workspace.Options.GetOption(SolutionCrawlerOptions.PreviewBackOffTimeSpanInMS); + var workerBackOffTimeSpanInMS = workspace.Options.GetOption(InternalSolutionCrawlerOptions.PreviewBackOffTimeSpanInMS); var analyzer = _provider.CreateIncrementalAnalyzer(workspace); var source = s_cancellationTokens.GetValue(workspace, _ => new CancellationTokenSource()); diff --git a/src/EditorFeatures/Test/MinimalTestExportProvider.cs b/src/EditorFeatures/Test/MinimalTestExportProvider.cs index 3eba02338ca53ca66c06e60a5acbb02c6edca10c..2f22d27cc5dccb08b726f608b64d43d6473395be 100644 --- a/src/EditorFeatures/Test/MinimalTestExportProvider.cs +++ b/src/EditorFeatures/Test/MinimalTestExportProvider.cs @@ -56,7 +56,7 @@ public static Type[] GetLanguageNeutralTypes() typeof(TestExportProvider) }; - return types.Concat(TestHelpers.GetAllTypesWithStaticFieldsImplementingType(typeof(SolutionCrawlerOptions).Assembly, typeof(Microsoft.CodeAnalysis.Options.IOption))) + return types.Concat(TestHelpers.GetAllTypesWithStaticFieldsImplementingType(typeof(InternalSolutionCrawlerOptions).Assembly, typeof(Microsoft.CodeAnalysis.Options.IOption))) .Concat(TestHelpers.GetAllTypesWithStaticFieldsImplementingType(typeof(EditorComponentOnOffOptions).Assembly, typeof(Microsoft.CodeAnalysis.Options.IOption))) .Concat(TestHelpers.GetAllTypesWithStaticFieldsImplementingType(typeof(ServiceComponentOnOffOptions).Assembly, typeof(Microsoft.CodeAnalysis.Options.IOption))) .Concat(TestHelpers.GetAllTypesWithStaticFieldsImplementingType(typeof(Microsoft.CodeAnalysis.Formatting.FormattingOptions).Assembly, typeof(Microsoft.CodeAnalysis.Options.IOption))) diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs index f057c9ee07cfa4099e7a5e3606a664cd89ec7aad..a2526b9fbe2763201322f95af6a4e51a0f1830dd 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs @@ -458,6 +458,8 @@ public async Task ReanalyzeAllDocumentsAsync(Project project, CancellationToken { foreach (var document in project.Documents) { + cancellationToken.ThrowIfCancellationRequested(); + await AppendDiagnosticsAsync(document, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Features.csproj b/src/Features/Core/Features.csproj index 406707ae0e2e560d203f8216898c97071ff51508..eb93e9ada32f5f6a72dfa77acb4cea09a0c4dfb0 100644 --- a/src/Features/Core/Features.csproj +++ b/src/Features/Core/Features.csproj @@ -508,7 +508,7 @@ - + diff --git a/src/Features/Core/SolutionCrawler/IdleProcessor.cs b/src/Features/Core/SolutionCrawler/IdleProcessor.cs index be7ae42f1e46557b0e177b8d208c6ba067dc9ca8..084f4f1b1ec18d777a22170acdfac1142766a58e 100644 --- a/src/Features/Core/SolutionCrawler/IdleProcessor.cs +++ b/src/Features/Core/SolutionCrawler/IdleProcessor.cs @@ -51,6 +51,27 @@ protected void UpdateLastAccessTime() _lastAccessTimeInMS = Environment.TickCount; } + protected async Task WaitForIdleAsync() + { + while (true) + { + if (this.CancellationToken.IsCancellationRequested) + { + return; + } + + var diffInMS = Environment.TickCount - _lastAccessTimeInMS; + if (diffInMS >= _backOffTimeSpanInMS) + { + return; + } + + // TODO: will safestart/unwarp capture cancellation exception? + var timeLeft = _backOffTimeSpanInMS - diffInMS; + await Task.Delay(Math.Max(MinimumDelayInMS, timeLeft), this.CancellationToken).ConfigureAwait(continueOnCapturedContext: false); + } + } + private async Task ProcessAsync() { while (true) @@ -80,27 +101,6 @@ private async Task ProcessAsync() } } - private async Task WaitForIdleAsync() - { - while (true) - { - if (this.CancellationToken.IsCancellationRequested) - { - return; - } - - var diffInMS = Environment.TickCount - _lastAccessTimeInMS; - if (diffInMS >= _backOffTimeSpanInMS) - { - return; - } - - // TODO: will safestart/unwarp capture cancellation exception? - var timeLeft = _backOffTimeSpanInMS - diffInMS; - await Task.Delay(Math.Max(MinimumDelayInMS, timeLeft), this.CancellationToken).ConfigureAwait(continueOnCapturedContext: false); - } - } - public virtual Task AsyncProcessorTask { get diff --git a/src/Features/Core/SolutionCrawler/SolutionCrawlerOptions.cs b/src/Features/Core/SolutionCrawler/InternalSolutionCrawlerOptions.cs similarity index 55% rename from src/Features/Core/SolutionCrawler/SolutionCrawlerOptions.cs rename to src/Features/Core/SolutionCrawler/InternalSolutionCrawlerOptions.cs index f559cfb3cfef2b51828b0d494398e63c31fbf730..2ae33a367059ef13d03a0fcb068ebe4c95210c2a 100644 --- a/src/Features/Core/SolutionCrawler/SolutionCrawlerOptions.cs +++ b/src/Features/Core/SolutionCrawler/InternalSolutionCrawlerOptions.cs @@ -4,27 +4,29 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler { - internal static class SolutionCrawlerOptions + internal static class InternalSolutionCrawlerOptions { + public const string OptionName = "SolutionCrawler"; + [ExportOption] public static readonly Option SolutionCrawler = new Option("FeatureManager/Components", "Solution Crawler", defaultValue: true); [ExportOption] - public static readonly Option ActiveFileWorkerBackOffTimeSpanInMS = new Option("SolutionCrawler", "Active file worker backoff timespan in ms", defaultValue: 200); + public static readonly Option ActiveFileWorkerBackOffTimeSpanInMS = new Option(OptionName, "Active file worker backoff timespan in ms", defaultValue: 200); [ExportOption] - public static readonly Option AllFilesWorkerBackOffTimeSpanInMS = new Option("SolutionCrawler", "All files worker backoff timespan in ms", defaultValue: 1500); + public static readonly Option AllFilesWorkerBackOffTimeSpanInMS = new Option(OptionName, "All files worker backoff timespan in ms", defaultValue: 1500); [ExportOption] - public static readonly Option EntireProjectWorkerBackOffTimeSpanInMS = new Option("SolutionCrawler", "Entire project analysis worker backoff timespan in ms", defaultValue: 5000); + public static readonly Option EntireProjectWorkerBackOffTimeSpanInMS = new Option(OptionName, "Entire project analysis worker backoff timespan in ms", defaultValue: 5000); [ExportOption] - public static readonly Option SemanticChangeBackOffTimeSpanInMS = new Option("SolutionCrawler", "Semantic change backoff timespan in ms", defaultValue: 100); + public static readonly Option SemanticChangeBackOffTimeSpanInMS = new Option(OptionName, "Semantic change backoff timespan in ms", defaultValue: 100); [ExportOption] - public static readonly Option ProjectPropagationBackOffTimeSpanInMS = new Option("SolutionCrawler", "Project propagation backoff timespan in ms", defaultValue: 500); + public static readonly Option ProjectPropagationBackOffTimeSpanInMS = new Option(OptionName, "Project propagation backoff timespan in ms", defaultValue: 500); [ExportOption] - public static readonly Option PreviewBackOffTimeSpanInMS = new Option("SolutionCrawler", "Preview backoff timespan in ms", defaultValue: 500); + public static readonly Option PreviewBackOffTimeSpanInMS = new Option(OptionName, "Preview backoff timespan in ms", defaultValue: 500); } } diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncDocumentWorkItemQueue.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncDocumentWorkItemQueue.cs index 7c571643ab839c1ab03a8f35e330cc345e843955..772e19a3a3c828340cb11d1352e8b529488fdbe1 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncDocumentWorkItemQueue.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncDocumentWorkItemQueue.cs @@ -50,7 +50,7 @@ protected override bool TryTake_NoLock(DocumentId key, out WorkItem workInfo) return false; } - protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, out WorkItem workItem) + protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, ProjectDependencyGraph dependencyGraph, out WorkItem workItem) { // there must be at least one item in the map when this is called unless host is shutting down. if (_documentWorkQueue.Count == 0) @@ -59,7 +59,7 @@ protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, out return false; } - var documentId = GetBestDocumentId_NoLock(preferableProjectId); + var documentId = GetBestDocumentId_NoLock(preferableProjectId, dependencyGraph); if (TryTake_NoLock(documentId, out workItem)) { return true; @@ -68,18 +68,9 @@ protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, out return Contract.FailWithReturn("how?"); } - private DocumentId GetBestDocumentId_NoLock(ProjectId preferableProjectId) + private DocumentId GetBestDocumentId_NoLock(ProjectId preferableProjectId, ProjectDependencyGraph dependencyGraph) { - var projectId = preferableProjectId; - if (projectId == null || !_documentWorkQueue.ContainsKey(projectId)) - { - // explicitly iterate so that we can use struct enumerator - foreach (var pair in _documentWorkQueue) - { - projectId = pair.Key; - break; - } - } + var projectId = GetBestProjectId_NoLock(preferableProjectId, dependencyGraph); var documentMap = _documentWorkQueue[projectId]; @@ -104,6 +95,35 @@ private DocumentId GetBestDocumentId_NoLock(ProjectId preferableProjectId) return lowPriorityDocumentId; } + private ProjectId GetBestProjectId_NoLock(ProjectId projectId, ProjectDependencyGraph dependencyGraph) + { + if (projectId != null) + { + if (_documentWorkQueue.ContainsKey(projectId)) + { + return projectId; + } + + // see if there is any project that depends on this project has work item queued. if there is any, use that project + // as next project to process + foreach (var dependingProjectId in dependencyGraph.GetProjectsThatDirectlyDependOnThisProject(projectId)) + { + if (_documentWorkQueue.ContainsKey(dependingProjectId)) + { + return dependingProjectId; + } + } + } + + // explicitly iterate so that we can use struct enumerator + foreach (var pair in _documentWorkQueue) + { + return pair.Key; + } + + return Contract.FailWithReturn("Shouldn't reach here"); + } + protected override bool AddOrReplace_NoLock(WorkItem item) { // now document work diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncProjectWorkItemQueue.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncProjectWorkItemQueue.cs index 8f81ac09930bda434b3389443ea952818b3b93b8..6b2f5ae5447921a8614557cefe7fe901fe2dd7c2 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncProjectWorkItemQueue.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncProjectWorkItemQueue.cs @@ -49,7 +49,7 @@ protected override bool TryTake_NoLock(ProjectId key, out WorkItem workInfo) return _projectWorkQueue.Remove(key); } - protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, out WorkItem workItem) + protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, ProjectDependencyGraph dependencyGraph, out WorkItem workItem) { if (preferableProjectId != null) { @@ -57,6 +57,14 @@ protected override bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, out { return true; } + + foreach (var dependingProjectId in dependencyGraph.GetProjectsThatDirectlyDependOnThisProject(preferableProjectId)) + { + if (TryTake_NoLock(dependingProjectId, out workItem)) + { + return true; + } + } } // explicitly iterate so that we can use struct enumerator diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs index 0567e0022a975fed9d0b53addc934decc4f8c1b1..e0138bf04dea903f75e7cf39c3fa6267bed6ac7e 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs @@ -39,7 +39,7 @@ public AsyncWorkItemQueue(SolutionCrawlerProgressReporter progressReporter) protected abstract bool TryTake_NoLock(TKey key, out WorkItem workInfo); - protected abstract bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, out WorkItem workItem); + protected abstract bool TryTakeAnyWork_NoLock(ProjectId preferableProjectId, ProjectDependencyGraph dependencyGraph, out WorkItem workItem); public bool HasAnyWork { @@ -52,17 +52,6 @@ public bool HasAnyWork } } - public int WorkItemCount - { - get - { - lock (_gate) - { - return WorkItemCount_NoLock; - } - } - } - public void RemoveCancellationSource(object key) { lock (_gate) @@ -198,12 +187,12 @@ public bool TryTake(TKey key, out WorkItem workInfo, out CancellationTokenSource } } - public bool TryTakeAnyWork(ProjectId preferableProjectId, out WorkItem workItem, out CancellationTokenSource source) + public bool TryTakeAnyWork(ProjectId preferableProjectId, ProjectDependencyGraph dependencyGraph, out WorkItem workItem, out CancellationTokenSource source) { lock (_gate) { // there must be at least one item in the map when this is called unless host is shutting down. - if (TryTakeAnyWork_NoLock(preferableProjectId, out workItem)) + if (TryTakeAnyWork_NoLock(preferableProjectId, dependencyGraph, out workItem)) { if (!HasAnyWork_NoLock) { diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.GlobalOperationAwareIdleProcessor.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.GlobalOperationAwareIdleProcessor.cs index 7cc539b5c64fa6b91aeeb7ab4a99855a4da817fa..115d4832d2865d9b935193693184c004117a342a 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.GlobalOperationAwareIdleProcessor.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.GlobalOperationAwareIdleProcessor.cs @@ -45,6 +45,14 @@ private abstract class GlobalOperationAwareIdleProcessor : IdleProcessor _globalOperationNotificationService.Stopped += OnGlobalOperationStopped; } + protected Task GlobalOperationTask + { + get + { + return _globalOperationTask; + } + } + protected abstract void PauseOnGlobalOperation(); private void OnGlobalOperationStarted(object sender, EventArgs e) @@ -76,10 +84,30 @@ private void OnGlobalOperationStopped(object sender, GlobalOperationEventArgs e) _globalOperationTask = SpecializedTasks.EmptyTask; } - protected async Task GlobalOperationWaitAsync() + protected abstract Task HigherQueueOperationTask { get; } + protected abstract bool HigherQueueHasWorkItem { get; } + + protected async Task WaitForHigherPriorityOperationsAsync() { - // we wait for global operation if there is anything going on - await _globalOperationTask.ConfigureAwait(false); + do + { + // we wait for global operation and higher queue operation if there is anything going on + if (!this.GlobalOperationTask.IsCompleted || !this.HigherQueueOperationTask.IsCompleted) + { + await Task.WhenAll(this.GlobalOperationTask, this.HigherQueueOperationTask).ConfigureAwait(false); + } + + // if there are no more work left for higher queue, then it is our time to go ahead + if (!HigherQueueHasWorkItem) + { + break; + } + + // back off and wait for next time slot. + this.UpdateLastAccessTime(); + await this.WaitForIdleAsync().ConfigureAwait(false); + } + while (true); } public virtual void Shutdown() diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs index 2d7f07cbffc777ddb100eb38fe1a31dc59fcc814..621e2ecdf9e0f66898710f7c2ffcac0c5a575129 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs @@ -59,6 +59,14 @@ public Task Running } } + public bool HasAnyWork + { + get + { + return _workItemQueue.HasAnyWork; + } + } + public void Enqueue(WorkItem item) { Contract.ThrowIfFalse(item.DocumentId != null, "can only enqueue a document work item"); @@ -134,6 +142,7 @@ protected override async Task ExecuteAsync() private bool GetNextWorkItem(out WorkItem workItem, out CancellationTokenSource documentCancellation) { + // GetNextWorkItem since it can't fail. we still return bool to confirm that this never fail. var documentId = _processor._documentTracker.GetActiveDocument(); if (documentId != null) { @@ -143,7 +152,11 @@ private bool GetNextWorkItem(out WorkItem workItem, out CancellationTokenSource } } - return _workItemQueue.TryTakeAnyWork(preferableProjectId: null, workItem: out workItem, source: out documentCancellation); + return _workItemQueue.TryTakeAnyWork( + preferableProjectId: null, + dependencyGraph: this._processor.DependencyGraph, + workItem: out workItem, + source: out documentCancellation); } private async Task ProcessDocumentAsync(Solution solution, ImmutableArray analyzers, WorkItem workItem, CancellationTokenSource source) diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs index 4108712287a10bd3ee3ec446ff821ad42e8bea72..5036b5dd47337fe78df926e890cb61e31a164047 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs @@ -143,6 +143,14 @@ private Solution CurrentSolution } } + private ProjectDependencyGraph DependencyGraph + { + get + { + return CurrentSolution.GetProjectDependencyGraph(); + } + } + private IEnumerable GetOpenDocumentIds() { return _registration.Workspace.GetOpenDocumentIds(); diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs index e989c6ce3852209dc853dc55b52e154be4d94537..2ca9a92ad72b85973c81c39ad007f0b50339fb2b 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs @@ -57,15 +57,12 @@ protected override async Task ExecuteAsync() try { // we wait for global operation, higher and normal priority processor to finish its working - await Task.WhenAll( - this.Processor._highPriorityProcessor.Running, - this.Processor._normalPriorityProcessor.Running, - GlobalOperationWaitAsync()).ConfigureAwait(false); + await WaitForHigherPriorityOperationsAsync().ConfigureAwait(false); // process any available project work, preferring the active project. WorkItem workItem; CancellationTokenSource projectCancellation; - if (_workItemQueue.TryTakeAnyWork(this.Processor.GetActiveProject(), out workItem, out projectCancellation)) + if (_workItemQueue.TryTakeAnyWork(this.Processor.GetActiveProject(), this.Processor.DependencyGraph, out workItem, out projectCancellation)) { await ProcessProjectAsync(this.Analyzers, workItem, projectCancellation).ConfigureAwait(false); } @@ -76,6 +73,22 @@ protected override async Task ExecuteAsync() } } + protected override Task HigherQueueOperationTask + { + get + { + return Task.WhenAll(this.Processor._highPriorityProcessor.Running, this.Processor._normalPriorityProcessor.Running); + } + } + + protected override bool HigherQueueHasWorkItem + { + get + { + return this.Processor._highPriorityProcessor.HasAnyWork || this.Processor._normalPriorityProcessor.HasAnyWork; + } + } + protected override void PauseOnGlobalOperation() { _workItemQueue.RequestCancellationOnRunningTasks(); @@ -90,11 +103,25 @@ public void Enqueue(WorkItem item) var added = _workItemQueue.AddOrReplace(item); + // lower priority queue gets lowest time slot possible. if there is any activity going on in higher queue, it drop whatever it has + // and let higher work item run + CancelRunningTaskIfHigherQueueHasWorkItem(); + Logger.Log(FunctionId.WorkCoordinator_Project_Enqueue, s_enqueueLogger, Environment.TickCount, item.ProjectId, !added); SolutionCrawlerLogger.LogWorkItemEnqueue(this.Processor._logAggregator, item.ProjectId); } + private void CancelRunningTaskIfHigherQueueHasWorkItem() + { + if (!HigherQueueHasWorkItem) + { + return; + } + + _workItemQueue.RequestCancellationOnRunningTasks(); + } + private async Task ProcessProjectAsync(ImmutableArray analyzers, WorkItem workItem, CancellationTokenSource source) { if (this.CancellationToken.IsCancellationRequested) diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs index 3c46bf2a33b6bcb15fdfa99a197552390836d39f..025f9afc0c336a93f7cdee8297a9643285640ccf 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs @@ -124,6 +124,14 @@ public Task Running } } + public bool HasAnyWork + { + get + { + return _workItemQueue.HasAnyWork; + } + } + protected override async Task ExecuteAsync() { if (this.CancellationToken.IsCancellationRequested) @@ -137,11 +145,7 @@ protected override async Task ExecuteAsync() // mark it as running _running = source.Task; - // we wait for global operation if there is anything going on - await GlobalOperationWaitAsync().ConfigureAwait(false); - - // we wait for higher processor to finish its working - await this.Processor._highPriorityProcessor.Running.ConfigureAwait(false); + await WaitForHigherPriorityOperationsAsync().ConfigureAwait(false); // okay, there must be at least one item in the map await ResetStatesAsync().ConfigureAwait(false); @@ -155,7 +159,7 @@ protected override async Task ExecuteAsync() // process one of documents remaining var documentCancellation = default(CancellationTokenSource); WorkItem workItem; - if (!_workItemQueue.TryTakeAnyWork(_currentProjectProcessing, out workItem, out documentCancellation)) + if (!_workItemQueue.TryTakeAnyWork(_currentProjectProcessing, this.Processor.DependencyGraph, out workItem, out documentCancellation)) { return; } @@ -183,6 +187,22 @@ protected override async Task ExecuteAsync() } } + protected override Task HigherQueueOperationTask + { + get + { + return this.Processor._highPriorityProcessor.Running; + } + } + + protected override bool HigherQueueHasWorkItem + { + get + { + return this.Processor._highPriorityProcessor.HasAnyWork; + } + } + protected override void PauseOnGlobalOperation() { _workItemQueue.RequestCancellationOnRunningTasks(); diff --git a/src/Features/Core/SolutionCrawler/WorkCoordinator.cs b/src/Features/Core/SolutionCrawler/WorkCoordinator.cs index a10bc9a9380967f31e55b3d952f44ba55e8b294a..07980da0e51107523924a744105e1a5ac19986a9 100644 --- a/src/Features/Core/SolutionCrawler/WorkCoordinator.cs +++ b/src/Features/Core/SolutionCrawler/WorkCoordinator.cs @@ -54,21 +54,21 @@ private partial class WorkCoordinator _eventProcessingQueue = new SimpleTaskQueue(TaskScheduler.Default); - var activeFileBackOffTimeSpanInMS = _optionService.GetOption(SolutionCrawlerOptions.ActiveFileWorkerBackOffTimeSpanInMS); - var allFilesWorkerBackOffTimeSpanInMS = _optionService.GetOption(SolutionCrawlerOptions.AllFilesWorkerBackOffTimeSpanInMS); - var entireProjectWorkerBackOffTimeSpanInMS = _optionService.GetOption(SolutionCrawlerOptions.EntireProjectWorkerBackOffTimeSpanInMS); + var activeFileBackOffTimeSpanInMS = _optionService.GetOption(InternalSolutionCrawlerOptions.ActiveFileWorkerBackOffTimeSpanInMS); + var allFilesWorkerBackOffTimeSpanInMS = _optionService.GetOption(InternalSolutionCrawlerOptions.AllFilesWorkerBackOffTimeSpanInMS); + var entireProjectWorkerBackOffTimeSpanInMS = _optionService.GetOption(InternalSolutionCrawlerOptions.EntireProjectWorkerBackOffTimeSpanInMS); _documentAndProjectWorkerProcessor = new IncrementalAnalyzerProcessor( listener, analyzerProviders, _registration, activeFileBackOffTimeSpanInMS, allFilesWorkerBackOffTimeSpanInMS, entireProjectWorkerBackOffTimeSpanInMS, _shutdownToken); - var semanticBackOffTimeSpanInMS = _optionService.GetOption(SolutionCrawlerOptions.SemanticChangeBackOffTimeSpanInMS); - var projectBackOffTimeSpanInMS = _optionService.GetOption(SolutionCrawlerOptions.ProjectPropagationBackOffTimeSpanInMS); + var semanticBackOffTimeSpanInMS = _optionService.GetOption(InternalSolutionCrawlerOptions.SemanticChangeBackOffTimeSpanInMS); + var projectBackOffTimeSpanInMS = _optionService.GetOption(InternalSolutionCrawlerOptions.ProjectPropagationBackOffTimeSpanInMS); _semanticChangeProcessor = new SemanticChangeProcessor(listener, _registration, _documentAndProjectWorkerProcessor, semanticBackOffTimeSpanInMS, projectBackOffTimeSpanInMS, _shutdownToken); // if option is on - if (_optionService.GetOption(SolutionCrawlerOptions.SolutionCrawler)) + if (_optionService.GetOption(InternalSolutionCrawlerOptions.SolutionCrawler)) { _registration.Workspace.WorkspaceChanged += OnWorkspaceChanged; _registration.Workspace.DocumentOpened += OnDocumentOpened; @@ -116,7 +116,7 @@ public void Shutdown(bool blockingShutdown) private void OnOptionChanged(object sender, OptionChangedEventArgs e) { // if solution crawler got turned off or on. - if (e.Option == SolutionCrawlerOptions.SolutionCrawler) + if (e.Option == InternalSolutionCrawlerOptions.SolutionCrawler) { var value = (bool)e.Value; if (value) diff --git a/src/Test/Diagnostics/DiagnosticOnly_Logger.cs b/src/Test/Diagnostics/DiagnosticOnly_Logger.cs index d120cd0aa9c47948121c6753d8ede2b8a8c276fd..41702beebd081d2078d2e009590955272b6cf2d3 100644 --- a/src/Test/Diagnostics/DiagnosticOnly_Logger.cs +++ b/src/Test/Diagnostics/DiagnosticOnly_Logger.cs @@ -52,20 +52,6 @@ internal static void SetLogger(IOptionService optionsService, string loggerName) Logger.SetLogger(GetLogger(optionsService, loggerName)); } - /// - /// let ones such as Perf setup to share loggingChecker func - /// - internal static Func GetLoggingChecker(IOptionService optionsService) - { - var functionIds = Enum.GetValues(typeof(FunctionId)).Cast(); - var functionIdOptions = functionIds.ToDictionary( - id => id, id => optionsService.GetOption(FunctionIdOptions.GetOption(id))); - - Func loggingChecker = (functionId) => functionIdOptions[functionId]; - - return loggingChecker; - } - /// /// get string representation of functionId /// @@ -109,9 +95,9 @@ private static ILogger GetLogger(IOptionService optionsService, string loggerNam switch (loggerName) { case "EtwLogger": - return new EtwLogger(GetLoggingChecker(optionsService)); + return new EtwLogger(Logger.GetLoggingChecker(optionsService)); case "TraceLogger": - return new TraceLogger(GetLoggingChecker(optionsService)); + return new TraceLogger(Logger.GetLoggingChecker(optionsService)); default: return EmptyLogger.Instance; } diff --git a/src/VisualStudio/Core/Def/Guids.cs b/src/VisualStudio/Core/Def/Guids.cs index e6a2be85256b16323528149d85ea97967bc03364..e95c857f7ce183d5cefb79ce58f5c4adadfad84d 100644 --- a/src/VisualStudio/Core/Def/Guids.cs +++ b/src/VisualStudio/Core/Def/Guids.cs @@ -90,6 +90,7 @@ internal static class Guids public const string RoslynOptionPagePerformanceFunctionIdIdString = "0C537218-3BDD-4CC8-AC4B-CEC152D4871A"; public const string RoslynOptionPagePerformanceLoggersIdString = "236AC96F-A60D-4BD6-A480-D315151EDC2B"; public const string RoslynOptionPageInternalDiagnosticsIdString = "48993C4C-C619-42AD-B1C8-79378AD8BEF2"; + public const string RoslynOptionPageInternalSolutionCrawlerIdString = "9702D3BD-F06C-4A6A-974B-7D0C2BC89A72"; public static readonly Guid RoslynPackageId = new Guid(RoslynPackageIdString); public static readonly Guid RoslynCommandSetId = new Guid(RoslynCommandSetIdString); diff --git a/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs b/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs index 78a55e8143bb5cd99eed49f70886a291f0fc86eb..3183669963bf36835fdabea035ab5e817ea7d837 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs @@ -60,6 +60,30 @@ protected void BindToOption(CheckBox checkbox, PerLanguageOption optionKey _bindingExpressions.Add(bindingExpression); } + protected void BindToOption(TextBox textBox, Option optionKey) + { + Binding binding = new Binding(); + + binding.Source = new OptionBinding(OptionService, optionKey); + binding.Path = new PropertyPath("Value"); + binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit; + + var bindingExpression = textBox.SetBinding(TextBox.TextProperty, binding); + _bindingExpressions.Add(bindingExpression); + } + + protected void BindToOption(TextBox textBox, PerLanguageOption optionKey, string languageName) + { + Binding binding = new Binding(); + + binding.Source = new PerLanguageOptionBinding(OptionService, optionKey, languageName); + binding.Path = new PropertyPath("Value"); + binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit; + + var bindingExpression = textBox.SetBinding(TextBox.TextProperty, binding); + _bindingExpressions.Add(bindingExpression); + } + internal virtual void LoadSettings() { foreach (var bindingExpression in _bindingExpressions) diff --git a/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs b/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs index 8549447aaa5e69102120ff60c95353b17e46b865..bcd282f6fe838993a08b3db1b944d224c0ad6b44 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs @@ -25,6 +25,16 @@ public AbstractSettingStoreOptionSerializer(IServiceProvider serviceProvider) } public virtual bool TryFetch(OptionKey optionKey, out object value) + { + return TryFetch(optionKey, (r, k, o) => r.GetValue(k, defaultValue: (bool)o.DefaultValue ? 1 : 0).Equals(1), out value); + } + + public virtual bool TryPersist(OptionKey optionKey, object value) + { + return TryPersist(optionKey, value, (r, k, o, v) => r.SetValue(k, (bool)v ? 1 : 0, RegistryValueKind.DWord)); + } + + protected bool TryFetch(OptionKey optionKey, Func valueGetter, out object value) { if (this.RegistryKey == null) { @@ -40,21 +50,21 @@ public virtual bool TryFetch(OptionKey optionKey, out object value) lock (Gate) { - using (var openSubKey = this.RegistryKey.OpenSubKey(collectionPathAndPropertyName.Item1)) + using (var subKey = this.RegistryKey.OpenSubKey(collectionPathAndPropertyName.Item1)) { - if (openSubKey == null) + if (subKey == null) { value = null; return false; } - value = openSubKey.GetValue(collectionPathAndPropertyName.Item2, defaultValue: (bool)optionKey.Option.DefaultValue ? 1 : 0).Equals(1); + value = valueGetter(subKey, collectionPathAndPropertyName.Item2, optionKey.Option); return true; } } } - public virtual bool TryPersist(OptionKey optionKey, object value) + protected bool TryPersist(OptionKey optionKey, object value, Action valueSetter) { // We ignore languageName, since the current use of this class is only for // language-specific options that apply to a single language. The underlying option @@ -74,10 +84,9 @@ public virtual bool TryPersist(OptionKey optionKey, object value) { using (var subKey = this.RegistryKey.CreateSubKey(collectionPathAndPropertyName.Item1)) { - subKey.SetValue(collectionPathAndPropertyName.Item2, (bool)value ? 1 : 0, RegistryValueKind.DWord); + valueSetter(subKey, collectionPathAndPropertyName.Item2, optionKey.Option, value); + return true; } - - return true; } } } diff --git a/src/VisualStudio/Core/Impl/Options/InternalOptionSerializer.cs b/src/VisualStudio/Core/Impl/Options/InternalOptionSerializer.cs index befde2ef1992fbd6b6059b996ce76af7e572209b..8124387957515863b47e849b46979f8e54c1d73d 100644 --- a/src/VisualStudio/Core/Impl/Options/InternalOptionSerializer.cs +++ b/src/VisualStudio/Core/Impl/Options/InternalOptionSerializer.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.VisualStudio.Shell; using Microsoft.Win32; using Roslyn.Utilities; @@ -18,11 +19,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options PerformanceFunctionIdOptionsProvider.Name, LoggerOptions.FeatureName, CacheOptions.FeatureName, - InternalDiagnosticsOptions.OptionName), Shared] + InternalDiagnosticsOptions.OptionName, + InternalSolutionCrawlerOptions.OptionName), Shared] internal class InternalOptionSerializer : AbstractSettingStoreOptionSerializer { - private const string CachePath = @"Roslyn\Internal\Performance\Cache"; - [ImportingConstructor] public InternalOptionSerializer(SVsServiceProvider serviceProvider) : base(serviceProvider) @@ -51,28 +51,25 @@ public InternalOptionSerializer(SVsServiceProvider serviceProvider) { return Tuple.Create(@"Roslyn\Internal\Diagnostics", key.Name); } + else if (key.Feature == InternalSolutionCrawlerOptions.OptionName) + { + return Tuple.Create(@"Roslyn\Internal\SolutionCrawler", key.Name); + } + else if (key.Feature == CacheOptions.FeatureName) + { + return Tuple.Create(@"Roslyn\Internal\Performance\Cache", key.Name); + } throw ExceptionUtilities.Unreachable; } public override bool TryFetch(OptionKey optionKey, out object value) { - if (optionKey.Option.Feature == CacheOptions.FeatureName) + switch (optionKey.Option.Feature) { - lock (Gate) - { - using (var openSubKey = this.RegistryKey.OpenSubKey(CachePath)) - { - if (openSubKey == null) - { - value = null; - return false; - } - - value = openSubKey.GetValue(optionKey.Option.Name, defaultValue: optionKey.Option.DefaultValue); - return true; - } - } + case CacheOptions.FeatureName: + case InternalSolutionCrawlerOptions.OptionName: + return TryFetch(optionKey, (r, k, o) => r.GetValue(k, defaultValue: o.DefaultValue), out value); } return base.TryFetch(optionKey, out value); @@ -80,16 +77,11 @@ public override bool TryFetch(OptionKey optionKey, out object value) public override bool TryPersist(OptionKey optionKey, object value) { - if (optionKey.Option.Feature == CacheOptions.FeatureName) + switch (optionKey.Option.Feature) { - lock (Gate) - { - using (var subKey = this.RegistryKey.CreateSubKey(CachePath)) - { - subKey.SetValue(optionKey.Option.Name, value, optionKey.Option.Type == typeof(int) ? RegistryValueKind.DWord : RegistryValueKind.QWord); - return true; - } - } + case CacheOptions.FeatureName: + case InternalSolutionCrawlerOptions.OptionName: + return TryPersist(optionKey, value, (r, k, o, v) => r.SetValue(k, v, o.Type == typeof(int) ? RegistryValueKind.DWord : RegistryValueKind.QWord)); } return base.TryPersist(optionKey, value); diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs index 46973542bc3101dc65b051ce155a9a53b425b443..702c19691ee5f934c933e159c4e463417e0b952e 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs @@ -2,6 +2,7 @@ using System; using System.Linq; +using System.Windows; using System.Windows.Controls; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; @@ -19,9 +20,7 @@ public InternalOptionsControl(string featureOptionName, IServiceProvider service { if (!option.IsPerLanguage) { - var checkBox = new CheckBox() { Content = option.Name }; - BindToOption(checkBox, (Option)option); - panel.Children.Add(checkBox); + AddOption(panel, option); } else { @@ -51,11 +50,79 @@ public InternalOptionsControl(string featureOptionName, IServiceProvider service this.Content = viewer; } - private void AddPerLanguageOption(StackPanel panel, IOption option, string language) + private void AddOption(StackPanel panel, IOption option) { - var checkBox = new CheckBox() { Content = option.Name + " [" + language + "]" }; - BindToOption(checkBox, (PerLanguageOption)option, language); - panel.Children.Add(checkBox); + var uiElement = CreateControl(option); + if (uiElement != null) + { + panel.Children.Add(uiElement); + } + } + + private void AddPerLanguageOption(StackPanel panel, IOption option, string languageName) + { + var uiElement = CreateControl(option, languageName); + if (uiElement != null) + { + panel.Children.Add(uiElement); + } + } + + private UIElement CreateControl(IOption option, string languageName = null) + { + if (option.Type == typeof(bool)) + { + var checkBox = new CheckBox() { Content = option.Name + GetLanguage(languageName) }; + BindToCheckBox(checkBox, option, languageName); + return checkBox; + } + + if (option.Type == typeof(int)) + { + var label = new Label() { Content = option.Name + GetLanguage(languageName) }; + var textBox = new TextBox(); + BindToTextBox(textBox, option, languageName); + + var panel = new StackPanel(); + panel.Children.Add(label); + panel.Children.Add(textBox); + + return panel; + } + + return null; + } + + private string GetLanguage(string languageName) + { + if (languageName == null) + { + return string.Empty; + } + + return " [" + languageName + "]"; + } + + private void BindToCheckBox(CheckBox checkBox, IOption option, string languageName = null) + { + if (languageName == null) + { + BindToOption(checkBox, (Option)option); + return; + } + + BindToOption(checkBox, (PerLanguageOption)option, languageName); + } + + private void BindToTextBox(TextBox textBox, IOption option, string languageName = null) + { + if (languageName == null) + { + BindToOption(textBox, (Option)option); + return; + } + + BindToOption(textBox, (PerLanguageOption)option, languageName); } } } diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalSolutionCrawlerPage.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalSolutionCrawlerPage.cs new file mode 100644 index 0000000000000000000000000000000000000000..e47f2b400f52eacee1aaa2ae76f683aaf681e969 --- /dev/null +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalSolutionCrawlerPage.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.SolutionCrawler; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + [Guid(Guids.RoslynOptionPageInternalSolutionCrawlerIdString)] + internal class InternalSolutionCrawlerPage : AbstractOptionPage + { + protected override AbstractOptionPageControl CreateOptionPage(IServiceProvider serviceProvider) + { + return new InternalOptionsControl(InternalSolutionCrawlerOptions.OptionName, serviceProvider); + } + } +} diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj index 65146da7e3caefa1512def066ccf3ad682ad5837..5141c010e815fcb3977da42a6229d871cff74775 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj @@ -106,6 +106,7 @@ + diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindowPackage.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindowPackage.cs index ea1be59696f98639c53e46f2d64385704e4e169f..8e538d946576ae4c9af3655cc697a8094cb3f36d 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindowPackage.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindowPackage.cs @@ -34,6 +34,7 @@ namespace Roslyn.VisualStudio.DiagnosticsWindow [ProvideOptionPage(typeof(PerformanceFunctionIdPage), @"Roslyn\Performance", @"FunctionId", categoryResourceID: 0, pageNameResourceID: 0, supportsAutomation: true, SupportsProfiles = false)] [ProvideOptionPage(typeof(PerformanceLoggersPage), @"Roslyn\Performance", @"Loggers", categoryResourceID: 0, pageNameResourceID: 0, supportsAutomation: true, SupportsProfiles = false)] [ProvideOptionPage(typeof(InternalDiagnosticsPage), @"Roslyn\Diagnostics", @"Internal", categoryResourceID: 0, pageNameResourceID: 0, supportsAutomation: true, SupportsProfiles = false)] + [ProvideOptionPage(typeof(InternalSolutionCrawlerPage), @"Roslyn\SolutionCrawler", @"Internal", categoryResourceID: 0, pageNameResourceID: 0, supportsAutomation: true, SupportsProfiles = false)] // This attribute registers a tool window exposed by this package. [ProvideToolWindow(typeof(DiagnosticsWindow))] [Guid(GuidList.guidVisualStudioDiagnosticsWindowPkgString)] diff --git a/src/Workspaces/Core/Portable/Log/FunctionIdOptions.cs b/src/Workspaces/Core/Portable/Log/FunctionIdOptions.cs index d77bb0c1154a3336b539e36b030552b5e24fbaa9..5951b7a9751a8a48f1439667553cc3c354e58277 100644 --- a/src/Workspaces/Core/Portable/Log/FunctionIdOptions.cs +++ b/src/Workspaces/Core/Portable/Log/FunctionIdOptions.cs @@ -25,82 +25,11 @@ private static bool GetDefaultValue(FunctionId id) { switch (id) { - case FunctionId.TestEvent_NotUsed: - return false; - - case FunctionId.Tagger_AdornmentManager_OnLayoutChanged: - case FunctionId.Tagger_AdornmentManager_UpdateInvalidSpans: - case FunctionId.Tagger_BatchChangeNotifier_NotifyEditorNow: - case FunctionId.Tagger_BatchChangeNotifier_NotifyEditor: - case FunctionId.Tagger_TagSource_ProcessNewTags: - case FunctionId.Tagger_SyntacticClassification_TagComputer_GetTags: - case FunctionId.Tagger_SemanticClassification_TagProducer_ProduceTags: - case FunctionId.Tagger_BraceHighlighting_TagProducer_ProduceTags: - case FunctionId.Tagger_LineSeparator_TagProducer_ProduceTags: - case FunctionId.Tagger_Outlining_TagProducer_ProduceTags: - case FunctionId.Tagger_Highlighter_TagProducer_ProduceTags: - case FunctionId.Tagger_ReferenceHighlighting_TagProducer_ProduceTags: - return false; - - case FunctionId.Tagger_Diagnostics_RecomputeTags: - case FunctionId.Tagger_Diagnostics_Updated: - return false; - - case FunctionId.Workspace_SourceText_GetChangeRanges: - case FunctionId.Workspace_Recoverable_RecoverRootAsync: - case FunctionId.Workspace_Recoverable_RecoverRoot: - case FunctionId.Workspace_Recoverable_RecoverTextAsync: - case FunctionId.Workspace_Recoverable_RecoverText: - return false; - - case FunctionId.Misc_NonReentrantLock_BlockingWait: - return false; - - case FunctionId.Cache_Created: - case FunctionId.Cache_AddOrAccess: - case FunctionId.Cache_Remove: - case FunctionId.Cache_Evict: - case FunctionId.Cache_EvictAll: - case FunctionId.Cache_ItemRank: - return false; - - case FunctionId.Simplifier_ReduceAsync: - case FunctionId.Simplifier_ExpandNode: - case FunctionId.Simplifier_ExpandToken: - return false; - - case FunctionId.TemporaryStorageServiceFactory_ReadText: - case FunctionId.TemporaryStorageServiceFactory_WriteText: - case FunctionId.TemporaryStorageServiceFactory_ReadStream: - case FunctionId.TemporaryStorageServiceFactory_WriteStream: - return false; - - case FunctionId.WorkCoordinator_DocumentWorker_Enqueue: - case FunctionId.WorkCoordinator_ProcessProjectAsync: - case FunctionId.WorkCoordinator_ProcessDocumentAsync: - case FunctionId.WorkCoordinator_SemanticChange_Enqueue: - case FunctionId.WorkCoordinator_SemanticChange_EnqueueFromMember: - case FunctionId.WorkCoordinator_SemanticChange_EnqueueFromType: - case FunctionId.WorkCoordinator_SemanticChange_FullProjects: - case FunctionId.WorkCoordinator_Project_Enqueue: - case FunctionId.WorkCoordinator_ActivieFileEnqueue: - return false; - - case FunctionId.Diagnostics_SyntaxDiagnostic: - case FunctionId.Diagnostics_SemanticDiagnostic: - case FunctionId.Diagnostics_ProjectDiagnostic: - case FunctionId.Diagnostics_DocumentReset: - case FunctionId.Diagnostics_DocumentOpen: - case FunctionId.Diagnostics_RemoveDocument: - case FunctionId.Diagnostics_RemoveProject: - return false; - - case FunctionId.SuggestedActions_HasSuggestedActionsAsync: - case FunctionId.SuggestedActions_GetSuggestedActions: - return false; - + // change not to enable any etw events by default. + // we used to couple this to other logger such as code marker but now it is only specific to etw. + // each events should be enabled specifically when needed. default: - return true; + return false; } } } diff --git a/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs b/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs index 3a28656c19ba614556596c581e3248bad53e6230..de1048546f414b061cea641e33f7176012bc60c1 100644 --- a/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs +++ b/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs @@ -59,7 +59,7 @@ protected override string CreateMessage() return string.Join("|", _map.Select(kv => string.Format("{0}={1}", kv.Key, kv.Value))); } - public override void Free() + protected override void FreeCore() { if (_map != null) { diff --git a/src/Workspaces/Core/Portable/Log/LogMessage.cs b/src/Workspaces/Core/Portable/Log/LogMessage.cs index 009d8065878501b646c64ecc6dcda50378547256..7db8feb369dcda53b8baf2c6c7c369f86a21018b 100644 --- a/src/Workspaces/Core/Portable/Log/LogMessage.cs +++ b/src/Workspaces/Core/Portable/Log/LogMessage.cs @@ -48,7 +48,7 @@ public static LogMessage Create(Func messageGetter, TArg arg /// /// Logger will call this to return LogMessage to its pool /// - public abstract void Free(); + protected abstract void FreeCore(); public string GetMessage() { @@ -60,6 +60,13 @@ public string GetMessage() return _message; } + public void Free() + { + _message = null; + + FreeCore(); + } + private sealed class StaticLogMessage : LogMessage { private static readonly ObjectPool s_pool = SharedPools.Default(); @@ -77,7 +84,7 @@ protected override string CreateMessage() return _message; } - public override void Free() + protected override void FreeCore() { if (_message == null) { @@ -108,7 +115,7 @@ protected override string CreateMessage() return _messageGetter(); } - public override void Free() + protected override void FreeCore() { if (_messageGetter == null) { @@ -141,7 +148,7 @@ protected override string CreateMessage() return _messageGetter(_arg); } - public override void Free() + protected override void FreeCore() { if (_messageGetter == null) { @@ -177,7 +184,7 @@ protected override string CreateMessage() return _messageGetter(_arg0, _arg1); } - public override void Free() + protected override void FreeCore() { if (_messageGetter == null) { @@ -216,7 +223,7 @@ protected override string CreateMessage() return _messageGetter(_arg0, _arg1, _arg2); } - public override void Free() + protected override void FreeCore() { if (_messageGetter == null) { @@ -258,7 +265,7 @@ protected override string CreateMessage() return _messageGetter(_arg0, _arg1, _arg2, _arg3); } - public override void Free() + protected override void FreeCore() { if (_messageGetter == null) {