Package nallar.tickthreading.minecraft.profiling

Source Code of nallar.tickthreading.minecraft.profiling.PacketProfiler

package nallar.tickthreading.minecraft.profiling;

import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
import nallar.tickthreading.minecraft.commands.Command;
import nallar.tickthreading.util.TableFormatter;
import net.minecraft.command.ICommandSender;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.Packet250CustomPayload;
import org.cliffc.high_scale_lib.NonBlockingHashMap;

import java.util.*;
import java.util.concurrent.atomic.*;

public class PacketProfiler {
  private static boolean profiling = false;
  private static final Map<String, AtomicInteger> size = new NonBlockingHashMap<String, AtomicInteger>();
  private static final Map<String, AtomicInteger> count = new NonBlockingHashMap<String, AtomicInteger>();

  public static synchronized boolean startProfiling(final ICommandSender commandSender, final int time) {
    if (profiling) {
      Command.sendChat(commandSender, "Someone else is already profiling packets.");
      return false;
    }
    profiling = true;
    Command.sendChat(commandSender, "Profiling packets for " + time + " seconds.");
    new Thread() {
      @Override
      public void run() {
        try {
          Thread.sleep(time * 1000);
        } catch (InterruptedException ignored) {
        }
        Command.sendChat(commandSender, writeStats(new TableFormatter(commandSender)).toString());
        synchronized (PacketProfiler.class) {
          size.clear();
          count.clear();
          profiling = false;
        }
      }
    }.start();
    return true;
  }

  private static <T> List<T> sortedKeys(Map<T, ? extends Comparable<?>> map, int elements) {
    List<T> list = Ordering.natural().reverse().onResultOf(Functions.forMap(map)).immutableSortedCopy(map.keySet());
    return list.size() > elements ? list.subList(0, elements) : list;
  }

  private static TableFormatter writeStats(final TableFormatter tf) {
    return writeStats(tf, 9);
  }

  private static TableFormatter writeStats(final TableFormatter tf, int elements) {
    Map<String, Integer> count = new HashMap<String, Integer>();
    for (Map.Entry<String, AtomicInteger> entry : PacketProfiler.count.entrySet()) {
      count.put(entry.getKey(), entry.getValue().get());
    }
    Map<String, Integer> size = new HashMap<String, Integer>();
    for (Map.Entry<String, AtomicInteger> entry : PacketProfiler.size.entrySet()) {
      size.put(entry.getKey(), entry.getValue().get());
    }

    tf
        .heading("Packet")
        .heading("Count")
        .heading("Size");
    final List<String> sortedIdsByCount = sortedKeys(count, elements);
    for (String id : sortedIdsByCount) {
      tf
          .row(getName(id))
          .row(count.get(id))
          .row(humanReadableByteCount(size.get(id)));
    }
    tf.finishTable();
    tf.sb.append('\n');
    tf
        .heading("Packet")
        .heading("Count")
        .heading("Size");
    final List<String> sortedIdsBySize = sortedKeys(size, elements);
    for (String id : sortedIdsBySize) {
      tf
          .row(getName(id))
          .row(count.get(id))
          .row(humanReadableByteCount(size.get(id)));
    }
    tf.finishTable();
    return tf;
  }

  private static String getName(String name) {
    int id;
    try {
      id = Integer.parseInt(name);
    } catch (NumberFormatException ignored) {
      return name;
    }
    return ((Class) Packet.packetIdToClassMap.lookup(id)).getName().replace("net.minecraft.network.packet.Packet", "");
  }

  public static void record(final Packet packet) {
    if (!profiling) {
      return;
    }
    String id;
    int size;
    if (packet instanceof Packet250CustomPayload) {
      Packet250CustomPayload packet250CustomPayload = (Packet250CustomPayload) packet;
      byte[] data = packet250CustomPayload.data;
      size = data == null ? 0 : data.length;
      id = packet250CustomPayload.channel + (size > 0 ? Byte.toString(data[0]) : Byte.MIN_VALUE);
    } else {
      id = String.valueOf(packet.getPacketId());
      size = packet.getPacketSize();
    }
    getCount(id).getAndIncrement();
    getSize(id).addAndGet(size);
  }

  private static AtomicInteger getCount(String id) {
    AtomicInteger t = count.get(id);
    if (t == null) {
      synchronized (count) {
        t = count.get(id);
        if (t == null) {
          t = new AtomicInteger();
          count.put(id, t);
        }
      }
    }
    return t;
  }

  private static AtomicInteger getSize(String id) {
    AtomicInteger t = size.get(id);
    if (t == null) {
      synchronized (size) {
        t = size.get(id);
        if (t == null) {
          t = new AtomicInteger();
          size.put(id, t);
        }
      }
    }
    return t;
  }

  // http://stackoverflow.com/a/3758880/250076
  public static String humanReadableByteCount(int bytes) {
    int unit = 1024;
    if (bytes < unit) {
      return bytes + " B";
    }
    int exp = (int) (Math.log(bytes) / Math.log(unit));
    char pre = ("KMGTPE").charAt(exp - 1);
    return String.format("%.1f%cB", bytes / Math.pow(unit, exp), pre);
  }
}
TOP

Related Classes of nallar.tickthreading.minecraft.profiling.PacketProfiler

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.