diff --git a/plugins/filePrediction/resources/META-INF/plugin.xml b/plugins/filePrediction/resources/META-INF/plugin.xml index da981e617a2e..1c046b9f65b4 100644 --- a/plugins/filePrediction/resources/META-INF/plugin.xml +++ b/plugins/filePrediction/resources/META-INF/plugin.xml @@ -23,6 +23,7 @@ + diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/FileNavigationLogger.kt b/plugins/filePrediction/src/com/intellij/filePrediction/FileNavigationLogger.kt index 7e504976cc63..7611966817fc 100644 --- a/plugins/filePrediction/src/com/intellij/filePrediction/FileNavigationLogger.kt +++ b/plugins/filePrediction/src/com/intellij/filePrediction/FileNavigationLogger.kt @@ -9,12 +9,16 @@ internal object FileNavigationLogger { fun logEvent(project: Project, event: String, + sessionId: Int, features: FileFeaturesComputationResult, filePath: String, + prevFilePath: String?, refsComputation: Long, probability: Double? = null) { val data = FeatureUsageData(). + addData("session_id", sessionId). addAnonymizedPath(filePath). + addAnonymizedValue("prev_file_path", prevFilePath). addData("refs_computation", refsComputation). addData("features_computation", features.duration) diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionEditorManagerListener.kt b/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionEditorManagerListener.kt index 74f612f1e0c2..bf5fe9b12588 100644 --- a/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionEditorManagerListener.kt +++ b/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionEditorManagerListener.kt @@ -10,7 +10,7 @@ internal class FilePredictionEditorManagerListener : FileEditorManagerListener { override fun selectionChanged(event: FileEditorManagerEvent) { val newFile = event.newFile ?: return if (ApplicationManager.getApplication().isEAP && Registry.get("filePrediction.calculate.features").asBoolean()) { - FilePredictionHandler.onFileOpened(event.manager.project, newFile, event.oldFile) + FilePredictionHandler.getInstance()?.onFileOpened(event.manager.project, newFile, event.oldFile) } } } \ No newline at end of file diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionHandler.kt b/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionHandler.kt index fc8971cb0383..2a5f2eb565ee 100644 --- a/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionHandler.kt +++ b/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionHandler.kt @@ -2,18 +2,25 @@ package com.intellij.filePrediction import com.intellij.filePrediction.history.FilePredictionHistory import com.intellij.filePrediction.predictor.FileUsagePredictor +import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.progress.util.BackgroundTaskUtil import com.intellij.openapi.project.Project import com.intellij.openapi.project.impl.ProjectManagerImpl import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.concurrency.NonUrgentExecutor -object FilePredictionHandler { - private const val CALCULATE_OPEN_FILE_PROBABILITY: Double = 0.5 +class FilePredictionHandler { + companion object { + private const val CALCULATE_OPEN_FILE_PROBABILITY: Double = 0.5 + private const val CALCULATE_CANDIDATE_PROBABILITY: Double = 0.1 + + fun getInstance(): FilePredictionHandler? = ServiceManager.getService(FilePredictionHandler::class.java) + } - private const val CALCULATE_CANDIDATE_PROBABILITY: Double = 0.1 private val predictor: FileUsagePredictor = FileUsagePredictor(30, 5, 10) + private var session: FilePredictionSessionHolder = FilePredictionSessionHolder() + fun onFileOpened(project: Project, newFile: VirtualFile, prevFile: VirtualFile?) { if (ProjectManagerImpl.isLight(project)) { return @@ -21,21 +28,26 @@ object FilePredictionHandler { NonUrgentExecutor.getInstance().execute { BackgroundTaskUtil.runUnderDisposeAwareIndicator(project, Runnable { - if (Math.random() < CALCULATE_OPEN_FILE_PROBABILITY) { - logOpenedFile(project, newFile, prevFile) + val previousSession = session.getSession() + if (previousSession != null && previousSession.shouldLog(CALCULATE_OPEN_FILE_PROBABILITY)) { + logOpenedFile(project, previousSession.id, newFile, prevFile) } - if (Math.random() < CALCULATE_CANDIDATE_PROBABILITY) { - predictor.predictNextFile(project, newFile) + val newSession = session.newSession() + if (newSession != null && newSession.shouldLog(CALCULATE_CANDIDATE_PROBABILITY)) { + predictor.predictNextFile(project, newSession.id, newFile) } FilePredictionHistory.getInstance(project).onFileOpened(newFile.url) }) } } - private fun logOpenedFile(project: Project, newFile: VirtualFile, prevFile: VirtualFile?) { + private fun logOpenedFile(project: Project, + sessionId: Int, + newFile: VirtualFile, + prevFile: VirtualFile?) { val result = FilePredictionFeaturesHelper.calculateExternalReferences(project, prevFile) val features = FilePredictionFeaturesHelper.calculateFileFeatures(project, newFile, result.value, prevFile) - FileNavigationLogger.logEvent(project, "file.opened", features, newFile.path, result.duration) + FileNavigationLogger.logEvent(project, "file.opened", sessionId, features, newFile.path, prevFile?.path, result.duration) } } \ No newline at end of file diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionSession.kt b/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionSession.kt new file mode 100644 index 000000000000..ab8c89ef75ac --- /dev/null +++ b/plugins/filePrediction/src/com/intellij/filePrediction/FilePredictionSession.kt @@ -0,0 +1,27 @@ +package com.intellij.filePrediction + +import java.util.concurrent.atomic.AtomicInteger + +private val counter = AtomicInteger(0) + +internal class FilePredictionSessionHolder { + private var session: FilePredictionSession? = null + + @Synchronized + fun getSession(): FilePredictionSession? = session + + @Synchronized + fun newSession(): FilePredictionSession? { + session = FilePredictionSession() + return session + } +} + +internal class FilePredictionSession { + val id = counter.incrementAndGet() + private val loggingProbability = Math.random() + + fun shouldLog(threshold: Double): Boolean { + return loggingProbability < threshold + } +} \ No newline at end of file diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/predictor/FileUsagePredictor.kt b/plugins/filePrediction/src/com/intellij/filePrediction/predictor/FileUsagePredictor.kt index 2755b1d69b59..06110bf4a9e3 100644 --- a/plugins/filePrediction/src/com/intellij/filePrediction/predictor/FileUsagePredictor.kt +++ b/plugins/filePrediction/src/com/intellij/filePrediction/predictor/FileUsagePredictor.kt @@ -14,27 +14,28 @@ import com.intellij.openapi.vfs.VirtualFile internal class FileUsagePredictor(private val candidatesLimit: Int, private val logTopLimit: Int, private val logTotalLimit: Int) { - fun predictNextFile(project: Project, file: VirtualFile) { + fun predictNextFile(project: Project, sessionId: Int, file: VirtualFile) { val result = FilePredictionFeaturesHelper.calculateExternalReferences(project, file) val model = getFilePredictionModel() if (model != null) { - predictAndLogCandidates(project, model, file, result) + predictAndLogCandidates(project, sessionId, model, file, result) } else { - logCandidates(project, file, result) + logCandidates(project, sessionId, file, result) } } - private fun logCandidates(project: Project, file: VirtualFile, refs: FileReferencesComputationResult) { + private fun logCandidates(project: Project, sessionId: Int, file: VirtualFile, refs: FileReferencesComputationResult) { val candidateFiles = provideCandidates(project, file, refs.value.references, logTotalLimit) for (candidate in candidateFiles) { val features = FilePredictionFeaturesHelper.calculateFileFeatures(project, candidate, refs.value, file) - FileNavigationLogger.logEvent(project, "candidate.calculated", features, candidate.path, refs.duration) + FileNavigationLogger.logEvent(project, "candidate.calculated", sessionId, features, candidate.path, file.path, refs.duration) } } private fun predictAndLogCandidates(project: Project, + sessionId: Int, model: FilePredictionModel, file: VirtualFile, refs: FileReferencesComputationResult) { @@ -47,25 +48,35 @@ internal class FileUsagePredictor(private val candidatesLimit: Int, } candidates.sortByDescending { it.probability } - logCandidatesWithProbability(project, candidates, refs.duration) + logCandidatesWithProbability(project, sessionId, file.path, candidates, refs.duration) } - private fun logCandidatesWithProbability(project: Project, candidates: MutableList, refsComputation: Long) { + private fun logCandidatesWithProbability(project: Project, + sessionId: Int, + prevPath: String?, + candidates: MutableList, + refsComputation: Long) { val head = candidates.take(logTopLimit) - logCalculatedCandidates(project, head, refsComputation) + logCalculatedCandidates(project, sessionId, prevPath, head, refsComputation) if (candidates.size > logTopLimit) { val tail = candidates.subList(logTopLimit, candidates.size) val randomToLog = tail.shuffled().take(logTotalLimit - logTopLimit) - logCalculatedCandidates(project, randomToLog, refsComputation) + logCalculatedCandidates(project, sessionId, prevPath, randomToLog, refsComputation) } } - private fun logCalculatedCandidates(project: Project, candidates: Collection, refsComputation: Long) { + private fun logCalculatedCandidates(project: Project, + sessionId: Int, + prevPath:String?, + candidates: Collection, + refsComputation: Long) { for (candidate in candidates) { val probability = candidate.probability val features = candidate.features - FileNavigationLogger.logEvent(project, "candidate.calculated", features, candidate.path, refsComputation, probability) + FileNavigationLogger.logEvent( + project, "candidate.calculated", sessionId, features, candidate.path, prevPath, refsComputation, probability + ) } } } diff --git a/plugins/filePrediction/test/com/intellij/filePrediction/predictor/FileUsagePredictorLoggerTest.kt b/plugins/filePrediction/test/com/intellij/filePrediction/predictor/FileUsagePredictorLoggerTest.kt index f5381371b642..27e43a2e5442 100644 --- a/plugins/filePrediction/test/com/intellij/filePrediction/predictor/FileUsagePredictorLoggerTest.kt +++ b/plugins/filePrediction/test/com/intellij/filePrediction/predictor/FileUsagePredictorLoggerTest.kt @@ -29,7 +29,7 @@ class FileUsagePredictorLoggerTest : CodeInsightFixtureTestCase