<commit_before>// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;

import com.intellij.diagnostic.ThreadDumper;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.FactoryMap;
import com.intellij.util.text.CharArrayUtil;
import gnu.trove.TLongLongHashMap;
import gnu.trove.TObjectLongHashMap;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.lang.management.*;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

class ActivityMonitorAction extends DumbAwareAction {
  private static final String[] MEANINGLESS_PREFIXES_1 = {"com.intellij.", "com.jetbrains.", "org.jetbrains.", "org.intellij."};
  private static final String[] MEANINGLESS_PREFIXES_2 = {"util.", "openapi.", "plugins.", "extapi."};

  @Override
  public void actionPerformed(@NotNull AnActionEvent e) {
    JTextArea textArea = new JTextArea(12, 100);
    textArea.setText("Loading...");
    ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
    List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
    CompilationMXBean jitBean = ManagementFactory.getCompilationMXBean();
    OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
    Method getProcessCpuTime = Objects.requireNonNull(ReflectionUtil.getMethod(osBean.getClass().getInterfaces()[0], "getProcessCpuTime"));
    ScheduledFuture<?> future = AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(new Runnable() {
      final TLongLongHashMap lastThreadTimes = new TLongLongHashMap();
      final TObjectLongHashMap<String> subsystemToSamples = new TObjectLongHashMap<>();
      long lastGcTime = totalGcTime();
      long lastProcessTime = totalProcessTime();
      long lastJitTime = jitBean.getTotalCompilationTime();
      long lastUiUpdate = System.currentTimeMillis();

      private final Map<String, String> classToSubsystem = FactoryMap.create(className -> {
        String pkg = StringUtil.getPackageName(className);
        if (pkg.isEmpty()) pkg = className;

        String prefix = getMeaninglessPrefix(pkg);
        if (!prefix.isEmpty()) {
          pkg = pkg.substring(prefix.length()) + " (in " + StringUtil.trimEnd(prefix, ".") + ")";
        }

        IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(PluginManagerCore.getPluginByClassName(className));
        return plugin != null ? "Plugin " + plugin.getName() + ": " + pkg : pkg;
      });

      private String getMeaninglessPrefix(String qname) {
        String result = findPrefix(qname, MEANINGLESS_PREFIXES_1);
        if (!result.isEmpty()) {
          result += findPrefix(qname.substring(result.length()), MEANINGLESS_PREFIXES_2);
        }
        return result;
      }

      private String findPrefix(String qname, String[] prefixes) {
        for (String prefix : prefixes) {
          if (qname.startsWith(prefix)) {
            return prefix;
          }
        }
        return "";
      }

      private long totalGcTime() {
        return gcBeans.stream().mapToLong(GarbageCollectorMXBean::getCollectionTime).sum();
      }

      private long totalProcessTime() {
        try {
          return (long)getProcessCpuTime.invoke(osBean);
        }
        catch (Exception ex) {
          return 0;
        }
      }

      @NotNull
      private String getSubsystemName(long threadId) {
        if (threadId == Thread.currentThread().getId()) {
          return "<Activity Monitor>";
        }

        ThreadInfo info = threadBean.getThreadInfo(threadId);
        if (info == null) return "<unidentified: thread finished>";

        if (info.getThreadState() == Thread.State.RUNNABLE) {
          info = threadBean.getThreadInfo(threadId, Integer.MAX_VALUE);
          if (info == null) return "<unidentified: thread finished>";

          StackTraceElement[] trace = info.getStackTrace();
          for (StackTraceElement element : trace) {
            String className = element.getClassName();
            if (!isInfrastructureClass(className)) {
              return classToSubsystem.get(className);
            }
          }
          return "<infrastructure: " + getCommonThreadName(info) + ">";
        }
        return "<unidentified: " + getCommonThreadName(info) + ">";
      }

      private String getCommonThreadName(ThreadInfo info) {
        String name = info.getThreadName();
        if (ThreadDumper.isEDT(name)) return "UI thread";

        int numberStart = CharArrayUtil.shiftBackward(name, name.length() - 1, "0123456789/ ") + 1;
        if (numberStart > 0) return name.substring(0, numberStart);
        return name;
      }

      private boolean isInfrastructureClass(String className) {
        return className.startsWith("sun.") ||
               className.startsWith("com.sun.") ||
               className.startsWith("com.yourkit.") ||
               className.startsWith("com.fasterxml.jackson.") ||
               className.startsWith("net.sf.cglib.") ||
               className.startsWith("org.jetbrains.org.objectweb.asm.") ||
               className.startsWith("org.picocontainer.") ||
               className.startsWith("net.jpountz.lz4.") ||
               className.startsWith("net.n3.nanoxml.") ||
               className.startsWith("org.apache.") ||
               className.startsWith("one.util.streamex") ||
               className.startsWith("java.") ||
               className.startsWith("gnu.") ||
               className.startsWith("kotlin.") ||
               className.startsWith("groovy.") ||
               className.startsWith("org.codehaus.groovy.") ||
               className.startsWith("org.gradle.") ||
               className.startsWith("com.google.common.") ||
               className.startsWith("com.google.gson.") ||
               className.startsWith("com.intellij.psi.impl.source.tree.") ||
               className.startsWith("com.intellij.psi.util.Cached") ||
               className.startsWith("com.intellij.openapi.extensions.") ||
               className.startsWith("com.intellij.openapi.util.") ||
               className.startsWith("com.intellij.util.") ||
               className.startsWith("com.intellij.concurrency.") ||
               className.startsWith("com.intellij.semantic.") ||
               className.startsWith("com.intellij.jam.") ||
               className.startsWith("com.intellij.psi.stubs.") ||
               className.startsWith("com.intellij.ide.IdeEventQueue") ||
               className.startsWith("com.intellij.openapi.fileTypes.") ||
               className.startsWith("com.intellij.openapi.vfs.newvfs.persistent.PersistentFS") ||
               className.startsWith("com.intellij.openapi.vfs.newvfs.persistent.FSRecords") ||
               className.startsWith("javax.");
      }

      @Override
      public void run() {
        for (long id : threadBean.getAllThreadIds()) {
          long cpuTime = threadBean.getThreadCpuTime(id);
          long prev = lastThreadTimes.put(id, cpuTime);
          if (prev != 0 && cpuTime > prev) {
            String subsystem = getSubsystemName(id);
            subsystemToSamples.put(subsystem, subsystemToSamples.get(subsystem) + cpuTime - prev);
          }
        }
        long now = System.currentTimeMillis();
        long sinceLastUpdate = now - lastUiUpdate;
        if (sinceLastUpdate > 2_000) {<commit_msg>make ActivityMonitorAction JIT-friendlier<commit_after>// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;

import com.intellij.diagnostic.ThreadDumper;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import gnu.trove.TLongLongHashMap;
import gnu.trove.TObjectLongHashMap;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.lang.management.*;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

class ActivityMonitorAction extends DumbAwareAction {
  private static final String[] MEANINGLESS_PREFIXES_1 = {"com.intellij.", "com.jetbrains.", "org.jetbrains.", "org.intellij."};
  private static final String[] MEANINGLESS_PREFIXES_2 = {"util.", "openapi.", "plugins.", "extapi."};
  private static final String[] INFRASTRUCTURE_PREFIXES = {
    "sun.",
    "com.sun.",
    "com.yourkit.",
    "com.fasterxml.jackson.",
    "net.sf.cglib.",
    "org.jetbrains.org.objectweb.asm.",
    "org.picocontainer.",
    "net.jpountz.lz4.",
    "net.n3.nanoxml.",
    "org.apache.",
    "one.util.streamex",
    "java.",
    "gnu.",
    "kotlin.",
    "groovy.",
    "org.codehaus.groovy.",
    "org.gradle.",
    "com.google.common.",
    "com.google.gson.",
    "com.intellij.psi.impl.source.tree.",
    "com.intellij.psi.util.Cached",
    "com.intellij.openapi.extensions.",
    "com.intellij.openapi.util.",
    "com.intellij.util.",
    "com.intellij.concurrency.",
    "com.intellij.semantic.",
    "com.intellij.jam.",
    "com.intellij.psi.stubs.",
    "com.intellij.ide.IdeEventQueue",
    "com.intellij.openapi.fileTypes.",
    "com.intellij.openapi.vfs.newvfs.persistent.PersistentFS",
    "com.intellij.openapi.vfs.newvfs.persistent.FSRecords",
    "javax."
  };

  @Override
  public void actionPerformed(@NotNull AnActionEvent e) {
    JTextArea textArea = new JTextArea(12, 100);
    textArea.setText("Loading...");
    ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
    List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
    CompilationMXBean jitBean = ManagementFactory.getCompilationMXBean();
    OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
    Method getProcessCpuTime = Objects.requireNonNull(ReflectionUtil.getMethod(osBean.getClass().getInterfaces()[0], "getProcessCpuTime"));
    ScheduledFuture<?> future = AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(new Runnable() {
      final TLongLongHashMap lastThreadTimes = new TLongLongHashMap();
      final TObjectLongHashMap<String> subsystemToSamples = new TObjectLongHashMap<>();
      long lastGcTime = totalGcTime();
      long lastProcessTime = totalProcessTime();
      long lastJitTime = jitBean.getTotalCompilationTime();
      long lastUiUpdate = System.currentTimeMillis();

      private final Map<String, String> classToSubsystem = new HashMap<>();

      @NotNull
      private String calcSubSystemName(String className) {
        String pkg = StringUtil.getPackageName(className);
        if (pkg.isEmpty()) pkg = className;

        String prefix = getMeaninglessPrefix(pkg);
        if (!prefix.isEmpty()) {
          pkg = pkg.substring(prefix.length()) + " (in " + StringUtil.trimEnd(prefix, ".") + ")";
        }

        IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(PluginManagerCore.getPluginByClassName(className));
        return plugin != null ? "Plugin " + plugin.getName() + ": " + pkg : pkg;
      }

      private String getMeaninglessPrefix(String qname) {
        String result = findPrefix(qname, MEANINGLESS_PREFIXES_1);
        if (!result.isEmpty()) {
          result += findPrefix(qname.substring(result.length()), MEANINGLESS_PREFIXES_2);
        }
        return result;
      }

      private String findPrefix(String qname, String[] prefixes) {
        for (String prefix : prefixes) {
          if (qname.startsWith(prefix)) {
            return prefix;
          }
        }
        return "";
      }

      private long totalGcTime() {
        return gcBeans.stream().mapToLong(GarbageCollectorMXBean::getCollectionTime).sum();
      }

      private long totalProcessTime() {
        try {
          return (long)getProcessCpuTime.invoke(osBean);
        }
        catch (Exception ex) {
          return 0;
        }
      }

      @NotNull
      private String getSubsystemName(long threadId) {
        if (threadId == Thread.currentThread().getId()) {
          return "<Activity Monitor>";
        }

        ThreadInfo info = threadBean.getThreadInfo(threadId, Integer.MAX_VALUE);
        if (info == null) return "<unidentified: thread finished>";

        boolean runnable = info.getThreadState() == Thread.State.RUNNABLE;
        if (runnable) {
          for (StackTraceElement element : info.getStackTrace()) {
            String className = element.getClassName();
            if (!isInfrastructureClass(className)) {
              return classToSubsystem.computeIfAbsent(className, this::calcSubSystemName);
            }
          }
        }
        return (runnable ? "<infrastructure: " : "<unidentified: ") + getCommonThreadName(info) + ">";
      }

      private String getCommonThreadName(ThreadInfo info) {
        String name = info.getThreadName();
        if (ThreadDumper.isEDT(name)) return "UI thread";

        int numberStart = CharArrayUtil.shiftBackward(name, name.length() - 1, "0123456789/ ") + 1;
        if (numberStart > 0) return name.substring(0, numberStart);
        return name;
      }

      private boolean isInfrastructureClass(String className) {
        return ContainerUtil.exists(INFRASTRUCTURE_PREFIXES, className::startsWith);
      }

      @Override
      public void run() {
        for (long id : threadBean.getAllThreadIds()) {
          long cpuTime = threadBean.getThreadCpuTime(id);
          long prev = lastThreadTimes.put(id, cpuTime);
          if (prev != 0 && cpuTime > prev) {
            String subsystem = getSubsystemName(id);
            subsystemToSamples.put(subsystem, subsystemToSamples.get(subsystem) + cpuTime - prev);
          }
        }
        long now = System.currentTimeMillis();
        long sinceLastUpdate = now - lastUiUpdate;
        if (sinceLastUpdate > 2_000) {
{'fraction_non_alphanumeric': 0.12146487684087058, 'fraction_numerical': 0.00547373908510361, 'mean_word_length': 3.090351812366738, 'pattern_counts': {'":': 2, '<': 23, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3231348', 'n_tokens_mistral': 4527, 'n_tokens_neox': 4424, 'n_words': 784}