테스트

aion-server 4.8

Gitteol
최고관리자 · 1 · 💬 0 클론/새로받기
 4.8 61f661d · 1 commits 새로받기(Pull)
commons/src/com/aionemu/commons/utils/concurrent/RunnableStatsManager.java
package com.aionemu.commons.utils.concurrent;

import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author NB4L1
 */
public final class RunnableStatsManager {

	private static final Logger log = LoggerFactory.getLogger(RunnableStatsManager.class);
	private static final Map<Class<?>, ClassStat> classStats = new HashMap<>();

	private static final class ClassStat {

		private final String className;
		private final MethodStat runnableStat;

		private String[] methodNames = new String[0];
		private MethodStat[] methodStats = new MethodStat[0];

		private ClassStat(Class<?> clazz) {
			className = clazz.getName().replace("com.aionemu.gameserver.", "");
			runnableStat = new MethodStat(className, "run()");

			methodNames = new String[] { "run()" };
			methodStats = new MethodStat[] { runnableStat };

			classStats.put(clazz, this);
		}

		private MethodStat getRunnableStat() {
			return runnableStat;
		}

		private MethodStat getMethodStat(String methodName, boolean synchronizedAlready) {
			// method names will be interned automatically because of compiling, so this gonna work
			if ("run()".equals(methodName))
				return runnableStat;

			for (int i = 0; i < methodNames.length; i++)
				if (methodNames[i].equals(methodName))
					return methodStats[i];

			if (!synchronizedAlready) {
				synchronized (this) {
					return getMethodStat(methodName, true);
				}
			}

			methodName = methodName.intern();

			final MethodStat methodStat = new MethodStat(className, methodName);

			methodNames = Arrays.copyOf(methodNames, methodNames.length + 1);
			methodNames[methodNames.length - 1] = methodName;
			methodStats = Arrays.copyOf(methodStats, methodStats.length + 1);
			methodStats[methodNames.length - 1] = methodStat;

			return methodStat;
		}
	}

	private static final class MethodStat {

		private final ReentrantLock lock = new ReentrantLock();

		private final String className;
		private final String methodName;

		private long count;
		private long total;
		private long min = Long.MAX_VALUE;
		private long max = Long.MIN_VALUE;

		private MethodStat(String className, String methodName) {
			this.className = className;
			this.methodName = methodName;
		}

		private void handleStats(long runTime) {
			lock.lock();
			try {
				count++;
				total += runTime;
				min = Math.min(min, runTime);
				max = Math.max(max, runTime);
			} finally {
				lock.unlock();
			}
		}
	}

	private static ClassStat getClassStat(Class<?> clazz, boolean synchronizedAlready) {
		ClassStat classStat = classStats.get(clazz);

		if (classStat != null)
			return classStat;

		if (!synchronizedAlready) {
			synchronized (RunnableStatsManager.class) {
				return getClassStat(clazz, true);
			}
		}

		return new ClassStat(clazz);
	}

	public static void handleStats(Class<? extends Runnable> clazz, long runTime) {
		getClassStat(clazz, false).getRunnableStat().handleStats(runTime);
	}

	public static void handleStats(Class<?> clazz, String methodName, long runTime) {
		getClassStat(clazz, false).getMethodStat(methodName, false).handleStats(runTime);
	}

	public static enum SortBy {
		AVG("average"),
		COUNT("count"),
		TOTAL("total"),
		NAME("class"),
		METHOD("method"),
		MIN("min"),
		MAX("max"), ;

		private final String xmlAttributeName;

		private SortBy(String xmlAttributeName) {
			this.xmlAttributeName = xmlAttributeName;
		}

		private final Comparator<MethodStat> comparator = new Comparator<MethodStat>() {

			@Override
			@SuppressWarnings({ "rawtypes", "unchecked" })
			public int compare(MethodStat o1, MethodStat o2) {
				final Comparable c1 = getComparableValueOf(o1);
				final Comparable c2 = getComparableValueOf(o2);

				if (c1 instanceof Number)
					return c2.compareTo(c1);

				final String s1 = (String) c1;
				final String s2 = (String) c2;

				final int len1 = s1.length();
				final int len2 = s2.length();
				final int n = Math.min(len1, len2);

				for (int k = 0; k < n; k++) {
					char ch1 = s1.charAt(k);
					char ch2 = s2.charAt(k);

					if (ch1 != ch2) {
						if (Character.isUpperCase(ch1) != Character.isUpperCase(ch2))
							return ch2 - ch1;
						else
							return ch1 - ch2;
					}
				}

				final int result = len1 - len2;

				if (result != 0)
					return result;

				switch (SortBy.this) {
					case METHOD:
						return NAME.comparator.compare(o1, o2);
					default:
						return 0;
				}
			}
		};

		@SuppressWarnings("rawtypes")
		private Comparable getComparableValueOf(MethodStat stat) {
			switch (this) {
				case AVG:
					return stat.total / stat.count;
				case COUNT:
					return stat.count;
				case TOTAL:
					return stat.total;
				case NAME:
					return stat.className;
				case METHOD:
					return stat.methodName;
				case MIN:
					return stat.min;
				case MAX:
					return stat.max;
				default:
					throw new InternalError();
			}
		}

		private static final SortBy[] VALUES = SortBy.values();
	}

	public static void dumpClassStats() {
		dumpClassStats(null);
	}

	public static void dumpClassStats(final SortBy sortBy) {
		final List<MethodStat> methodStats = new ArrayList<>();

		synchronized (RunnableStatsManager.class) {
			for (ClassStat classStat : classStats.values())
				for (MethodStat methodStat : classStat.methodStats)
					if (methodStat.count > 0)
						methodStats.add(methodStat);
		}

		if (sortBy != null)
			Collections.sort(methodStats, sortBy.comparator);

		final List<String> lines = new ArrayList<>();

		lines.add("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
		lines.add("<entries>");
		lines.add("\t<!-- This XML contains statistics about execution times. -->");
		lines.add("\t<!-- Submitted results will help the developers to optimize the server. -->");

		final String[][] values = new String[SortBy.VALUES.length][methodStats.size()];
		final int[] maxLength = new int[SortBy.VALUES.length];

		for (int i = 0; i < SortBy.VALUES.length; i++) {
			final SortBy sort = SortBy.VALUES[i];

			for (int k = 0; k < methodStats.size(); k++) {
				@SuppressWarnings("rawtypes")
				final Comparable c = sort.getComparableValueOf(methodStats.get(k));

				final String value;

				if (c instanceof Number)
					value = NumberFormat.getInstance(Locale.ENGLISH).format(((Number) c).longValue());
				else
					value = String.valueOf(c);

				values[i][k] = value;

				maxLength[i] = Math.max(maxLength[i], value.length());
			}
		}

		for (int k = 0; k < methodStats.size(); k++) {
			StringBuilder sb = new StringBuilder();
			sb.append("\t<entry ");

			EnumSet<SortBy> set = EnumSet.allOf(SortBy.class);

			if (sortBy != null) {
				switch (sortBy) {
					case NAME:
					case METHOD:
						appendAttribute(sb, SortBy.NAME, values[SortBy.NAME.ordinal()][k], maxLength[SortBy.NAME.ordinal()]);
						set.remove(SortBy.NAME);

						appendAttribute(sb, SortBy.METHOD, values[SortBy.METHOD.ordinal()][k], maxLength[SortBy.METHOD.ordinal()]);
						set.remove(SortBy.METHOD);
						break;
					default:
						appendAttribute(sb, sortBy, values[sortBy.ordinal()][k], maxLength[sortBy.ordinal()]);
						set.remove(sortBy);
						break;
				}
			}

			for (SortBy sort : SortBy.VALUES)
				if (set.contains(sort))
					appendAttribute(sb, sort, values[sort.ordinal()][k], maxLength[sort.ordinal()]);

			sb.append("/>");

			lines.add(sb.toString());
		}

		lines.add("</entries>");

		try {
			Path statsFolder = Paths.get("./log/stats");
			Files.createDirectories(statsFolder);
			try (PrintStream ps = new PrintStream(statsFolder + "/MethodStats.log")) {
				for (String line : lines)
					ps.println(line);
			}
		} catch (Exception e) {
			log.warn("", e);
		}
	}

	private static void appendAttribute(StringBuilder sb, SortBy sortBy, String value, int fillTo) {
		sb.append(sortBy.xmlAttributeName);
		sb.append("=");

		if (sortBy != SortBy.NAME && sortBy != SortBy.METHOD)
			for (int i = value.length(); i < fillTo; i++)
				sb.append(" ");

		sb.append("\"");
		sb.append(value);
		sb.append("\" ");

		if (sortBy == SortBy.NAME || sortBy == SortBy.METHOD)
			for (int i = value.length(); i < fillTo; i++)
				sb.append(" ");
	}
}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 TOP 10
순위 닉네임 포인트
1 no_profile 타키야겐지쪽지보내기 자기소개 아이디로 검색 전체게시물 102,949
2 no_profile 동가리쪽지보내기 자기소개 아이디로 검색 전체게시물 63,733
3 no_profile 라프텔쪽지보내기 자기소개 아이디로 검색 전체게시물 51,771
4 no_profile 불멸의행복쪽지보내기 자기소개 아이디로 검색 전체게시물 36,923
5 서번트쪽지보내기 자기소개 아이디로 검색 전체게시물 35,011
6 no_profile 닥터스쪽지보내기 자기소개 아이디로 검색 전체게시물 29,470
7 no_profile 검은고양이쪽지보내기 자기소개 아이디로 검색 전체게시물 29,077
8 no_profile Revolution쪽지보내기 자기소개 아이디로 검색 전체게시물 28,199
9 no_profile 보거스쪽지보내기 자기소개 아이디로 검색 전체게시물 26,731
10 no_profile 호롤롤로쪽지보내기 자기소개 아이디로 검색 전체게시물 17,020
알림 0