示例#1
0
        /// <summary>
        /// Tracks obtaining commit characters and committing
        /// </summary>
        /// <param name="telemetry">Telemetry from <see cref="IAsyncCompletionSession"/></param>
        /// <param name="sourceData">Data aggregator</param>
        private static void AddCommitManagerData(CompletionSessionTelemetry telemetry, Dictionary <string, AggregateCommitManagerData> commitManagerData)
        {
            var commitKey = telemetry.CommitManagerName;

            if (!string.IsNullOrEmpty(commitKey))
            {
                // commitKey is empty when session is dismissed without committing.
                if (!commitManagerData.ContainsKey(commitKey))
                {
                    commitManagerData[commitKey] = new AggregateCommitManagerData();
                }
                var aggregateCommitManagerData = commitManagerData[commitKey];

                aggregateCommitManagerData.TotalCommitTime += telemetry.CommitDuration;
                aggregateCommitManagerData.CommitCount++;

                aggregateCommitManagerData.MaxCommitTime = Math.Max(aggregateCommitManagerData.MaxCommitTime, telemetry.CommitDuration);
            }

            foreach (var commitManagerSetupData in telemetry.CommitManagerSetupDuration)
            {
                if (!commitManagerData.ContainsKey(commitManagerSetupData.Key))
                {
                    commitManagerData[commitManagerSetupData.Key] = new AggregateCommitManagerData();
                }
                var aggregateCommitManagerData = commitManagerData[commitManagerSetupData.Key];

                aggregateCommitManagerData.TotalSetupTime += commitManagerSetupData.Value;
                aggregateCommitManagerData.SetupCount++;

                aggregateCommitManagerData.MaxSetupTime = Math.Max(aggregateCommitManagerData.MaxSetupTime, commitManagerSetupData.Value);
            }
        }
示例#2
0
        /// <summary>
        /// Tracks obtaining applicable span and getting items
        /// </summary>
        /// <param name="telemetry">Telemetry from <see cref="IAsyncCompletionSession"/></param>
        /// <param name="sourceData">Data aggregator</param>
        private static void AddSourceData(CompletionSessionTelemetry telemetry, Dictionary <string, AggregateSourceData> sourceData)
        {
            foreach (var setupData in telemetry.ItemSourceSetupDuration)
            {
                if (!sourceData.ContainsKey(setupData.Key))
                {
                    sourceData[setupData.Key] = new AggregateSourceData();
                }
                var aggregateSourceData = sourceData[setupData.Key];

                aggregateSourceData.TotalSetupTime += setupData.Value;
                aggregateSourceData.SetupCount++;

                aggregateSourceData.MaxSetupTime = Math.Max(aggregateSourceData.MaxSetupTime, setupData.Value);
            }

            foreach (var getContextData in telemetry.ItemSourceGetContextDuration)
            {
                if (!sourceData.ContainsKey(getContextData.Key))
                {
                    sourceData[getContextData.Key] = new AggregateSourceData();
                }
                var aggregateSourceData = sourceData[getContextData.Key];

                aggregateSourceData.TotalGetContextTime += getContextData.Value;
                aggregateSourceData.GetContextCount++;
            }
        }
#pragma warning restore CA1822

        #endregion

        #region MEF part helper methods

        private void GetCommitManagersAndChars(
            SnapshotPoint triggerLocation,
            Func <IContentType, ITextViewRoleSet, IReadOnlyList <Lazy <IAsyncCompletionCommitManagerProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata> > > getImports,
            ITextSnapshot rootSnapshot,
            ITextView textView,
            CompletionSessionTelemetry telemetry,
            out IList <(IAsyncCompletionCommitManager, ITextBuffer)> managersWithBuffers,
        public async Task <AggregatedCompletionContext> GetAggregatedCompletionContextAsync(ITextView textView, CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token)
        {
            if (token.IsCancellationRequested || textView.IsClosed)
            {
                return(AggregatedCompletionContext.Empty);
            }

            var telemetryHost = GetOrCreateTelemetry(textView);
            var telemetry     = new CompletionSessionTelemetry(telemetryHost, headless: true);

            // ----- GetCompletionSources and GetRootSnapshot need to be run on the UI thread:
            await JoinableTaskContext.Factory.SwitchToMainThreadAsync();

            if (token.IsCancellationRequested || textView.IsClosed)
            {
                return(AggregatedCompletionContext.Empty);
            }

            var rootSnapshot = GetRootSnapshot(textView);

            GetCompletionSources(triggerLocation, GetItemSourceProviders, rootSnapshot, textView, textView.BufferGraph, trigger, telemetry, token,
                                 out var sourcesWithLocations, out var applicableToSpan);

            // ----- Go back to background thread to continue processing
            await TaskScheduler.Default;

            if (token.IsCancellationRequested || textView.IsClosed)
            {
                return(AggregatedCompletionContext.Empty);
            }

            // No source declared an appropriate ApplicableToSpan
            if (applicableToSpan == default)
            {
                return(AggregatedCompletionContext.Empty);
            }

            // No source wishes to participate
            if (!sourcesWithLocations.Any())
            {
                return(null);
            }

            var aggregatingSession = AsyncCompletionSession.CreateAggregatingSession(applicableToSpan, JoinableTaskContext, sourcesWithLocations, this, textView, telemetry, GuardedOperations);

            var completionData = await aggregatingSession.ConnectToCompletionSources(trigger, triggerLocation, rootSnapshot, token).ConfigureAwait(true);

            if (completionData.IsCanceled)
            {
                return(AggregatedCompletionContext.Empty);
            }

            var aggregateCompletionContext = new CompletionContext(
                completionData.InitialCompletionItems,
                completionData.RequestedSuggestionItemOptions,
                completionData.InitialSelectionHint);

            return(new AggregatedCompletionContext(aggregateCompletionContext, aggregatingSession));
        }
 private static void AddBlockingExtensionData(CompletionSessionTelemetry telemetry, Dictionary <string, int> blockingExtensionData)
 {
     foreach (var blockingExtension in telemetry.BlockingExtensionCounter)
     {
         if (!blockingExtensionData.ContainsKey(blockingExtension.Key))
         {
             blockingExtensionData[blockingExtension.Key] = 0;
         }
         blockingExtensionData[blockingExtension.Key] += blockingExtension.Value;
     }
 }
示例#6
0
        /// <summary>
        /// Adds data from <see cref="CompletionSessionTelemetry" /> to appropriate buckets.
        /// </summary>
        /// <param name=""></param>
        internal void Add(CompletionSessionTelemetry telemetry)
        {
            if (_logger == null)
            {
                return;
            }

            AddSourceData(telemetry, SourceData);
            AddItemManagerData(telemetry, ItemManagerData);
            AddCommitManagerData(telemetry, CommitManagerData);
            AddPresenterData(telemetry, PresenterData);
            AddE2EData(telemetry, E2EData);
        }
示例#7
0
        /// <summary>
        /// Tracks opening, updating and closing the GUI
        /// </summary>
        /// <param name="telemetry">Telemetry from <see cref="IAsyncCompletionSession"/></param>
        /// <param name="sourceData">Data aggregator</param>
        private static void AddPresenterData(CompletionSessionTelemetry telemetry, Dictionary <string, AggregatePresenterData> presenterData)
        {
            var presenterKey = telemetry.PresenterProviderName;

            if (!presenterData.ContainsKey(presenterKey))
            {
                presenterData[presenterKey] = new AggregatePresenterData();
            }
            var aggregatePresenterData = presenterData[presenterKey];

            aggregatePresenterData.InitialRenderTime += telemetry.InitialRenderingDuration;
            aggregatePresenterData.TotalRenderTime   += telemetry.TotalRenderingDuration;
            aggregatePresenterData.RenderCount       += telemetry.TotalRenderingCount;
            aggregatePresenterData.TotalClosingTime  += telemetry.ClosingDuration;
            aggregatePresenterData.ClosingCount++;

            aggregatePresenterData.MaxRenderTime  = Math.Max(aggregatePresenterData.MaxRenderTime, telemetry.InitialRenderingDuration);
            aggregatePresenterData.MaxClosingTime = Math.Max(aggregatePresenterData.MaxClosingTime, telemetry.ClosingDuration);
        }
示例#8
0
        /// <summary>
        /// Tracks sorting and filtering items
        /// </summary>
        /// <param name="telemetry">Telemetry from <see cref="IAsyncCompletionSession"/></param>
        /// <param name="sourceData">Data aggregator</param>
        private static void AddItemManagerData(CompletionSessionTelemetry telemetry, Dictionary <string, AggregateItemManagerData> itemManagerData)
        {
            var itemManagerKey = telemetry.ItemManagerName;

            if (!itemManagerData.ContainsKey(itemManagerKey))
            {
                itemManagerData[itemManagerKey] = new AggregateItemManagerData();
            }
            var aggregateItemManagerData = itemManagerData[itemManagerKey];

            aggregateItemManagerData.InitialProcessTime           += telemetry.InitialProcessingDuration;
            aggregateItemManagerData.TotalProcessTime             += telemetry.TotalProcessingDuration;
            aggregateItemManagerData.TotalBlockingComputationTime += telemetry.BlockingComputationDuration;
            aggregateItemManagerData.ProcessCount       += telemetry.TotalProcessingCount;
            aggregateItemManagerData.TotalKeystrokes    += telemetry.NumberOfKeystrokes;
            aggregateItemManagerData.UserEverScrolled   += telemetry.UserEverScrolled ? 1 : 0;
            aggregateItemManagerData.UserEverSetFilters += telemetry.UserEverSetFilters ? 1 : 0;
            aggregateItemManagerData.FinalItemCount     += telemetry.FinalItemCount;
            aggregateItemManagerData.SessionCount++;

            aggregateItemManagerData.MaxBlockingComputationTime = Math.Max(aggregateItemManagerData.MaxBlockingComputationTime, telemetry.BlockingComputationDuration);
        }
示例#9
0
        private static void AddE2EData(CompletionSessionTelemetry telemetry, AggregateE2EData e2eData)
        {
            switch (telemetry.CompletionState)
            {
            case CompletionSessionState.Committed:
                e2eData.Committed++;
                break;

            case CompletionSessionState.CommittedSuggestionItem:
                e2eData.CommittedSuggestionItem++;
                break;

            case CompletionSessionState.CommittedThroughClick:
                e2eData.CommittedThroughClick++;
                break;

            case CompletionSessionState.CommittedThroughCompleteWord:
                e2eData.CommittedThroughCompleteWord++;
                break;

            case CompletionSessionState.DismissedDueToBackspace:
                e2eData.DismissedDueToBackspace++;
                break;

            case CompletionSessionState.DismissedDueToCancellation:
                e2eData.DismissedDueToCancellation++;
                break;

            case CompletionSessionState.DismissedDueToCaretLeaving:
                e2eData.DismissedDueToCaretLeaving++;
                break;

            case CompletionSessionState.DismissedDuringFiltering:
                e2eData.DismissedDuringFiltering++;
                break;

            case CompletionSessionState.DismissedDueToNonBlockingMode:
                e2eData.DismissedDueToNonBlockingMode++;
                break;

            case CompletionSessionState.DismissedDueToUnhandledError:
                e2eData.DismissedDueToUnhandledError++;
                break;

            case CompletionSessionState.DismissedThroughUI:
                e2eData.DismissedThroughUI++;
                break;

            case CompletionSessionState.DismissedUninitialized:
                e2eData.DismissedUninitialized++;
                break;

            default:
                e2eData.Dismissed++;
                break;
            }

            if (telemetry.CompletionState == CompletionSessionState.DismissedDueToCancellation)
            {
                e2eData.HistogramBucketCanceled++;
            }
            else
            {
                var E2eDuration = telemetry.E2EStopwatch.ElapsedMilliseconds;
                if (E2eDuration == 0)
                {
                    e2eData.HistogramBucketInvalid++;
                }
                else if (E2eDuration <= 25)
                {
                    e2eData.HistogramBucket25++;
                }
                else if (E2eDuration <= 50)
                {
                    e2eData.HistogramBucket50++;
                }
                else if (E2eDuration <= 100)
                {
                    e2eData.HistogramBucket100++;
                }
                else if (E2eDuration <= 250)
                {
                    e2eData.HistogramBucket250++;
                }
                else if (E2eDuration <= 500)
                {
                    e2eData.HistogramBucket500++;
                }
                else if (E2eDuration <= 1000)
                {
                    e2eData.HistogramBucket1000++;
                }
                else if (E2eDuration <= 2000)
                {
                    e2eData.HistogramBucket2000++;
                }
                else
                {
                    e2eData.HistogramBucketLast++;
                }
            }
        }
示例#10
0
        public IAsyncCompletionSession TriggerCompletion(ITextView textView, CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token)
        {
            var session = GetSession(textView);

            if (session != null)
            {
                return(session);
            }

            // This is a simple check that only queries the feature service.
            // If it succeeds, we will map triggerLocation to available buffers to discover MEF parts.
            // This is expensive but projected languages require it to discover parts in all available buffers.
            // To avoid doing this work, call IsCompletionSupported with appropriate IContentType prior to calling TriggerCompletion
            if (!CompletionAvailability.IsCurrentlyAvailable(textView))
            {
                return(null);
            }

            if (textView.IsClosed)
            {
                return(null);
            }

            if (!JoinableTaskContext.IsOnMainThread)
            {
                throw new InvalidOperationException($"This method must be callled on the UI thread.");
            }

            var telemetryHost = GetOrCreateTelemetry(textView);
            var telemetry     = new CompletionSessionTelemetry(telemetryHost);

            var rootSnapshot = GetRootSnapshot(textView);

            if (token.IsCancellationRequested || textView.IsClosed)
            {
                return(null);
            }

            // See if we can use more aggressive cancellation token for typing scenarios
            if (trigger.Reason == CompletionTriggerReason.Insertion)
            {
                token = CompletionUtilities.GetResponsiveToken(textView, token);
            }

            GetCompletionSources(triggerLocation, GetItemSourceProviders, rootSnapshot, textView, textView.BufferGraph, trigger, telemetry, token,
                                 out var sourcesWithLocations, out var applicableToSpan);

            if (token.IsCancellationRequested || textView.IsClosed)
            {
                return(null);
            }

            // No source declared an appropriate ApplicableToSpan
            if (applicableToSpan == default)
            {
                return(null);
            }

            // No source wishes to participate
            if (!sourcesWithLocations.Any())
            {
                return(null);
            }

            // Some of our extensions need to initialize the source providers before they initialize commit manager providers.
            // Therefore, it is important to invoke GetCommitManagerProviders after invoking GetItemSourceProviders.
            GetCommitManagersAndChars(triggerLocation, GetCommitManagerProviders, rootSnapshot, textView, telemetry,
                                      out var managersWithBuffers, out var potentialCommitChars);

            if (_contentTypeComparer == null)
            {
                _contentTypeComparer = new StableContentTypeComparer(ContentTypeRegistryService);
            }

            var itemManager       = GetItemManager(triggerLocation, GetItemManagerProviders, rootSnapshot, textView, _contentTypeComparer);
            var presenterProvider = GetPresenterProvider(triggerLocation, GetPresenters, rootSnapshot, textView.Roles, _contentTypeComparer);

            if (token.IsCancellationRequested || textView.IsClosed)
            {
                return(null);
            }

            session = new AsyncCompletionSession(applicableToSpan, potentialCommitChars, JoinableTaskContext, presenterProvider, sourcesWithLocations, managersWithBuffers, itemManager, this, textView, telemetry, GuardedOperations);
            textView.Properties.AddProperty(typeof(IAsyncCompletionSession), session);

            textView.Closed += DismissSessionOnViewClosed;
            EmulateLegacyCompletionTelemetry(textView);
            GuardedOperations.RaiseEvent(this, CompletionTriggered, new CompletionTriggeredEventArgs(session, textView));

            return(session);
        }