Last active
August 29, 2015 13:57
-
-
Save vongosling/9661145 to your computer and use it in GitHub Desktop.
Performance analyzer v1.1.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
2013-5-08 - version 1.0.0 released
2014-3-21 - version 1.1.0 released
Fixed - log4j thread safe problem
Feature - support logback