Package nallar.tickthreading.minecraft.profiling

Source Code of nallar.tickthreading.minecraft.profiling.ContentionProfiler$IntegerHolder

package nallar.tickthreading.minecraft.profiling;

import com.google.common.primitives.Longs;
import nallar.tickthreading.Log;
import nallar.tickthreading.minecraft.commands.Command;
import nallar.tickthreading.util.CollectionsUtil;
import nallar.tickthreading.util.TableFormatter;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ThreadMinecraftServer;

import java.lang.management.*;
import java.util.*;

public class ContentionProfiler {
  public static void profile(final ICommandSender commandSender, int seconds, int resolution) {
    final ContentionProfiler contentionProfiler = new ContentionProfiler(seconds, resolution);
    contentionProfiler.run(new Runnable() {
      @Override
      public void run() {
        TableFormatter tf = new TableFormatter(commandSender);
        contentionProfiler.dump(tf, commandSender instanceof MinecraftServer ? 15 : 6);
        Command.sendChat(commandSender, tf.toString());
      }
    });
  }

  public ContentionProfiler(int seconds, int resolution) {
    this.seconds = seconds;
    this.resolution = resolution;
  }

  private final int seconds;
  private final int resolution;
  private long ticks;
  private long[] threads;
  private final Map<String, IntegerHolder> monitorMap = new IntHashMap<String>();
  private final Map<String, IntegerHolder> waitingMap = new IntHashMap<String>();
  private final Map<String, IntegerHolder> traceMap = new IntHashMap<String>();

  public void run(final Runnable completed) {
    final int ticks = seconds * 1000 / resolution;
    new Thread(new Runnable() {
      @Override
      public void run() {
        profile(ticks);
        completed.run();
      }
    }, "Contention Profiler").start();
  }

  public void dump(final TableFormatter tf, int entries) {
    float ticks = this.ticks;
    tf
        .heading("Monitor")
        .heading("Wasted Cores");
    for (String key : CollectionsUtil.sortedKeys(monitorMap, entries)) {
      tf
          .row(key)
          .row(monitorMap.get(key).value / ticks);
    }
    tf.finishTable();
    tf.sb.append('\n');
    tf
        .heading("Wait")
        .heading("Wasted Cores");
    for (String key : CollectionsUtil.sortedKeys(waitingMap, entries)) {
      tf
          .row(key)
          .row(waitingMap.get(key).value / ticks);
    }
    tf.finishTable();
    tf.sb.append('\n');
    tf
        .heading("Stack")
        .heading("Wasted Cores");
    for (String key : CollectionsUtil.sortedKeys(traceMap, entries)) {
      tf
          .row(key)
          .row(traceMap.get(key).value / ticks);
    }
    tf.finishTable();
  }

  private void profile(int ticks) {
    List<Long> threads = new ArrayList<Long>();
    for (Thread thread : Thread.getAllStackTraces().keySet()) {
      if (thread instanceof ThreadMinecraftServer) {
        threads.add(thread.getId());
      }
    }
    this.threads = Longs.toArray(threads);
    while (ticks-- > 0) {
      long r = resolution - tick();

      if (r > 0) {
        try {
          Thread.sleep(r, 0);
        } catch (InterruptedException e) {
          Log.severe("Interrupted in profiling", e);
          return;
        }
      } else if (r < -10) {
        ticks--;
      }
      this.ticks++;
    }
  }

  private long tick() {
    long t = System.currentTimeMillis();
    ThreadInfo[] threads = ManagementFactory.getThreadMXBean().getThreadInfo(this.threads, 6);
    for (ThreadInfo thread : threads) {
      if (thread == null) {
        continue;
      }
      Thread.State ts = thread.getThreadState();
      switch (ts) {
        case WAITING:
        case TIMED_WAITING:
        case BLOCKED:
          StackTraceElement[] stackTrace = thread.getStackTrace();
          StackTraceElement stack = null;
          StackTraceElement prevStack = null;
          for (StackTraceElement stackTraceElement : stackTrace) {
            String className = stackTraceElement.getClassName();
            if (className.startsWith("java") || className.startsWith("sun.")) {
              prevStack = stackTraceElement;
            } else {
              stack = stackTraceElement;
              break;
            }
          }
          if (stack != null && ("waitForCompletion".equals(stack.getMethodName()) || "nallar.tickthreading.minecraft.ThreadManager$1".equals(stack.getClassName()))) {
            continue;
          }
          LockInfo lockInfo = thread.getLockInfo();
          if (lockInfo != null) {
            (ts == Thread.State.BLOCKED ? monitorMap : waitingMap).get(lockInfo.toString()).value++;
          }
          if (stack != null) {
            String prev = name(prevStack);
            traceMap.get(name(stack) + (prev == null ? "" : " -> " + prev)).value++;
          }
          break;
      }
    }
    return System.currentTimeMillis() - t;
  }

  private static String name(StackTraceElement stack) {
    if (stack == null) {
      return null;
    }
    String className = stack.getClassName();
    return className.substring(className.lastIndexOf('.') + 1) + '.' + stack.getMethodName();
  }

  private static class IntHashMap<K> extends HashMap<K, IntegerHolder> {
    IntHashMap() {
    }

    @Override
    public IntegerHolder get(Object k) {
      IntegerHolder integerHolder = super.get(k);
      if (integerHolder == null) {
        integerHolder = new IntegerHolder();
        put((K) k, integerHolder);
      }
      return integerHolder;
    }
  }

  private static class IntegerHolder implements Comparable<IntegerHolder> {
    public int value;

    IntegerHolder() {
    }

    @Override
    public int compareTo(final IntegerHolder o) {
      int x = value;
      int y = o.value;
      return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
  }
}
TOP

Related Classes of nallar.tickthreading.minecraft.profiling.ContentionProfiler$IntegerHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.