com.alibaba.antx.util.Profiler Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.antx.util;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 用来测试并统计线程执行时间的工具。
*
* @author Michael Zhou
*/
public final class Profiler {
private static final ThreadLocal entryStack = new ThreadLocal();
/** 开始计时。 */
public static void start() {
start((String) null);
}
/**
* 开始计时。
*
* @param message 第一个entry的信息
*/
public static void start(String message) {
entryStack.set(new Entry(message, null, null));
}
/**
* 开始计时。
*
* @param message 第一个entry的信息
*/
public static void start(Message message) {
entryStack.set(new Entry(message, null, null));
}
/**
* 清除计时器。
*
* 清除以后必须再次调用start
方可重新计时。
*
*/
public static void reset() {
entryStack.set(null);
}
/**
* 开始一个新的entry,并计时。
*
* @param message 新entry的信息
*/
public static void enter(String message) {
Entry currentEntry = getCurrentEntry();
if (currentEntry != null) {
currentEntry.enterSubEntry(message);
}
}
/**
* 开始一个新的entry,并计时。
*
* @param message 新entry的信息
*/
public static void enter(Message message) {
Entry currentEntry = getCurrentEntry();
if (currentEntry != null) {
currentEntry.enterSubEntry(message);
}
}
/** 结束最近的一个entry,记录结束时间。 */
public static Entry release() {
Entry currentEntry = getCurrentEntry();
if (currentEntry != null) {
currentEntry.release();
}
return currentEntry;
}
/**
* 取得耗费的总时间。
*
* @return 耗费的总时间,如果未开始计时,则返回-1
*/
public static long getDuration() {
Entry entry = (Entry) entryStack.get();
if (entry != null) {
return entry.getDuration();
} else {
return -1;
}
}
/**
* 列出所有的entry。
*
* @return 列出所有entry,并统计各自所占用的时间
*/
public static String dump() {
return dump("", "");
}
/**
* 列出所有的entry。
*
* @param prefix 前缀
* @return 列出所有entry,并统计各自所占用的时间
*/
public static String dump(String prefix) {
return dump(prefix, prefix);
}
/**
* 列出所有的entry。
*
* @param prefix1 首行前缀
* @param prefix2 后续行前缀
* @return 列出所有entry,并统计各自所占用的时间
*/
public static String dump(String prefix1, String prefix2) {
Entry entry = (Entry) entryStack.get();
if (entry != null) {
return entry.toString(prefix1, prefix2);
} else {
return "";
}
}
/**
* 取得第一个entry。
*
* @return 第一个entry,如果不存在,则返回null
*/
public static Entry getEntry() {
return (Entry) entryStack.get();
}
/**
* 取得最近的一个entry。
*
* @return 最近的一个entry,如果不存在,则返回null
*/
private static Entry getCurrentEntry() {
Entry subEntry = (Entry) entryStack.get();
Entry entry = null;
if (subEntry != null) {
do {
entry = subEntry;
subEntry = entry.getUnreleasedEntry();
} while (subEntry != null);
}
return entry;
}
private static Object defaultIfNull(Object object, Object defaultValue) {
return object != null ? object : defaultValue;
}
private static String defaultIfEmpty(String str, String defaultStr) {
return str == null || str.length() == 0 ? defaultStr : str;
}
/** 代表一个计时单元。 */
public static final class Entry {
private final List subEntries = new ArrayList(4);
private final Object message;
private final Entry parentEntry;
private final Entry firstEntry;
private final long baseTime;
private final long startTime;
private long endTime;
/**
* 创建一个新的entry。
*
* @param message entry的信息,可以是null
* @param parentEntry 父entry,可以是null
* @param firstEntry 第一个entry,可以是null
*/
private Entry(Object message, Entry parentEntry, Entry firstEntry) {
this.message = message;
this.startTime = System.currentTimeMillis();
this.parentEntry = parentEntry;
this.firstEntry = (Entry) defaultIfNull(firstEntry, this);
this.baseTime = firstEntry == null ? 0 : firstEntry.startTime;
}
/** 取得entry的信息。 */
public String getMessage() {
String messageString = null;
if (message instanceof String) {
messageString = (String) message;
} else if (message instanceof Message) {
Message messageObject = (Message) message;
MessageLevel level = MessageLevel.BRIEF_MESSAGE;
if (isReleased()) {
level = messageObject.getMessageLevel(this);
}
if (level == MessageLevel.DETAILED_MESSAGE) {
messageString = messageObject.getDetailedMessage();
} else {
messageString = messageObject.getBriefMessage();
}
}
return defaultIfEmpty(messageString, null);
}
/**
* 取得entry相对于第一个entry的起始时间。
*
* @return 相对起始时间
*/
public long getStartTime() {
return baseTime > 0 ? startTime - baseTime : 0;
}
/**
* 取得entry相对于第一个entry的结束时间。
*
* @return 相对结束时间,如果entry还未结束,则返回-1
*/
public long getEndTime() {
if (endTime < baseTime) {
return -1;
} else {
return endTime - baseTime;
}
}
/**
* 取得entry持续的时间。
*
* @return entry持续的时间,如果entry还未结束,则返回-1
*/
public long getDuration() {
if (endTime < startTime) {
return -1;
} else {
return endTime - startTime;
}
}
/**
* 取得entry自身所用的时间,即总时间减去所有子entry所用的时间。
*
* @return entry自身所用的时间,如果entry还未结束,则返回-1
*/
public long getDurationOfSelf() {
long duration = getDuration();
if (duration < 0) {
return -1;
} else if (subEntries.isEmpty()) {
return duration;
} else {
for (int i = 0; i < subEntries.size(); i++) {
Entry subEntry = (Entry) subEntries.get(i);
duration -= subEntry.getDuration();
}
if (duration < 0) {
return -1;
} else {
return duration;
}
}
}
/**
* 取得当前entry在父entry中所占的时间百分比。
*
* @return 百分比
*/
public double getPecentage() {
double parentDuration = 0;
double duration = getDuration();
if (parentEntry != null && parentEntry.isReleased()) {
parentDuration = parentEntry.getDuration();
}
if (duration > 0 && parentDuration > 0) {
return duration / parentDuration;
} else {
return 0;
}
}
/**
* 取得当前entry在第一个entry中所占的时间百分比。
*
* @return 百分比
*/
public double getPecentageOfAll() {
double firstDuration = 0;
double duration = getDuration();
if (firstEntry != null && firstEntry.isReleased()) {
firstDuration = firstEntry.getDuration();
}
if (duration > 0 && firstDuration > 0) {
return duration / firstDuration;
} else {
return 0;
}
}
/**
* 取得所有子entries。
*
* @return 所有子entries的列表(不可更改)
*/
public List getSubEntries() {
return Collections.unmodifiableList(subEntries);
}
/** 结束当前entry,并记录结束时间。 */
private void release() {
endTime = System.currentTimeMillis();
}
/**
* 判断当前entry是否结束。
*
* @return 如果entry已经结束,则返回true
*/
private boolean isReleased() {
return endTime > 0;
}
/**
* 创建一个新的子entry。
*
* @param message 子entry的信息
*/
private void enterSubEntry(Object message) {
Entry subEntry = new Entry(message, this, firstEntry);
subEntries.add(subEntry);
}
/**
* 取得未结束的子entry。
*
* @return 未结束的子entry,如果没有子entry,或所有entry均已结束,则返回null
*/
private Entry getUnreleasedEntry() {
Entry subEntry = null;
if (!subEntries.isEmpty()) {
subEntry = (Entry) subEntries.get(subEntries.size() - 1);
if (subEntry.isReleased()) {
subEntry = null;
}
}
return subEntry;
}
/**
* 将entry转换成字符串的表示。
*
* @return 字符串表示的entry
*/
@Override
public String toString() {
return toString("", "");
}
/**
* 将entry转换成字符串的表示。
*
* @param prefix1 首行前缀
* @param prefix2 后续行前缀
* @return 字符串表示的entry
*/
private String toString(String prefix1, String prefix2) {
StringBuffer buffer = new StringBuffer();
toString(buffer, prefix1, prefix2);
return buffer.toString();
}
/**
* 将entry转换成字符串的表示。
*
* @param buffer 字符串buffer
* @param prefix1 首行前缀
* @param prefix2 后续行前缀
*/
private void toString(StringBuffer buffer, String prefix1, String prefix2) {
buffer.append(prefix1);
String message = getMessage();
long startTime = getStartTime();
long duration = getDuration();
long durationOfSelf = getDurationOfSelf();
double percent = getPecentage();
double percentOfAll = getPecentageOfAll();
Object[] params = new Object[] { message, // {0} - entry信息
new Long(startTime), // {1} - 起始时间
new Long(duration), // {2} - 持续总时间
new Long(durationOfSelf), // {3} - 自身消耗的时间
new Double(percent), // {4} - 在父entry中所占的时间比例
new Double(percentOfAll) // {5} - 在总时间中所旧的时间比例
};
StringBuffer pattern = new StringBuffer("{1,number} ");
if (isReleased()) {
pattern.append("[{2,number}ms");
if (durationOfSelf > 0 && durationOfSelf != duration) {
pattern.append(" ({3,number}ms)");
}
if (percent > 0) {
pattern.append(", {4,number,##%}");
}
if (percentOfAll > 0) {
pattern.append(", {5,number,##%}");
}
pattern.append("]");
} else {
pattern.append("[UNRELEASED]");
}
if (message != null) {
pattern.append(" - {0}");
}
buffer.append(MessageFormat.format(pattern.toString(), params));
for (int i = 0; i < subEntries.size(); i++) {
Entry subEntry = (Entry) subEntries.get(i);
buffer.append('\n');
if (i == subEntries.size() - 1) {
subEntry.toString(buffer, prefix2 + "`---", prefix2 + " "); // 最后一项
} else if (i == 0) {
subEntry.toString(buffer, prefix2 + "+---", prefix2 + "| "); // 第一项
} else {
subEntry.toString(buffer, prefix2 + "+---", prefix2 + "| "); // 中间项
}
}
}
}
/** 显示消息的级别。 */
public static final class MessageLevel implements Serializable {
private static final long serialVersionUID = 3257849896026388537L;
public static final MessageLevel NO_MESSAGE = new MessageLevel();
public static final MessageLevel BRIEF_MESSAGE = new MessageLevel();
public static final MessageLevel DETAILED_MESSAGE = new MessageLevel();
}
/** 代表一个profiler entry的详细信息。 */
public interface Message {
MessageLevel getMessageLevel(Entry entry);
String getBriefMessage();
String getDetailedMessage();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy