概述
执行jmter tests ,直接用于本地GUI和非GUI调用,或者在服务器模式下运行时由RemoteJMeterEngineImpl启动
介绍
在JMeterEngineImpl中做了一部分的解释,可以结合着看
主要变量
灵魂级变量,注意关键字volatile
private static volatile StandardJMeterEngine engine;
构造函数
有两种构造函数,带参和不带参
public StandardJMeterEngine() {
this(null);
}
public StandardJMeterEngine(String host) {
this.host = host;
// Hack to allow external control
initSingletonEngine(this);
}
操作engine
initSingletonEngine()、initSingletonEngine()、stopEngineNow()、stopEngine()略
stopThread
根据threadName停止线程的执行:分两种情况立即停止和非立即停止,根据第二个参数的值决定
private static boolean stopThread(String threadName, boolean now) {
if (engine == null) {
return false;// e.g. not yet started
}
boolean wasStopped = false;
// ConcurrentHashMap does not need synch. here
for (AbstractThreadGroup threadGroup : engine.groups) {
wasStopped = wasStopped || threadGroup.stopThread(threadName, now);
}
return wasStopped;
}
ThreadGroup.stopThread及调用及具体实现参考代码如下
public boolean stopThread(String threadName, boolean now) {
for(Entry<JMeterThread, Thread> entry : allThreads.entrySet()) {
JMeterThread thrd = entry.getKey();
if (thrd.getThreadName().equals(threadName)) {
stopThread(thrd, entry.getValue(), now);
return true;
}
}
return false;
}
/**
* Hard Stop JMeterThread thrd and interrupt JVM Thread if interrupt is true
* @param jmeterThread {@link JMeterThread}
* @param jvmThread {@link Thread}
* @param interrupt Interrupt thread or not
*/
private void stopThread(JMeterThread jmeterThread, Thread jvmThread, boolean interrupt) {
jmeterThread.stop();
jmeterThread.interrupt(); // interrupt sampler if possible
if (interrupt && jvmThread != null) { // Bug 49734
jvmThread.interrupt(); // also interrupt JVM thread
}
}
configure
参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t2
runTest
参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t3
removeThreadGroups
移除线程组,在run方法里调用
private void removeThreadGroups(List<?> elements) {
Iterator<?> iter = elements.iterator();
while (iter.hasNext()) { // Can't use for loop here because we remove elements
Object item = iter.next();
if (item instanceof AbstractThreadGroup) {
iter.remove();
} else if (!(item instanceof TestElement)) {
iter.remove();
}
}
}
notifyTestListenersOfStart
测试开始通知监听
private void notifyTestListenersOfStart(SearchByClass<TestStateListener> testListeners) {
for (TestStateListener tl : testListeners.getSearchResults()) {
if (tl instanceof TestBean) {
TestBeanHelper.prepare((TestElement) tl);
}
if (host == null) {
tl.testStarted();
} else {
tl.testStarted(host);
}
}
}
介绍本方法需要了解下TestStateListener
public interface TestStateListener {
void testStarted();
void testStarted(String host);
void testEnded();
void testEnded(String host);
}
testStarted:在测试开始之前调用
testEnded:在所有线程测试结束时调用一次
notifyTestListenersOfEnd
测试结束通知监听
private void notifyTestListenersOfEnd(SearchByClass<TestStateListener> testListeners) {
log.info("Notifying test listeners of end of test");
for (TestStateListener tl : testListeners.getSearchResults()) {
try {
if (host == null) {
tl.testEnded();
} else {
tl.testEnded(host);
}
} catch (Exception e) {
log.warn("Error encountered during shutdown of " + tl.toString(), e);
}
}
if (host != null) {
log.info("Test has ended on host " + host);
long now = System.currentTimeMillis();
System.out.println("Finished the test on host " + host + " @ " + new Date(now) + " (" + now + ")" // NOSONAR Intentional
+ (EXIT_AFTER_TEST ? " - exit requested." : ""));
if (EXIT_AFTER_TEST) {
exit();
}
}
active = false;
}
stopTest
参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t5
StopTest
实现runnable接口,主要操作AbstractThreadGroup中的方法
run()
- JMeterContextService清零:JMeterContextService.startTest()
public static synchronized void startTest() {
if (testStart == 0) {
numberOfActiveThreads = 0;
testStart = System.currentTimeMillis();
JMeterUtils.setProperty("TESTSTART.MS",Long.toString(testStart));
}
}
public static synchronized void clearTotalThreads() {
totalThreads = 0;
numberOfThreadsStarted = 0;
numberOfThreadsFinished = 0;
}
- PreCompiler the Tashree
try {
PreCompiler compiler = new PreCompiler();
test.traverse(compiler);
} catch (RuntimeException e) {
log.error("Error occurred compiling the tree:", e);
JMeterUtils.reportErrorToUser("Error occurred compiling the tree: - see log file", e);
return; // no point continuing
}
- 利用SearchByClass解析所有TestStateListener 加入到testList中
SearchByClass<TestStateListener> testListeners = new SearchByClass<>(TestStateListener.class); // TL-S&E
test.traverse(testListeners);
// Merge in any additional test listeners
// currently only used by the function parser
testListeners.getSearchResults().addAll(testList);
- 触发上一步中解析的testListener的testStarted方法:ResultCollector会递增instanceCount,初始化fileOutput;TestPlan会设置FileServer的basedir,添加classpath; JavaSampler会初始化真正要跑的AbstractJavaSamplerClient类;
- 利用SearchByClass解析所有ThreadGroup(包括SetupThreadGroup,ThreadGroup, PostThreadGroup)
notifyTestListenersOfStart(testListeners);
private void notifyTestListenersOfStart(SearchByClass<TestStateListener> testListeners) {
for (TestStateListener tl : testListeners.getSearchResults()) {
if (tl instanceof TestBean) {
TestBeanHelper.prepare((TestElement) tl);
}
if (host == null) {
tl.testStarted();
} else {
tl.testStarted(host);
}
}
}
- 实例化一个ListenerNotifier实例,用来通知事件发生
ListenerNotifier notifier = new ListenerNotifier();
- 启动所有SetupThreadGroup(一般情况下没有SetupThreadGroup)并等待到都结束
if (setupIter.hasNext()) {
log.info("Starting setUp thread groups");
while (running && setupIter.hasNext()) {// for each setup thread group
AbstractThreadGroup group = setupIter.next();
groupCount++;
String groupName = group.getName();
log.info("Starting setUp ThreadGroup: " + groupCount + " : " + groupName);
startThreadGroup(group, groupCount, setupSearcher, testLevelElements, notifier);
if (serialized && setupIter.hasNext()) {
log.info("Waiting for setup thread group: " + groupName
+ " to finish before starting next setup group");
group.waitThreadsStopped();
}
}
log.info("Waiting for all setup thread groups to exit");
// wait for all Setup Threads To Exit
waitThreadsStopped();
log.info("All Setup Threads have ended");
groupCount = 0;
JMeterContextService.clearTotalThreads();
}
- 进行一次gc后 开始跑真正的测试,即启动所有的ThreadGroup,这里会检查serialized属性,用来判断是否这些ThreadGroup串行执行
JMeterUtils.helpGC();
- 等待所有的ThreadGroup结束
while (running && iter.hasNext()) {// for each thread group
AbstractThreadGroup group = iter.next();
// ignore Setup and Post here. We could have filtered the searcher.
// but then
// future Thread Group objects wouldn't execute.
if (group instanceof SetupThreadGroup || group instanceof PostThreadGroup) {
continue;
}
groupCount++;
String groupName = group.getName();
log.info("Starting ThreadGroup: " + groupCount + " : " + groupName);
startThreadGroup(group, groupCount, searcher, testLevelElements, notifier);
if (serialized && iter.hasNext()) {
log.info("Waiting for thread group: " + groupName + " to finish before starting next group");
group.waitThreadsStopped();
}
} // end of thread groups
if (groupCount == 0) { // No TGs found
log.info("No enabled thread groups found");
} else {
if (running) {
log.info("All thread groups have been started");
} else {
log.info("Test stopped - no more thread groups will be started");
}
}
// wait for all Test Threads To Exit
waitThreadsStopped();
- 若有 PostThreadGroup(一般没有),执行所有的PostThreadGroup并等待至所有PostThreadGroup结束
if (postIter.hasNext()) {
groupCount = 0;
JMeterContextService.clearTotalThreads();
log.info("Starting tearDown thread groups");
if (mainGroups && !running) { // i.e. shutdown/stopped during main
// thread groups
running = shutdown && tearDownOnShutdown; // re-enable for
// tearDown if
// necessary
}
while (running && postIter.hasNext()) {// for each setup thread
// group
AbstractThreadGroup group = postIter.next();
groupCount++;
String groupName = group.getName();
log.info("Starting tearDown ThreadGroup: " + groupCount + " : " + groupName);
startThreadGroup(group, groupCount, postSearcher, testLevelElements, notifier);
if (serialized && postIter.hasNext()) {
log.info("Waiting for post thread group: " + groupName
+ " to finish before starting next post group");
group.waitThreadsStopped();
}
}
waitThreadsStopped(); // wait for Post threads to stop
}
- 触发第三步中解析的testListener的testEnded方法:JavaSampler会调用真正跑的AbstractJavaSamplerClient的teardownTest方法,可以打印该JavaSamplerClient测试总共花费的时间;ResultCollector用来将测试结果写如文件生成;reportTestPlan用来关闭文件。
notifyTestListenersOfEnd(testListeners);
JMeterContextService.endTest();
startThreadGroup
启动线程组,run方法中调用
private void startThreadGroup(AbstractThreadGroup group, int groupCount, SearchByClass<?> searcher,
List<?> testLevelElements, ListenerNotifier notifier) {
try {
int numThreads = group.getNumThreads();
JMeterContextService.addTotalThreads(numThreads);
boolean onErrorStopTest = group.getOnErrorStopTest();
boolean onErrorStopTestNow = group.getOnErrorStopTestNow();
boolean onErrorStopThread = group.getOnErrorStopThread();
boolean onErrorStartNextLoop = group.getOnErrorStartNextLoop();
String groupName = group.getName();
log.info("Starting " + numThreads + " threads for group " + groupName + ".");
if (onErrorStopTest) {
log.info("Test will stop on error");
} else if (onErrorStopTestNow) {
log.info("Test will stop abruptly on error");
} else if (onErrorStopThread) {
log.info("Thread will stop on error");
} else if (onErrorStartNextLoop) {
log.info("Thread will start next loop on error");
} else {
log.info("Thread will continue on error");
}
ListedHashTree threadGroupTree = (ListedHashTree) searcher.getSubTree(group);
threadGroupTree.add(group, testLevelElements);
groups.add(group);
group.start(groupCount, notifier, threadGroupTree, this);
} catch (JMeterStopTestException ex) { // NOSONAR Reported by log
JMeterUtils.reportErrorToUser("Error occurred starting thread group :" + group.getName()
+ ", error message:" + ex.getMessage() + ", \r\nsee log file for more details", ex);
return; // no point continuing
}
}
waitThreadsStopped
等待线程停止,run方法中调用
/**
* Wait for Group Threads to stop
*/
private void waitThreadsStopped() {
// ConcurrentHashMap does not need synch. here
for (AbstractThreadGroup threadGroup : groups) {
threadGroup.waitThreadsStopped();
}
}
/**
* Wait for all Group Threads to stop
*/
@Override
public void waitThreadsStopped() {
if (delayedStartup) {
waitThreadStopped(threadStarter);
}
for (Thread t : allThreads.values()) {
waitThreadStopped(t);
}
}
/**
* Wait for thread to stop
* @param thread Thread
*/
private void waitThreadStopped(Thread thread) {
if (thread != null) {
while (thread.isAlive()) {
try {
thread.join(WAIT_TO_DIE);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
学习备忘
原文连接 http://blog.csdn.net/yue530tomtom/article/details/78055365