jmeter 소스 ---StandardJMeterEngine

개요


jmter tests를 실행하여 로컬 GUI 및 비 GUI 호출에 직접 사용하거나 서버 모드에서 실행할 때 RemoteJMeterEngineImpl에서 시작합니다.

소개


JMeter Engine Impl에서 해석한 부분을 결합해서 볼 수 있습니다.

주요 변수


영혼급 변수, 키워드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 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 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 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()

  • JMeterContext Service 지우기: JMeterContext Service.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 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은 File Server의 basedir를 설정하고classpath를 추가합니다.JavaSampler는 실제로 뛸 Abstract JavaSampler Client 클래스를 초기화합니다
  • SearchByClass를 이용하여 모든 ThreadGroup(SetupThreadGroup, ThreadGroup, PostThreadGroup 포함)을 분석합니다
  • notifyTestListenersOfStart(testListeners);
    
    private void notifyTestListenersOfStart(SearchByClass testListeners) {
        for (TestStateListener tl : testListeners.getSearchResults()) {
            if (tl instanceof TestBean) {
                TestBeanHelper.prepare((TestElement) tl);
            }
            if (host == null) {
                tl.testStarted();
            } else {
                tl.testStarted(host);
            }
        }
    }
  • 이벤트 발생을 알리는 Listener Notifier 실례를 실례화합니다
  • 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는 진정으로 달리는 AbstractJavaSampler Client의teardown Test 방법을 호출합니다. 이 JavaSampler Client 테스트에 걸리는 시간을 출력할 수 있습니다.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
    see 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

    좋은 웹페이지 즐겨찾기