[performance] IJPL-173892 FUS: add project count, oom error flag and last action to low.memory events

(cherry picked from commit 048a9136700b3d9741cd21cb74260e9a8e62a16b)
IJ-CR-151911

GitOrigin-RevId: d0a323177357b21ec1a0db98ab699c6a4fb5eb15
This commit is contained in:
Yuriy Artamonov
2024-12-18 07:32:38 +01:00
committed by intellij-monorepo-bot
parent 2584933ede
commit c388c9cc0e
5 changed files with 61 additions and 14 deletions

View File

@@ -71,7 +71,7 @@ public final class DefaultIdeaErrorLogger {
var kind = getOOMErrorKind(event.getThrowable());
if (kind != null) {
ourOomOccurred = true;
LowMemoryNotifier.showNotification(kind, true, true);
LowMemoryNotifier.showNotification(kind, true);
}
else if (!ourOomOccurred) {
MessagePool.getInstance().addIdeFatalMessage(event);

View File

@@ -4,6 +4,8 @@ package com.intellij.diagnostic
import com.intellij.diagnostic.VMOptions.MemoryKind
import com.intellij.diagnostic.opentelemetry.SafepointBean
import com.intellij.ide.PowerSaveMode
import com.intellij.idea.IdeaLogger
import com.intellij.internal.statistic.collectors.fus.actions.persistence.ActionsEventLogGroup
import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.events.*
import com.intellij.internal.statistic.eventLog.events.EventFields.Boolean
@@ -124,7 +126,7 @@ private class IdeHeartbeatEventReporterService(cs: CoroutineScope) {
}
internal object UILatencyLogger : CounterUsagesCollector() {
private val GROUP = EventLogGroup("performance", 74)
private val GROUP = EventLogGroup("performance", 75)
internal val SYSTEM_CPU_LOAD: IntEventField = Int("system_cpu_load")
internal val SWAP_LOAD: IntEventField = Int("swap_load")
@@ -172,10 +174,22 @@ internal object UILatencyLogger : CounterUsagesCollector() {
@JvmField
val MAIN_MENU_LATENCY: EventId1<Long> = GROUP.registerEvent("mainmenu.latency", EventFields.DurationMs)
private val MEMORY_TYPE_FIELD = Enum("type", MemoryKind::class.java)
private val HEAP_SIZE_FIELD = Int("heap_size_gigabytes")
private val PROJECT_COUNT_FIELD = Int("project_count")
private val IS_OOM_HAPPENED_FIELD = Boolean("oom_error")
private val IS_FROM_CRASH_FIELD = Boolean("oom_crash")
private val LAST_ACTION_FIELD = ActionsEventLogGroup.ActionIdField("last_action_id")
@JvmField
val LOW_MEMORY_CONDITION: EventId2<MemoryKind, Int> = GROUP.registerEvent("low.memory",
Enum("type", MemoryKind::class.java),
Int("heap_size_gigabytes"))
val LOW_MEMORY_CONDITION: VarargEventId = GROUP.registerVarargEvent("low.memory",
MEMORY_TYPE_FIELD,
HEAP_SIZE_FIELD,
PROJECT_COUNT_FIELD,
IS_OOM_HAPPENED_FIELD,
IS_FROM_CRASH_FIELD,
LAST_ACTION_FIELD,
EventFields.Dumb)
// ==== JVMResponsivenessMonitor: overall system run-time-variability sampling
@@ -217,7 +231,22 @@ internal object UILatencyLogger : CounterUsagesCollector() {
}
@JvmStatic
fun lowMemory(kind: MemoryKind, currentXmxMegabytes: Int) {
LOW_MEMORY_CONDITION.log(kind, (currentXmxMegabytes.toDouble() / 1024).roundToInt())
fun lowMemory(
kind: MemoryKind,
currentXmxMegabytes: Int,
projectCount: Int,
oomError: Boolean,
fromCrashReport: Boolean,
dumbMode: Boolean,
) {
LOW_MEMORY_CONDITION.log(
MEMORY_TYPE_FIELD.with(kind),
HEAP_SIZE_FIELD.with((currentXmxMegabytes.toDouble() / 1024).roundToInt()),
PROJECT_COUNT_FIELD.with(projectCount),
IS_OOM_HAPPENED_FIELD.with(oomError),
IS_FROM_CRASH_FIELD.with(fromCrashReport),
LAST_ACTION_FIELD.with(IdeaLogger.ourLastActionId),
EventFields.Dumb.with(dumbMode)
)
}
}

View File

@@ -10,7 +10,11 @@ import com.intellij.notification.NotificationAction;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
@@ -21,24 +25,35 @@ final class LowMemoryNotifier implements Disposable {
private static final Set<VMOptions.MemoryKind> ourNotifications = ConcurrentCollectionFactory.createConcurrentSet();
private final LowMemoryWatcher myWatcher =
LowMemoryWatcher.register(() -> showNotification(VMOptions.MemoryKind.HEAP, false, true), ONLY_AFTER_GC);
LowMemoryWatcher.register(() -> showNotification(VMOptions.MemoryKind.HEAP, false), ONLY_AFTER_GC);
@Override
public void dispose() {
myWatcher.stop();
}
static void showNotification(@NotNull VMOptions.MemoryKind kind, boolean error, boolean suggestAnalyzing) {
static void showNotificationFromCrashAnalysis() {
showNotification(VMOptions.MemoryKind.HEAP, true, true);
}
static void showNotification(@NotNull VMOptions.MemoryKind kind, boolean oomError) {
showNotification(kind, oomError, false);
}
private static void showNotification(@NotNull VMOptions.MemoryKind kind, boolean oomError, boolean fromCrashReport) {
if (!ourNotifications.add(kind)) return;
int currentXmx = VMOptions.readOption(VMOptions.MemoryKind.HEAP, true);
UILatencyLogger.lowMemory(kind, currentXmx);
Project[] projects = ProjectManager.getInstance().getOpenProjects();
int projectCount = projects.length;
boolean isDumb = ContainerUtil.exists(projects, p -> DumbService.isDumb(p));
UILatencyLogger.lowMemory(kind, currentXmx, projectCount, oomError, fromCrashReport, isDumb);
var message = error ? IdeBundle.message("low.memory.notification.error", kind.label()) : IdeBundle.message("low.memory.notification.warning");
var type = error ? NotificationType.ERROR : NotificationType.WARNING;
var message = oomError ? IdeBundle.message("low.memory.notification.error", kind.label()) : IdeBundle.message("low.memory.notification.warning");
var type = oomError ? NotificationType.ERROR : NotificationType.WARNING;
var notification = new Notification("Low Memory", IdeBundle.message("low.memory.notification.title"), message, type);
if (suggestAnalyzing) {
if (!fromCrashReport) {
notification.addAction(NotificationAction.createSimpleExpiring(IdeBundle.message("low.memory.notification.analyze.action"), () ->
new HeapDumpSnapshotRunnable(MemoryReportReason.UserInvoked,
HeapDumpSnapshotRunnable.AnalysisOption.SCHEDULE_ON_NEXT_START).run()));

View File

@@ -531,7 +531,7 @@ private suspend fun reportCrashesIfAny() {
if (crashInfo.extraJvmLog != null) {
// Detect crashes caused by OOME
if (crashInfo.extraJvmLog.contains("java.lang.OutOfMemoryError: Java heap space")) {
LowMemoryNotifier.showNotification(VMOptions.MemoryKind.HEAP, true, false)
LowMemoryNotifier.showNotificationFromCrashAnalysis()
}
attachments += Attachment("jbr_err.txt", crashInfo.extraJvmLog).also { it.isIncluded = true }
}

View File

@@ -127,4 +127,7 @@ object ActionsEventLogGroup : CounterUsagesCollector() {
"custom.action.invoked",
ACTION_ID,
EventFields.InputEvent)
@Suppress("FunctionName")
internal fun ActionIdField(name: String): PrimitiveEventField<String?> = ActionIdEventField(name)
}