diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs index b742e336d8ce412b0aecd434e1e9522d636e1399..3f74ec02dd8af0c2d197d7b4e8402dc345874ae1 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs @@ -20,7 +20,10 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticUpdateSource private DiagnosticAnalyzerService(IDiagnosticUpdateSourceRegistrationService registrationService) : this() { _eventMap = new EventMap(); - _eventQueue = new SimpleTaskQueue(TaskScheduler.Default); + + // use diagnostic event task scheduler so that we never flood async events queue with million of events. + // queue itself can handle huge number of events but we are seeing OOM due to captured data in pending events. + _eventQueue = new SimpleTaskQueue(new DiagnosticEventTaskScheduler(blockingUpperBound: 100)); registrationService.Register(this); } diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticEventTaskScheduler.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticEventTaskScheduler.cs new file mode 100644 index 0000000000000000000000000000000000000000..a79d647a01ccf45d2aa34bae31a4a0126ac733e3 --- /dev/null +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticEventTaskScheduler.cs @@ -0,0 +1,55 @@ +// 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.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + /// + /// This task scheduler will block queuing new tasks if upper bound has met. + /// + internal class DiagnosticEventTaskScheduler : TaskScheduler + { + private readonly Task _mainTask; + private readonly BlockingCollection _tasks; + + public DiagnosticEventTaskScheduler(int blockingUpperBound) + { + _tasks = new BlockingCollection(blockingUpperBound); + + // portable layer doesnt support explicit thread creation. use long running task to create and hold onto a thread + _mainTask = Task.Factory.SafeStartNew(Start, CancellationToken.None, + TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, TaskScheduler.Default); + } + + private void Start() + { + while (true) + { + var task = _tasks.Take(); + bool ret = this.TryExecuteTask(task); + } + } + + protected override void QueueTask(Task task) + { + _tasks.Add(task); + } + + protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) + { + // NOTE: TPL will ensure only one task ever run when running scheduled task. and since this is only used + // in diagnostic events, we know task will ever run sequencely. so no worry about reverted order here. + return this.TryExecuteTask(task); + } + + protected override IEnumerable GetScheduledTasks() + { + // debugger will use this method to get scheduled tasks for this scheduler + return _tasks.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs index 3dbbe6624e46c1058c5dd1bcfd8ebb18b90b1f2c..ab368dc658ac4e1fdf51d250f85b5e63eec9df63 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs @@ -30,7 +30,10 @@ public DiagnosticService([ImportMany] IEnumerable + /// Only For Testing + /// + internal string Name_TestingOnly { get { return _stateName; } } - internal string Language + /// + /// Only For Testing + /// + internal string Language_TestingOnly { get { return _language; } } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs b/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs index 85de338c1516131ef65624afd77c261aba644ef7..2865384195cb98a7ae71a55dbda87c7f1042aad4 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs @@ -178,7 +178,7 @@ private static void VerifyDiagnosticStates(IEnumerable stateSets) { var state = stateSet.GetState((StateType)i); - if (!(set.Add(ValueTuple.Create(state.Language, state.Name)))) + if (!(set.Add(ValueTuple.Create(state.Language_TestingOnly, state.Name_TestingOnly)))) { Contract.Fail(); } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs index 7613d0335687cdb1b24f9aaae95bf89f5a85577e..438ec74813ca96bc52c5ba8c6485dedad3955db2 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs @@ -181,7 +181,7 @@ private async Task AnalyzeSyntaxAsync(Document document, ImmutableHashSet.Empty, data.Items); continue; } @@ -617,6 +617,11 @@ private static bool CheckSemanticVersions(Project project, AnalysisData existing project.CanReusePersistedDependentSemanticVersion(versions.ProjectVersion, versions.DataVersion, existingData.DataVersion); } + private void RaiseDiagnosticCreatedFromCacheIfNeeded(StateType type, Document document, StateSet stateSet, ImmutableArray items) + { + RaiseDocumentDiagnosticsUpdatedIfNeeded(type, document, stateSet, ImmutableArray.Empty, items); + } + private void RaiseDocumentDiagnosticsUpdatedIfNeeded( StateType type, Document document, StateSet stateSet, ImmutableArray existingItems, ImmutableArray newItems) { diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index a8d1522d17cdf8da9aec968c6db61833c25db811..3cfcc45b0a98c3342511c97a085a3302b9ee1d7b 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -177,6 +177,7 @@ +