mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
[evaluation-plugin] Record FUS to file
Co-authored-by: Gleb Marin <gleb.marin@jetbrains.com> Igor Davidenko <Igor.Davidenko@jetbrains.com> Merge-request: IJ-MR-139810 Merged-by: Igor Davidenko <Igor.Davidenko@jetbrains.com> GitOrigin-RevId: e6918392f03aa7eaf6f0b0c9a6ec3758a58d33d5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
39883358b0
commit
06a027d4c2
@@ -17,5 +17,10 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.core" />
|
||||
<orderEntry type="module" module-name="intellij.tools.ide.metrics.collector" />
|
||||
<orderEntry type="library" name="jackson-databind" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="intellij.platform.extensions" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics.uploader" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.ex" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.intellij.cce.fus
|
||||
|
||||
import com.intellij.cce.workspace.storages.LogsSaver
|
||||
import com.intellij.internal.statistic.eventLog.LogEventSerializer
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.util.io.delete
|
||||
import com.jetbrains.fus.reporting.model.lion3.LogEvent
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
|
||||
/**
|
||||
* Saves FUS logs of the action that will be passed in [invokeRememberingLogs] to [finalStorageDir].
|
||||
* In the resulting directory, logs will be divided into files by groups.
|
||||
*/
|
||||
class FusLogsSaver(private val finalStorageDir: Path, private val allowedGroups: List<String>? = null) : LogsSaver {
|
||||
private val temporaryFusLogsDirectory: Path = PathManager.getSystemPath().toNioPathOrNull()!! / "completion-fus-logs"
|
||||
|
||||
init {
|
||||
if (temporaryFusLogsDirectory.exists()) {
|
||||
clearTemporaryStorage()
|
||||
}
|
||||
temporaryFusLogsDirectory.createDirectory()
|
||||
require(finalStorageDir.exists())
|
||||
}
|
||||
|
||||
override fun <T> invokeRememberingLogs(action: () -> T): T {
|
||||
val logFilter: (LogEvent) -> Boolean = if (allowedGroups != null) { log -> log.group.id in allowedGroups }
|
||||
else { _ -> true }
|
||||
|
||||
val (actionResult, fusLogs) = collectingFusLogs(logFilter, action)
|
||||
val fusLogsByGroup = fusLogs.groupBy { it.group }
|
||||
for ((eventGroup, groupLogs) in fusLogsByGroup) {
|
||||
val serialisedGroupLogs = groupLogs.joinToString("\n") { LogEventSerializer.toString(it) }
|
||||
val fusGroupPath = temporaryFusLogsDirectory / eventGroup.id
|
||||
fusGroupPath.toFile().appendText(serialisedGroupLogs + "\n")
|
||||
}
|
||||
return actionResult
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
override fun save(languageName: String, trainingPercentage: Int) {
|
||||
try {
|
||||
for (sessionTemporaryRelativePath in temporaryFusLogsDirectory.walk()) {
|
||||
val sessionTemporaryPath = temporaryFusLogsDirectory / sessionTemporaryRelativePath
|
||||
val sessionId = sessionTemporaryPath.fileName
|
||||
val sessionFinalPath = obtainFinalLogsDirectory(languageName) / sessionId
|
||||
Files.move(sessionTemporaryPath, sessionFinalPath)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
clearTemporaryStorage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun obtainFinalLogsDirectory(languageName: String): Path {
|
||||
val fusFinalDirectory = finalStorageDir / languageName
|
||||
if (!fusFinalDirectory.exists()) {
|
||||
fusFinalDirectory.createDirectory()
|
||||
}
|
||||
else {
|
||||
require(fusFinalDirectory.isDirectory())
|
||||
}
|
||||
return fusFinalDirectory
|
||||
}
|
||||
|
||||
private fun clearTemporaryStorage() {
|
||||
require(temporaryFusLogsDirectory.exists())
|
||||
temporaryFusLogsDirectory.delete(true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.intellij.cce.fus
|
||||
|
||||
import com.intellij.internal.statistic.eventLog.*
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.extensions.impl.ExtensionPointImpl
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.use
|
||||
import com.jetbrains.fus.reporting.model.lion3.LogEvent
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
object MockFUSCollector {
|
||||
fun <T> collectLogEvents(parentDisposable: Disposable,
|
||||
action: () -> T): Pair<List<LogEvent>, T> {
|
||||
|
||||
val mockLoggerProvider = MockStatisticsEventLoggerProvider("ML")
|
||||
(StatisticsEventLoggerProvider.EP_NAME.point as ExtensionPointImpl<StatisticsEventLoggerProvider>)
|
||||
.maskAll(listOf(mockLoggerProvider), parentDisposable, true)
|
||||
val actionResult = action()
|
||||
return mockLoggerProvider.getLoggedEvents() to actionResult
|
||||
}
|
||||
}
|
||||
|
||||
private class MockStatisticsEventLoggerProvider(recorderId: String) : StatisticsEventLoggerProvider(recorderId,
|
||||
1,
|
||||
DEFAULT_SEND_FREQUENCY_MS,
|
||||
DEFAULT_MAX_FILE_SIZE_BYTES,
|
||||
false,
|
||||
true) {
|
||||
override val logger: MockStatisticsEventLogger = MockStatisticsEventLogger()
|
||||
|
||||
override fun isRecordEnabled(): Boolean = true
|
||||
|
||||
override fun isSendEnabled(): Boolean = false
|
||||
|
||||
fun getLoggedEvents(): List<LogEvent> = logger.logged
|
||||
|
||||
class MockStatisticsEventLogger(private val session: String = "mockSession",
|
||||
private val build: String = "999.999",
|
||||
private val bucket: String = "1",
|
||||
private val recorderVersion: String = "1") : StatisticsEventLogger {
|
||||
val logged = CopyOnWriteArrayList<LogEvent>()
|
||||
|
||||
override fun logAsync(group: EventLogGroup, eventId: String, data: Map<String, Any>, isState: Boolean): CompletableFuture<Void> {
|
||||
val eventTime = System.currentTimeMillis()
|
||||
|
||||
val event = newLogEvent(session, build, bucket, eventTime, group.id, group.version.toString(), recorderVersion, eventId, isState,
|
||||
data)
|
||||
.escape()
|
||||
logged.add(event)
|
||||
return CompletableFuture.completedFuture(null)
|
||||
}
|
||||
|
||||
override fun logAsync(group: EventLogGroup,
|
||||
eventId: String,
|
||||
dataProvider: () -> Map<String, Any>?,
|
||||
isState: Boolean): CompletableFuture<Void> {
|
||||
val data = dataProvider() ?: return CompletableFuture.completedFuture(null)
|
||||
return logAsync(group, eventId, data, isState)
|
||||
}
|
||||
|
||||
override fun computeAsync(computation: (backgroundThreadExecutor: Executor) -> Unit) {
|
||||
}
|
||||
|
||||
override fun getActiveLogFile(): EventLogFile? = null
|
||||
|
||||
override fun getLogFilesProvider(): EventLogFilesProvider = EmptyEventLogFilesProvider
|
||||
|
||||
override fun cleanup() {}
|
||||
|
||||
override fun rollOver() {}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> collectingFusLogs(logEventFilter: (LogEvent) -> Boolean, action: () -> T): Pair<T, List<LogEvent>> = Disposer.newDisposable().use { lifetime ->
|
||||
val (allFusLogs, result) = MockFUSCollector.collectLogEvents(lifetime, action)
|
||||
val mlFusLogs: List<LogEvent> = allFusLogs.filter { logEventFilter(it) }
|
||||
result to mlFusLogs
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.cce.interpreter
|
||||
|
||||
import com.intellij.cce.actions.*
|
||||
import com.intellij.cce.core.Session
|
||||
import com.intellij.cce.util.FileTextUtil.computeChecksum
|
||||
import com.intellij.cce.util.FileTextUtil.getDiff
|
||||
import java.nio.file.Paths
|
||||
import kotlin.random.Random
|
||||
|
||||
class ActionInvokingInterpreter(private val invokersFactory: InvokersFactory,
|
||||
private val handler: InterpretationHandler,
|
||||
private val filter: InterpretFilter,
|
||||
private val order: InterpretationOrder,
|
||||
private val projectPath: String?) : Interpreter {
|
||||
|
||||
override fun interpret(fileActions: FileActions, sessionHandler: (Session) -> Unit): List<Session> {
|
||||
val actionsInvoker = invokersFactory.createActionsInvoker()
|
||||
val featureInvoker = invokersFactory.createFeatureInvoker()
|
||||
val sessions = mutableListOf<Session>()
|
||||
val filePath = if (projectPath == null) fileActions.path else Paths.get(projectPath).resolve(fileActions.path).toString()
|
||||
val needToClose = !actionsInvoker.isOpen(filePath)
|
||||
val text = actionsInvoker.openFile(filePath)
|
||||
if (fileActions.checksum != computeChecksum(text)) {
|
||||
handler.onErrorOccurred(IllegalStateException("File $filePath has been modified."), fileActions.sessionsCount)
|
||||
return emptyList()
|
||||
}
|
||||
var shouldCompleteToken = filter.shouldCompleteToken()
|
||||
var isCanceled = false
|
||||
val actions = fileActions.actions.reorder(order)
|
||||
for (action in actions) {
|
||||
handler.onActionStarted(action)
|
||||
when (action) {
|
||||
is MoveCaret -> {
|
||||
actionsInvoker.moveCaret(action.offset)
|
||||
}
|
||||
is CallFeature -> {
|
||||
if (shouldCompleteToken) {
|
||||
val session = featureInvoker.callFeature(action.expectedText, action.offset, action.nodeProperties)
|
||||
sessions.add(session)
|
||||
sessionHandler(session)
|
||||
}
|
||||
isCanceled = handler.onSessionFinished(fileActions.path)
|
||||
shouldCompleteToken = filter.shouldCompleteToken()
|
||||
}
|
||||
is Rename -> actionsInvoker.rename(action.newName)
|
||||
is PrintText -> actionsInvoker.printText(action.text)
|
||||
is DeleteRange -> actionsInvoker.deleteRange(action.begin, action.end)
|
||||
is SelectRange -> actionsInvoker.selectRange(action.begin, action.end)
|
||||
is Delay -> actionsInvoker.delay(action.seconds)
|
||||
}
|
||||
if (isCanceled) break
|
||||
}
|
||||
|
||||
actionsInvoker.save()
|
||||
val resultText = actionsInvoker.getText()
|
||||
if (text != resultText) {
|
||||
actionsInvoker.deleteRange(0, resultText.length)
|
||||
actionsInvoker.printText(text)
|
||||
if (needToClose) actionsInvoker.closeFile(filePath)
|
||||
throw IllegalStateException("Text before and after interpretation doesn't match. Diff:\n${getDiff(text, resultText)}")
|
||||
}
|
||||
if (needToClose) actionsInvoker.closeFile(filePath)
|
||||
handler.onFileProcessed(fileActions.path)
|
||||
return sessions.sortedBy { it.offset }
|
||||
}
|
||||
|
||||
private fun List<Action>.reorder(order: InterpretationOrder): List<Action> {
|
||||
val groups = groupBy { it.sessionId }.values
|
||||
return when (order) {
|
||||
InterpretationOrder.LINEAR -> groups.flatten()
|
||||
InterpretationOrder.REVERSED -> groups.reversed().flatten()
|
||||
InterpretationOrder.RANDOM -> groups.shuffled(ORDER_RANDOM).flatten()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val ORDER_RANDOM = Random(42)
|
||||
@@ -3,76 +3,7 @@ package com.intellij.cce.interpreter
|
||||
|
||||
import com.intellij.cce.actions.*
|
||||
import com.intellij.cce.core.Session
|
||||
import com.intellij.cce.util.FileTextUtil.computeChecksum
|
||||
import com.intellij.cce.util.FileTextUtil.getDiff
|
||||
import java.nio.file.Paths
|
||||
import kotlin.random.Random
|
||||
|
||||
class Interpreter(private val invokersFactory: InvokersFactory,
|
||||
private val handler: InterpretationHandler,
|
||||
private val filter: InterpretFilter,
|
||||
private val order: InterpretationOrder,
|
||||
private val projectPath: String?) {
|
||||
|
||||
fun interpret(fileActions: FileActions, sessionHandler: (Session) -> Unit): List<Session> {
|
||||
val actionsInvoker = invokersFactory.createActionsInvoker()
|
||||
val featureInvoker = invokersFactory.createFeatureInvoker()
|
||||
val sessions = mutableListOf<Session>()
|
||||
val filePath = if (projectPath == null) fileActions.path else Paths.get(projectPath).resolve(fileActions.path).toString()
|
||||
val needToClose = !actionsInvoker.isOpen(filePath)
|
||||
val text = actionsInvoker.openFile(filePath)
|
||||
if (fileActions.checksum != computeChecksum(text)) {
|
||||
handler.onErrorOccurred(IllegalStateException("File $filePath has been modified."), fileActions.sessionsCount)
|
||||
return emptyList()
|
||||
}
|
||||
var shouldCompleteToken = filter.shouldCompleteToken()
|
||||
var isCanceled = false
|
||||
val actions = fileActions.actions.reorder(order)
|
||||
for (action in actions) {
|
||||
handler.onActionStarted(action)
|
||||
when (action) {
|
||||
is MoveCaret -> {
|
||||
actionsInvoker.moveCaret(action.offset)
|
||||
}
|
||||
is CallFeature -> {
|
||||
if (shouldCompleteToken) {
|
||||
val session = featureInvoker.callFeature(action.expectedText, action.offset, action.nodeProperties)
|
||||
sessions.add(session)
|
||||
sessionHandler(session)
|
||||
}
|
||||
isCanceled = handler.onSessionFinished(fileActions.path)
|
||||
shouldCompleteToken = filter.shouldCompleteToken()
|
||||
}
|
||||
is Rename -> actionsInvoker.rename(action.newName)
|
||||
is PrintText -> actionsInvoker.printText(action.text)
|
||||
is DeleteRange -> actionsInvoker.deleteRange(action.begin, action.end)
|
||||
is SelectRange -> actionsInvoker.selectRange(action.begin, action.end)
|
||||
is Delay -> actionsInvoker.delay(action.seconds)
|
||||
}
|
||||
if (isCanceled) break
|
||||
}
|
||||
|
||||
actionsInvoker.save()
|
||||
val resultText = actionsInvoker.getText()
|
||||
if (text != resultText) {
|
||||
actionsInvoker.deleteRange(0, resultText.length)
|
||||
actionsInvoker.printText(text)
|
||||
if (needToClose) actionsInvoker.closeFile(filePath)
|
||||
throw IllegalStateException("Text before and after interpretation doesn't match. Diff:\n${getDiff(text, resultText)}")
|
||||
}
|
||||
if (needToClose) actionsInvoker.closeFile(filePath)
|
||||
handler.onFileProcessed(fileActions.path)
|
||||
return sessions.sortedBy { it.offset }
|
||||
}
|
||||
|
||||
private fun List<Action>.reorder(order: InterpretationOrder): List<Action> {
|
||||
val groups = groupBy { it.sessionId }.values
|
||||
return when (order) {
|
||||
InterpretationOrder.LINEAR -> groups.flatten()
|
||||
InterpretationOrder.REVERSED -> groups.reversed().flatten()
|
||||
InterpretationOrder.RANDOM -> groups.shuffled(ORDER_RANDOM).flatten()
|
||||
}
|
||||
}
|
||||
interface Interpreter {
|
||||
fun interpret(fileActions: FileActions, sessionHandler: (Session) -> Unit): List<Session>
|
||||
}
|
||||
|
||||
private val ORDER_RANDOM = Random(42)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.intellij.cce.interpreter
|
||||
|
||||
import com.intellij.cce.actions.FileActions
|
||||
import com.intellij.cce.core.Session
|
||||
import com.intellij.cce.workspace.storages.LogsSaver
|
||||
|
||||
class LoggingInterpreterWrapper(private val baseInterpreter: Interpreter, private val logsSaver: LogsSaver) : Interpreter {
|
||||
override fun interpret(fileActions: FileActions, sessionHandler: (Session) -> Unit): List<Session> {
|
||||
return logsSaver.invokeRememberingLogs {
|
||||
baseInterpreter.interpret(fileActions, sessionHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Interpreter.wrapLogging(logsSaver: LogsSaver): Interpreter = LoggingInterpreterWrapper(this, logsSaver)
|
||||
@@ -83,6 +83,7 @@ data class Config private constructor(
|
||||
val sessionSeed: Long?,
|
||||
val order: InterpretationOrder,
|
||||
val saveLogs: Boolean,
|
||||
val saveFusLogs: Boolean,
|
||||
val saveFeatures: Boolean,
|
||||
val saveContent: Boolean,
|
||||
val logLocationAndItemText: Boolean,
|
||||
@@ -122,6 +123,7 @@ data class Config private constructor(
|
||||
var outputDir: String = Paths.get(projectPath, "completion-evaluation").toAbsolutePath().toString()
|
||||
var strategy: EvaluationStrategy = EvaluationStrategy.defaultStrategy
|
||||
var saveLogs = false
|
||||
var saveFusLogs = false
|
||||
var saveFeatures = true
|
||||
var saveContent = false
|
||||
var logLocationAndItemText = false
|
||||
@@ -147,6 +149,7 @@ data class Config private constructor(
|
||||
evaluationRoots.addAll(config.actions.evaluationRoots)
|
||||
ignoreFileNames.addAll(config.actions.ignoreFileNames)
|
||||
saveLogs = config.interpret.saveLogs
|
||||
saveFusLogs = config.interpret.saveFusLogs
|
||||
saveFeatures = config.interpret.saveFeatures
|
||||
saveContent = config.interpret.saveContent
|
||||
logLocationAndItemText = config.interpret.logLocationAndItemText
|
||||
@@ -195,6 +198,7 @@ data class Config private constructor(
|
||||
sessionSeed,
|
||||
order,
|
||||
saveLogs,
|
||||
saveFusLogs,
|
||||
saveFeatures,
|
||||
saveContent,
|
||||
logLocationAndItemText,
|
||||
|
||||
@@ -88,6 +88,7 @@ object ConfigFactory {
|
||||
builder.order = InterpretationOrder.valueOf(map.getAs<String>("order"))
|
||||
}
|
||||
builder.saveLogs = map.getAs("saveLogs")
|
||||
builder.saveFusLogs = map.getAs("saveFusLogs")
|
||||
if (map.containsKey("saveFeatures")) {
|
||||
builder.saveFeatures = map.getAs("saveFeatures")
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.cce.workspace
|
||||
import com.google.gson.Gson
|
||||
import com.intellij.cce.evaluable.EvaluationStrategy
|
||||
import com.intellij.cce.evaluable.StrategySerializer
|
||||
import com.intellij.cce.fus.FusLogsSaver
|
||||
import com.intellij.cce.workspace.storages.*
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.Files
|
||||
@@ -12,25 +13,25 @@ import java.nio.file.Paths
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class EvaluationWorkspace private constructor(private val basePath: Path) {
|
||||
class EvaluationWorkspace private constructor(private val basePath: Path,
|
||||
statsLogsPath: Path) {
|
||||
companion object {
|
||||
private const val DEFAULT_REPORT_TYPE = "html"
|
||||
private val gson = Gson()
|
||||
private val formatter = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss")
|
||||
|
||||
fun open(workspaceDir: String): EvaluationWorkspace {
|
||||
return EvaluationWorkspace(Paths.get(workspaceDir).toAbsolutePath())
|
||||
fun open(workspaceDir: String, statsLogsPath: Path): EvaluationWorkspace {
|
||||
return EvaluationWorkspace(Paths.get(workspaceDir).toAbsolutePath(), statsLogsPath)
|
||||
}
|
||||
|
||||
fun create(config: Config): EvaluationWorkspace {
|
||||
val workspace = EvaluationWorkspace(Paths.get(config.outputDir).toAbsolutePath().resolve(formatter.format(Date())))
|
||||
fun create(config: Config, statsLogsPath: Path): EvaluationWorkspace {
|
||||
val workspace = EvaluationWorkspace(Paths.get(config.outputDir).toAbsolutePath().resolve(formatter.format(Date())), statsLogsPath)
|
||||
workspace.writeConfig(config)
|
||||
return workspace
|
||||
}
|
||||
}
|
||||
|
||||
private val sessionsDir = subdir("data")
|
||||
private val logsDir = subdir("logs")
|
||||
private val fullLineLogsDir = subdir("full-line-logs")
|
||||
private val featuresDir = subdir("features")
|
||||
private val actionsDir = subdir("actions")
|
||||
@@ -45,7 +46,9 @@ class EvaluationWorkspace private constructor(private val basePath: Path) {
|
||||
|
||||
val errorsStorage: FileErrorsStorage = FileErrorsStorage(errorsDir.toString())
|
||||
|
||||
val logsStorage: LogsStorage = LogsStorage(logsDir.toString())
|
||||
val statLogsSaver: StatLogsSaver = StatLogsSaver(statsLogsPath, subdir("logs"))
|
||||
|
||||
val fusLogsSaver: LogsSaver = FusLogsSaver(subdir("fus-logs"))
|
||||
|
||||
val featuresStorage: FeaturesStorage = FeaturesStorageImpl(featuresDir.toString())
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.intellij.cce.workspace.storages
|
||||
|
||||
interface LogsSaver {
|
||||
fun <T> invokeRememberingLogs(action: () -> T): T
|
||||
|
||||
fun save(languageName: String, trainingPercentage: Int)
|
||||
}
|
||||
|
||||
class NoLogsSaver : LogsSaver {
|
||||
override fun <T> invokeRememberingLogs(action: () -> T): T = action()
|
||||
|
||||
override fun save(languageName: String, trainingPercentage: Int) = Unit
|
||||
}
|
||||
|
||||
fun logsSaverIf(condition: Boolean, createSaver: () -> LogsSaver): LogsSaver = if (condition) createSaver() else NoLogsSaver()
|
||||
|
||||
private fun makeNestingCollector(saverA: LogsSaver,
|
||||
saverB: LogsSaver
|
||||
) = object : LogsSaver {
|
||||
override fun <T> invokeRememberingLogs(action: () -> T): T {
|
||||
return saverA.invokeRememberingLogs {
|
||||
saverB.invokeRememberingLogs(action)
|
||||
}
|
||||
}
|
||||
|
||||
override fun save(languageName: String, trainingPercentage: Int) {
|
||||
try {
|
||||
saverA.save(languageName, trainingPercentage)
|
||||
}
|
||||
finally {
|
||||
saverB.save(languageName, trainingPercentage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Collection<LogsSaver>.asCompositeLogsSaver(): LogsSaver {
|
||||
val meaningfulSavers = this@asCompositeLogsSaver.filter { it !is NoLogsSaver }
|
||||
val meaningfulLogsSavers: List<LogsSaver> = meaningfulSavers.ifEmpty { listOf(NoLogsSaver()) }
|
||||
|
||||
return meaningfulLogsSavers.reduce(::makeNestingCollector)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
package com.intellij.cce.workspace.storages
|
||||
|
||||
@@ -2,31 +2,33 @@
|
||||
package com.intellij.cce.workspace.storages
|
||||
|
||||
import java.io.BufferedWriter
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.GZIPInputStream
|
||||
import kotlin.io.path.div
|
||||
|
||||
class LogsStorage(private val storageDir: String) {
|
||||
class StatLogsSaver(private val logsTemporaryStoragePath: Path, private val finalStorageDir: Path) : LogsSaver {
|
||||
private val formatter = SimpleDateFormat("dd_MM_yyyy")
|
||||
private val sessionIds = linkedSetOf<String>()
|
||||
|
||||
val path = storageDir
|
||||
override fun <T> invokeRememberingLogs(action: () -> T): T = action()
|
||||
|
||||
fun save(logsPath: String, languageName: String, trainingPercentage: Int) {
|
||||
val logsDir = File(logsPath)
|
||||
override fun save(languageName: String, trainingPercentage: Int) {
|
||||
val logsDir = logsTemporaryStoragePath.toFile()
|
||||
if (!logsDir.exists()) return
|
||||
val outputDir = Paths.get(storageDir, languageName)
|
||||
require(logsDir.isDirectory)
|
||||
val outputDir = finalStorageDir / languageName
|
||||
Files.createDirectories(outputDir)
|
||||
FileWriter(Paths.get(outputDir.toString(), "full.log").toString()).use { writer ->
|
||||
for (logChunk in (logsDir.listFiles() ?: emptyArray())
|
||||
.filter { it.name.startsWith("chunk") }
|
||||
.map { it.name.toString() }
|
||||
.sortedBy { it.substringAfterLast('_').substringBefore(".gz").toInt() }) {
|
||||
val chunkPath = Paths.get(logsPath, logChunk)
|
||||
val chunkPath = logsTemporaryStoragePath / logChunk
|
||||
if (Files.exists(chunkPath)) {
|
||||
val log = GZIPInputStream(chunkPath.toFile().readBytes().inputStream()).reader().readText()
|
||||
sessionIds.addAll(log.split("\n").filter { it.isNotBlank() }.map { getSessionId(it) })
|
||||
@@ -36,7 +38,7 @@ class LogsStorage(private val storageDir: String) {
|
||||
}
|
||||
}
|
||||
saveLogs(outputDir.toString(), trainingPercentage)
|
||||
File(storageDir).compress()
|
||||
finalStorageDir.toFile().compress()
|
||||
}
|
||||
|
||||
private fun saveLogs(outputDir: String, trainingPercentage: Int) {
|
||||
@@ -13,5 +13,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.ide" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
|
||||
<orderEntry type="module" module-name="intellij.evaluationPlugin.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics.uploader" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -15,6 +15,7 @@ import com.intellij.cce.evaluable.StrategySerializer
|
||||
import com.intellij.cce.evaluation.BackgroundStepFactory
|
||||
import com.intellij.cce.evaluation.EvaluationProcess
|
||||
import com.intellij.cce.evaluation.EvaluationRootInfo
|
||||
import com.intellij.cce.evaluation.step.SetupStatsCollectorStep
|
||||
import com.intellij.cce.util.ExceptionsUtil.stackTraceToString
|
||||
import com.intellij.cce.workspace.ConfigFactory
|
||||
import com.intellij.cce.workspace.EvaluationWorkspace
|
||||
@@ -109,7 +110,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter {
|
||||
override fun run() {
|
||||
val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the $featureName")
|
||||
val config = loadConfig(Paths.get(configPath), feature.getStrategySerializer())
|
||||
val workspace = EvaluationWorkspace.create(config)
|
||||
val workspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
runPreliminarySteps(feature, workspace)
|
||||
loadAndApply(config.projectPath) { project ->
|
||||
val stepFactory = BackgroundStepFactory(feature, config, project, null, EvaluationRootInfo(true))
|
||||
@@ -148,7 +149,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter {
|
||||
|
||||
override fun run() {
|
||||
val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the feature")
|
||||
val workspace = EvaluationWorkspace.open(workspacePath)
|
||||
val workspace = EvaluationWorkspace.open(workspacePath, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
val config = workspace.readConfig(feature.getStrategySerializer())
|
||||
runPreliminarySteps(feature, workspace)
|
||||
loadAndApply(config.projectPath) { project ->
|
||||
@@ -170,11 +171,11 @@ internal class CompletionEvaluationStarter : ApplicationStarter {
|
||||
override fun run() {
|
||||
val workspacesToCompare = getWorkspaces()
|
||||
val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the feature")
|
||||
val config = workspacesToCompare.map { EvaluationWorkspace.open(it) }.buildMultipleEvaluationsConfig(
|
||||
val config = workspacesToCompare.map { EvaluationWorkspace.open(it, SetupStatsCollectorStep.statsCollectorLogsDirectory) }.buildMultipleEvaluationsConfig(
|
||||
feature.getStrategySerializer(),
|
||||
"COMPARING",
|
||||
)
|
||||
val outputWorkspace = EvaluationWorkspace.create(config)
|
||||
val outputWorkspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
loadAndApply(config.projectPath) { project ->
|
||||
val process = EvaluationProcess.build({
|
||||
shouldGenerateReports = true
|
||||
@@ -207,12 +208,12 @@ internal class CompletionEvaluationStarter : ApplicationStarter {
|
||||
override fun run() {
|
||||
val workspacesToMerge = readWorkspacesFromDirectory(root)
|
||||
val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the feature")
|
||||
val config = workspacesToMerge.map { EvaluationWorkspace.open(it) }.buildMultipleEvaluationsConfig(
|
||||
val config = workspacesToMerge.map { EvaluationWorkspace.open(it, SetupStatsCollectorStep.statsCollectorLogsDirectory) }.buildMultipleEvaluationsConfig(
|
||||
feature.getStrategySerializer()
|
||||
)
|
||||
val outputWorkspace = EvaluationWorkspace.create(config)
|
||||
val outputWorkspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
for (workspacePath in workspacesToMerge) {
|
||||
val workspace = EvaluationWorkspace.open(workspacePath)
|
||||
val workspace = EvaluationWorkspace.open(workspacePath, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
val sessionFiles = workspace.sessionsStorage.getSessionFiles()
|
||||
for (sessionFile in sessionFiles) {
|
||||
outputWorkspace.sessionsStorage.saveSessions(workspace.sessionsStorage.getSessions(sessionFile.first))
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.intellij.cce.evaluable.common.getEditorSafe
|
||||
import com.intellij.cce.evaluable.completion.BaseCompletionActionsInvoker
|
||||
import com.intellij.cce.evaluation.*
|
||||
import com.intellij.cce.evaluation.step.ActionsGenerationStep
|
||||
import com.intellij.cce.evaluation.step.SetupStatsCollectorStep
|
||||
import com.intellij.cce.filter.EvaluationFilter
|
||||
import com.intellij.cce.filter.EvaluationFilterReader
|
||||
import com.intellij.cce.interpreter.FeatureInvoker
|
||||
@@ -55,7 +56,7 @@ internal class ContextCollectionEvaluationCommand : CompletionEvaluationStarter.
|
||||
override fun run() {
|
||||
val feature = EvaluableFeature.forFeature(featureName) ?: error("There is no support for the $featureName")
|
||||
val config = loadConfig(Paths.get(configPath), feature.getStrategySerializer())
|
||||
val workspace = EvaluationWorkspace.create(config)
|
||||
val workspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
val evaluationRootInfo = EvaluationRootInfo(true)
|
||||
loadAndApply(config.projectPath) { project ->
|
||||
val stepFactory = object : StepFactory by BackgroundStepFactory(
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
package com.intellij.cce.evaluation
|
||||
|
||||
import com.intellij.cce.evaluation.step.SetupStatsCollectorStep
|
||||
import com.intellij.cce.interpreter.InterpretFilter
|
||||
import com.intellij.cce.interpreter.InterpretationHandlerImpl
|
||||
import com.intellij.cce.interpreter.Interpreter
|
||||
import com.intellij.cce.interpreter.InvokersFactory
|
||||
import com.intellij.cce.interpreter.*
|
||||
import com.intellij.cce.util.ExceptionsUtil
|
||||
import com.intellij.cce.util.FilesHelper
|
||||
import com.intellij.cce.util.Progress
|
||||
@@ -15,6 +12,9 @@ import com.intellij.cce.workspace.EvaluationWorkspace
|
||||
import com.intellij.cce.workspace.info.FileErrorInfo
|
||||
import com.intellij.cce.workspace.info.FileSessionsInfo
|
||||
import com.intellij.cce.workspace.storages.FeaturesStorage
|
||||
import com.intellij.cce.workspace.storages.LogsSaver
|
||||
import com.intellij.cce.workspace.storages.asCompositeLogsSaver
|
||||
import com.intellij.cce.workspace.storages.logsSaverIf
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlin.math.roundToInt
|
||||
@@ -26,10 +26,16 @@ class ActionsInterpretationHandler(
|
||||
private val language: String,
|
||||
private val invokersFactory: InvokersFactory,
|
||||
private val project: Project) : TwoWorkspaceHandler {
|
||||
|
||||
companion object {
|
||||
val LOG = Logger.getInstance(ActionsInterpretationHandler::class.java)
|
||||
}
|
||||
|
||||
private fun createLogsSaver(workspace: EvaluationWorkspace): LogsSaver = listOf(
|
||||
logsSaverIf(config.interpret.saveLogs) { workspace.statLogsSaver },
|
||||
logsSaverIf(config.interpret.saveFusLogs) { workspace.fusLogsSaver }
|
||||
).asCompositeLogsSaver()
|
||||
|
||||
override fun invoke(workspace1: EvaluationWorkspace, workspace2: EvaluationWorkspace, indicator: Progress) {
|
||||
var sessionsCount: Int
|
||||
val computingTime = measureTimeMillis {
|
||||
@@ -37,12 +43,14 @@ class ActionsInterpretationHandler(
|
||||
}
|
||||
LOG.info("Computing of sessions count took $computingTime ms")
|
||||
val interpretationConfig = config.interpret
|
||||
val logsSaver = createLogsSaver(workspace2)
|
||||
val handler = InterpretationHandlerImpl(indicator, sessionsCount, interpretationConfig.sessionsLimit)
|
||||
val filter =
|
||||
if (interpretationConfig.sessionProbability < 1)
|
||||
RandomInterpretFilter(interpretationConfig.sessionProbability, interpretationConfig.sessionSeed)
|
||||
else InterpretFilter.default()
|
||||
val interpreter = Interpreter(invokersFactory, handler, filter, config.interpret.order, project.basePath)
|
||||
val interpreter = ActionInvokingInterpreter(invokersFactory, handler, filter, config.interpret.order, project.basePath)
|
||||
.wrapLogging(logsSaver)
|
||||
val featuresStorage = if (interpretationConfig.saveFeatures) workspace2.featuresStorage else FeaturesStorage.EMPTY
|
||||
LOG.info("Start interpreting actions")
|
||||
if (interpretationConfig.sessionProbability < 1) {
|
||||
@@ -75,7 +83,7 @@ class ActionsInterpretationHandler(
|
||||
}
|
||||
if (handler.isCancelled() || handler.isLimitExceeded()) break
|
||||
}
|
||||
if (interpretationConfig.saveLogs) workspace2.logsStorage.save(SetupStatsCollectorStep.statsCollectorLogsDirectory(), language, interpretationConfig.trainTestSplit)
|
||||
logsSaver.save(language, config.interpret.trainTestSplit)
|
||||
SetupStatsCollectorStep.deleteLogs()
|
||||
workspace2.saveMetadata()
|
||||
LOG.info("Interpreting actions completed")
|
||||
|
||||
@@ -36,7 +36,7 @@ class BackgroundStepFactory(
|
||||
ActionsInterpretationStep(config, config.language, invokersFactory, project)
|
||||
|
||||
override fun generateReportStep(): EvaluationStep =
|
||||
ReportGenerationStep(inputWorkspacePaths?.map { EvaluationWorkspace.open(it) },
|
||||
ReportGenerationStep(inputWorkspacePaths?.map { EvaluationWorkspace.open(it, SetupStatsCollectorStep.statsCollectorLogsDirectory) },
|
||||
config.reports.sessionsFilters, config.reports.comparisonFilters, project, feature)
|
||||
|
||||
override fun interpretActionsOnNewWorkspaceStep(): EvaluationStep =
|
||||
|
||||
@@ -16,7 +16,7 @@ import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.concurrency.FutureResult
|
||||
|
||||
abstract class BackgroundEvaluationStep(protected val project: Project) : EvaluationStep {
|
||||
abstract class BackgroundEvaluationStep(val project: Project) : EvaluationStep {
|
||||
protected companion object {
|
||||
val LOG = Logger.getInstance(BackgroundEvaluationStep::class.java)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ abstract class CreateWorkspaceStep(
|
||||
project: Project) : BackgroundEvaluationStep(project) {
|
||||
|
||||
override fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace {
|
||||
val newWorkspace = EvaluationWorkspace.create(config)
|
||||
val newWorkspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory)
|
||||
handler.invoke(workspace, newWorkspace, progress)
|
||||
return newWorkspace
|
||||
}
|
||||
|
||||
@@ -13,27 +13,27 @@ import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.runAndLogException
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.serviceContainer.ComponentManagerImpl
|
||||
import com.intellij.stats.completion.sender.StatisticSender
|
||||
import com.intellij.stats.completion.storage.FilePathProvider
|
||||
import com.intellij.stats.completion.storage.UniqueFilesProvider
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
class SetupStatsCollectorStep(private val experimentGroup: Int?,
|
||||
private val logLocationAndTextItem: Boolean) : UndoableEvaluationStep {
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(SetupStatsCollectorStep::class.java)
|
||||
private val LOG = thisLogger()
|
||||
private const val SEND_LOGS_KEY = "completion.stats.send.logs"
|
||||
private const val STATS_COLLECTOR_ID = "com.intellij.stats.completion"
|
||||
private const val COLLECT_LOGS_HEADLESS_KEY = "completion.evaluation.headless"
|
||||
fun statsCollectorLogsDirectory(): String = Paths.get(PathManager.getSystemPath(), "completion-stats-data").toString()
|
||||
val statsCollectorLogsDirectory: Path = Paths.get(PathManager.getSystemPath(), "completion-stats-data")
|
||||
|
||||
fun deleteLogs() {
|
||||
val logsDirectory = File(statsCollectorLogsDirectory())
|
||||
val logsDirectory = statsCollectorLogsDirectory.toFile()
|
||||
if (logsDirectory.exists()) {
|
||||
logsDirectory.deleteRecursively()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user