Skip to content

Instantly share code, notes, and snippets.

@vongosling
Last active August 29, 2015 13:57
Show Gist options
  • Save vongosling/9661145 to your computer and use it in GitHub Desktop.
Save vongosling/9661145 to your computer and use it in GitHub Desktop.
Performance analyzer v1.1.0
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.perf4j.LogParser;
import org.perf4j.StopWatch;
import org.perf4j.slf4j.Slf4JStopWatch;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;
import com.google.common.collect.Lists;
/**
* Performance analyzer v1.1.0
*
* @author vongosling 2013-5-8
* @param <T> Concrete business Class
*/
public class LoadExecutor<T> {
private static String LOG_TIME = "time.log";
private static String LOG_RESULT = "result.log";
private static String LOG_PATTERN = "%-5level [%thread]: %message%n";
private int threads;
private long requests;
private ExecutorService executor;
private T target;
public LoadExecutor(int threads, long requests, T target) {
this.threads = threads;
this.requests = requests;
this.target = target;
}
public void exec(String method, Object... args) throws InterruptedException, SecurityException,
NoSuchMethodException, ExecutionException, TimeoutException, IOException {
String targetMethod = target.getClass().getSimpleName() + "-" + method;
String prefix = getFmtDate();
String threadCount = String.valueOf(threads);
String reqCount = String.valueOf(requests);
String timeFile = fileNameGenerator(prefix, targetMethod, threadCount, reqCount, LOG_TIME);
String resultFile = fileNameGenerator(prefix, targetMethod, threadCount, reqCount,
LOG_RESULT);
// Layout layout = new EnhancedPatternLayout();
// Appender timeFileAppender = new FileAppender(layout, timeFile, false);
// Appender resultFileAppender = new FileAppender(layout, resultFile, false);
// Logger loggerTime = Logger.getLogger(LOG_TIME);
// Logger loggerResult = Logger.getLogger(LOG_RESULT);
// loggerTime.setAdditivity(false);
// loggerTime.addAppender(timeFileAppender);
// loggerResult.setAdditivity(false);
// loggerResult.addAppender(resultFileAppender);
// doProbe(loggerTime, loggerResult, method, args);
LoggerContext resultFileContext = (LoggerContext) LoggerFactory.getILoggerFactory();
LoggerContext timeFileContext = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder resultFileEncoder = new PatternLayoutEncoder();
resultFileEncoder.setContext(resultFileContext);
resultFileEncoder.setPattern(LOG_PATTERN);
resultFileEncoder.start();
PatternLayoutEncoder timeFileEncoder = new PatternLayoutEncoder();
timeFileEncoder.setContext(timeFileContext);
timeFileEncoder.setPattern(LOG_PATTERN);
timeFileEncoder.start();
FileAppender<ILoggingEvent> resultFileAppender = new FileAppender<ILoggingEvent>();
resultFileAppender.setFile(resultFile);
resultFileAppender.setContext(resultFileContext);
resultFileAppender.setEncoder(resultFileEncoder);
resultFileAppender.setPrudent(true);
resultFileAppender.start();
FileAppender<ILoggingEvent> timeFileAppender = new FileAppender<ILoggingEvent>();
timeFileAppender.setFile(timeFile);
timeFileAppender.setContext(timeFileContext);
timeFileAppender.setEncoder(timeFileEncoder);
timeFileAppender.setPrudent(true);
timeFileAppender.start();
Logger loggerTime = (Logger) LoggerFactory.getLogger(LOG_TIME);
Logger loggerResult = (Logger) LoggerFactory.getLogger(LOG_RESULT);
loggerTime.setAdditive(false);
loggerTime.setLevel(Level.INFO);
loggerTime.addAppender(timeFileAppender);
loggerResult.setAdditive(false);
loggerResult.setLevel(Level.INFO);
loggerResult.addAppender(resultFileAppender);
doProbe(loggerTime, loggerResult, method, args);
doCollect(targetMethod, prefix, threadCount, reqCount, timeFile);
}
private void doCollect(String targetMethod, String prefix, String threadCount, String reqCount,
String timeFile) {
String tpsFile = fileNameGenerator(prefix, targetMethod, threadCount, reqCount, "tps.html");
String statFile = fileNameGenerator(prefix, targetMethod, threadCount, reqCount, "stat.log");
String[] args = { "-o", statFile, "-g", tpsFile, timeFile };
LogParser.runMain(args);
}
private void doProbe(Logger loggerTime, Logger loggerResult, String method, Object... args)
throws NoSuchMethodException, InterruptedException, ExecutionException,
TimeoutException {
List<Class<?>> clazs = Lists.newArrayList();
executor = Executors.newFixedThreadPool(threads);
CompletionService<Boolean> cService = new ExecutorCompletionService<Boolean>(executor);
for (Object obj : args) {
clazs.add(obj.getClass());
}
Method m = target.getClass().getDeclaredMethod(method, clazs.toArray(new Class<?>[] {}));
warmUp(m, args);
for (long i = 1; i < requests + 1; i++) {
cService.submit(new Caller(loggerTime, m, args));
}
for (long i = 1; i < requests + 1; i++) {
Future<Boolean> future = cService.take();
boolean result = future.get(50, TimeUnit.SECONDS);
loggerResult.info("request " + i + " result is " + result);
}
}
private String fileNameGenerator(String name, String... args) {
StringBuilder sb = new StringBuilder(name);
for (String arg : args) {
sb.append("-");
sb.append(arg);
}
return sb.toString();
}
private String getFmtDate() {
Date date = new Date();
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss");
String prefix = fmt.format(date);
return prefix;
}
private void warmUp(Method method, Object... args) throws InterruptedException {
for (int i = 0; i < threads; i++) {
executor.execute(new WarmUp(method, args));
Thread.sleep(50);
}
}
private class WarmUp implements Runnable {
private Method method;
private Object[] args;
public WarmUp(Method method, Object... args) {
this.method = method;
this.args = args;
}
public void run() {
try {
method.invoke(target, args);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class Caller implements Callable<Boolean> {
private Method method;
private Logger log;
private Object[] args;
public Caller(Logger logger, Method method, Object... args) {
this.log = logger;
this.method = method;
this.args = args;
}
public Boolean call() throws Exception {
StopWatch stopWatch = new Slf4JStopWatch(log);
method.invoke(target, args);
stopWatch.stop(method.getName());
return true;
}
}
}
@vongosling
Copy link
Author

public class LoadExecutorTest {

@Test
public void testExec() throws Exception {
    Calendar instance = Calendar.getInstance();
    //instance.add(Calendar.DAY_OF_WEEK, 5);
    //System.out.println(Arrays.asList(instance.getClass().getDeclaredMethods()));
    LoadExecutor<Calendar> loadExecutor = new LoadExecutor<Calendar>(20, 100, instance);
    loadExecutor.exec("getTimeZone");
}

}

@vongosling
Copy link
Author

2013-5-08 - version 1.0.0 released
2014-3-21 - version 1.1.0 released
Fixed - log4j thread safe problem
Feature - support logback

@inter12
Copy link

inter12 commented Aug 6, 2014

查看某一个方法的执行时间?
感觉还可以写的更好点!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment