content: package com.taobao.arthas.core.command.monitor200;
  
  
  import java.lang.reflect.Method;
  import java.nio.ByteBuffer;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  
  import com.alibaba.arthas.deps.org.slf4j.Logger;
  import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
  import com.taobao.arthas.common.JavaVersionUtils;
  import com.taobao.arthas.common.PidUtils;
  import com.taobao.arthas.core.command.Constants;
  import com.taobao.arthas.core.command.model.PerfCounterModel;
  import com.taobao.arthas.core.command.model.PerfCounterVO;
  import com.taobao.arthas.core.shell.command.AnnotatedCommand;
  import com.taobao.arthas.core.shell.command.CommandProcess;
  import com.taobao.middleware.cli.annotations.Description;
  import com.taobao.middleware.cli.annotations.Name;
  import com.taobao.middleware.cli.annotations.Option;
  import com.taobao.middleware.cli.annotations.Summary;
  
  import sun.management.counter.Counter;
  import sun.management.counter.perf.PerfInstrumentation;
  
  /**
   * @see sun.misc.Perf
   * @see jdk.internal.perf.Perf
   * @see sun.management.counter.perf.PerfInstrumentation
   * @author hengyunabc 2020-02-16
   */
  @Name("perfcounter")
  @Summary("Display the perf counter information.")
  @Description("\nExamples:\n" +
          "  perfcounter\n" +
          "  perfcounter -d\n" +
          Constants.WIKI + Constants.WIKI_HOME + "perfcounter")
  public class PerfCounterCommand extends AnnotatedCommand {
      private static final Logger logger = LoggerFactory.getLogger(PerfCounterCommand.class);
      private static Object perfObject;
      private static Method attachMethod;
  
      private boolean details;
  
      @Option(shortName = "d", longName = "details", flag = true)
      @Description("print all perf counter details")
      public void setDetails(boolean details) {
          this.details = details;
      }
  
      @Override
      public void process(CommandProcess process) {
          List<Counter> perfCounters = getPerfCounters();
          if (perfCounters.isEmpty()) {
              process.end(1,
                      "please check arthas log. if java version >=9 , try to add jvm options when start your process: "
                              + "--add-opens java.base/jdk.internal.perf=ALL-UNNAMED "
                              + "--add-exports java.base/jdk.internal.perf=ALL-UNNAMED "
                              + "--add-opens java.management/sun.management.counter.perf=ALL-UNNAMED "
                              + "--add-opens java.management/sun.management.counter=ALL-UNNAMED");
              return;
          }
  
          List<PerfCounterVO> perfCounterVOs = new ArrayList<PerfCounterVO>();
          for (Counter counter : perfCounters) {
              PerfCounterVO perfCounterVO = new PerfCounterVO(counter.getName(), counter.getValue());
              if (details) {
                  perfCounterVO.setUnits(counter.getUnits().toString());
                  perfCounterVO.setVariability(counter.getVariability().toString());
              }
              perfCounterVOs.add(perfCounterVO);
          }
          process.appendResult(new PerfCounterModel(perfCounterVOs, details));
          process.end();
      }
  
      private static List<Counter> getPerfCounters() {
  
          /**
           * <pre>
           * Perf p = Perf.getPerf();
           * ByteBuffer buffer = p.attach(pid, "r");
           * </pre>
           */
          try {
              if (perfObject == null) {
                  // jdk8
                  String perfClassName = "sun.misc.Perf";
                  // jdk 11
                  if (!JavaVersionUtils.isLessThanJava9()) {
                      perfClassName = "jdk.internal.perf.Perf";
                  }
  
                  Class<?> perfClass = ClassLoader.getSystemClassLoader().loadClass(perfClassName);
                  Method getPerfMethod = perfClass.getDeclaredMethod("getPerf");
                  perfObject = getPerfMethod.invoke(null);
              }
  
              if (attachMethod == null) {
                  attachMethod = perfObject.getClass().getDeclaredMethod("attach",
                          new Class<?>[] { int.class, String.class });
              }
  
              ByteBuffer buffer = (ByteBuffer) attachMethod.invoke(perfObject,
                      new Object[] { (int) PidUtils.currentLongPid(), "r" });
  
              PerfInstrumentation perfInstrumentation = new PerfInstrumentation(buffer);
              return perfInstrumentation.getAllCounters();
          } catch (Throwable e) {
              logger.error("get perf counter error", e);
          }
          return Collections.emptyList();
      }
  }
  