IJPL-193258 Add statistic to track the functioning of the identifier highlighting cache

GitOrigin-RevId: 62d4351e8e9d3058d1632601e9a6ae0c48a93fba
This commit is contained in:
Alexey Kudravtsev
2025-06-30 13:09:02 +00:00
committed by intellij-monorepo-bot
parent f1978eebf2
commit 46ff7ba496
4 changed files with 92 additions and 25 deletions
@@ -0,0 +1,58 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl
import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.FeatureUsageData
import com.intellij.internal.statistic.eventLog.events.BooleanEventField
import com.intellij.internal.statistic.eventLog.events.EventFields
import com.intellij.internal.statistic.eventLog.events.IntEventField
import com.intellij.internal.statistic.eventLog.events.LongEventField
import com.intellij.internal.statistic.eventLog.events.PrimitiveEventField
import com.intellij.internal.statistic.eventLog.events.VarargEventId
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import java.time.Duration
internal object IdentifierHighlightingFUSReporter {
fun report(project: Project, file: VirtualFile?, offset: Int, result: IdentifierHighlightingResult, fromCache:Boolean, computationDurationMs: Long) {
IdentifierHighlightingFUSCollector.HIGHLIGHTED.log(project,
IdentifierHighlightingFUSCollector.DURATION_MS with computationDurationMs,
IdentifierHighlightingFUSCollector.OFFSET with offset,
IdentifierHighlightingFUSCollector.FROM_CACHE with fromCache,
IdentifierHighlightingFUSCollector.OCCURRENCES with result.occurrences.size,
IdentifierHighlightingFUSCollector.TARGETS with result.targets.size,
EventFields.FileType with file?.fileType
)
}
}
internal object IdentifierHighlightingFUSCollector : CounterUsagesCollector() {
@JvmField
val GROUP: EventLogGroup = EventLogGroup("identifier_highlighting", 1)
@JvmField
val OFFSET: IntEventField = EventFields.Int("offset")
@JvmField
val FROM_CACHE: BooleanEventField = EventFields.Boolean("from_cache")
/**
* ident highlighter computing duration in ms
*/
@JvmField
val DURATION_MS: LongEventField = LongEventField("duration_ms")
@JvmField
val OCCURRENCES: IntEventField = EventFields.Int("occurrences")
@JvmField
val TARGETS: IntEventField = EventFields.Int("targets")
@JvmField
val HIGHLIGHTED: VarargEventId = GROUP.registerVarargEvent(
"highlighted",
DURATION_MS,
OFFSET,
FROM_CACHE,
OCCURRENCES,
TARGETS,
EventFields.FileType,
)
override fun getGroup(): EventLogGroup = GROUP
}
@@ -93,6 +93,7 @@ class IdentifierHighlightingManagerImpl(private val myProject: Project) : Identi
}
override suspend fun getMarkupData(editor: Editor, visibleRange: ProperTextRange): IdentifierHighlightingResult {
val start = System.currentTimeMillis()
val document = editor.getDocument()
val modStamp = (document as DocumentEx).modificationSequence
var result: IdentifierHighlightingResult? = null
@@ -130,35 +131,42 @@ class IdentifierHighlightingManagerImpl(private val myProject: Project) : Identi
else {
val hostRes = IdentifierHighlightingAccessor.getInstance(myProject).getMarkupData(psiFile, editor, visibleRange, offset)
if (hostRes == WRONG_DOCUMENT_VERSION) {
return WRONG_DOCUMENT_VERSION
result = WRONG_DOCUMENT_VERSION
}
result = readAction {
if (document.modificationSequence != modStamp) {
throw ProcessCanceledException(RuntimeException("document changed during RPC call. modStamp before=$modStamp; mod stamp after=${document.modificationSequence}"))
else {
result = readAction {
if (document.modificationSequence != modStamp) {
throw ProcessCanceledException(RuntimeException("document changed during RPC call. modStamp before=$modStamp; mod stamp after=${document.modificationSequence}"))
}
val hostDocument = PsiDocumentManagerBase.getTopLevelDocument(document)
val occurrenceRangeMarkers = ArrayList<RangeMarker>(hostRes.occurrences.size)
val cache = mutableMapOf<TextRange, RangeMarker>()
val rangeMarkerOccurrences = hostRes.occurrences.map { o: IdentifierOccurrence ->
val marker = createMarker(hostDocument, o.range, cache)
occurrenceRangeMarkers.add(marker)
IdentifierOccurrence(marker, o.highlightInfoType)
}
val rangeMarkerTargets = hostRes.targets.map { r ->
createMarker(hostDocument, r, cache)
}
val rangeMarkerResult = IdentifierHighlightingResult(rangeMarkerOccurrences, rangeMarkerTargets)
for (marker in cache.values) {
marker.putUserData(IDENT_MARKUP, rangeMarkerResult)
}
val editorResults = ConcurrencyUtil.computeIfAbsent(editor, EDITOR_IDENT_RESULTS) {
ConcurrentCollectionFactory.createConcurrentSet()
}
editorResults.add(rangeMarkerResult)
rangeMarkerResult
}
val hostDocument = PsiDocumentManagerBase.getTopLevelDocument(document)
val occurrenceRangeMarkers = ArrayList<RangeMarker>(hostRes.occurrences.size)
val cache = mutableMapOf<TextRange, RangeMarker>()
val rangeMarkerOccurrences = hostRes.occurrences.map { o: IdentifierOccurrence ->
val marker = createMarker(hostDocument, o.range, cache)
occurrenceRangeMarkers.add(marker)
IdentifierOccurrence(marker, o.highlightInfoType)
}
val rangeMarkerTargets = hostRes.targets.map { r ->
createMarker(hostDocument, r, cache)
}
val rangeMarkerResult = IdentifierHighlightingResult(rangeMarkerOccurrences, rangeMarkerTargets)
for (marker in cache.values) {
marker.putUserData(IDENT_MARKUP, rangeMarkerResult)
}
val editorResults = ConcurrencyUtil.computeIfAbsent(editor, EDITOR_IDENT_RESULTS) {
ConcurrentCollectionFactory.createConcurrentSet()
}
editorResults.add(rangeMarkerResult)
rangeMarkerResult
}
}
}
val end = System.currentTimeMillis()
val file = readAction {
FileDocumentManager.getInstance().getFile(editor.document)
}
IdentifierHighlightingFUSReporter.report(myProject, file, offset, result, bestMarker != null, end-start)
return result
}
@@ -241,7 +241,7 @@ class BackgroundHighlighter(coroutineScope: CoroutineScope) {
var result = EMPTY_RESULT
var infos = listOf<HighlightInfo>()
try {
result = identPass.doCollectInformation(newPsiFile.project, visibleRange)
result = identPass.doCollectInformation(project, visibleRange)
if (result == WRONG_DOCUMENT_VERSION) {
launch(Dispatchers.EDT + modalityState) {
updateHighlighted(project, hostEditor, coroutineScope)
@@ -1092,6 +1092,7 @@
<statistics.counterUsagesCollector implementationClass="com.intellij.usages.impl.UsageViewStatisticsCollector"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.openapi.fileTypes.impl.FileTypeConfigurableInteractions"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.codeInsight.daemon.impl.DaemonFusCollector"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.codeInsight.daemon.impl.IdentifierHighlightingFUSCollector"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.codeInspection.ex.GlobalInspectionContextImpl$InspectionPerformanceCollector"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.util.indexing.projectFilter.IndexableFilesFilterHealthCheckCollector"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.codeInsight.completion.command.CommandCompletionCollector"/>