Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API to create JMeter threads while test is running #4205

Closed
asfimport opened this issue Dec 29, 2016 · 2 comments
Closed

Add API to create JMeter threads while test is running #4205

asfimport opened this issue Dec 29, 2016 · 2 comments

Comments

@asfimport
Copy link
Collaborator

@pmouawad (Bug 60530):
Following :
#238

OS: All

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Created attachment BUG_60530.patch: Patch

BUG_60530.patch
Index: src/core/org/apache/jmeter/threads/AbstractThreadGroup.java
===================================================================
--- src/core/org/apache/jmeter/threads/AbstractThreadGroup.java	(revision 1776125)
+++ src/core/org/apache/jmeter/threads/AbstractThreadGroup.java	(working copy)
@@ -251,6 +251,8 @@
 
     public abstract void start(int groupCount, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine);
 
+    public abstract JMeterThread addNewThread(int delay, StandardJMeterEngine engine);
+
     public abstract boolean verifyThreadsStopped();
 
     public abstract void waitThreadsStopped();
Index: src/core/org/apache/jmeter/threads/JMeterThread.java
===================================================================
--- src/core/org/apache/jmeter/threads/JMeterThread.java	(revision 1776125)
+++ src/core/org/apache/jmeter/threads/JMeterThread.java	(working copy)
@@ -50,6 +50,7 @@
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.collections.HashTree;
 import org.apache.jorphan.collections.HashTreeTraverser;
+import org.apache.jorphan.collections.ListedHashTree;
 import org.apache.jorphan.collections.SearchByClass;
 import org.apache.jorphan.logging.LoggingManager;
 import org.apache.jorphan.util.JMeterError;
@@ -977,4 +978,12 @@
         this.threadGroup = group;
     }
 
+    public ListedHashTree getTestTree() {
+        return (ListedHashTree) testTree;
+    }
+
+    public ListenerNotifier getNotifier() {
+        return notifier;
+    }
+
 }
Index: src/core/org/apache/jmeter/threads/ThreadGroup.java
===================================================================
--- src/core/org/apache/jmeter/threads/ThreadGroup.java	(revision 1776125)
+++ src/core/org/apache/jmeter/threads/ThreadGroup.java	(working copy)
@@ -83,17 +83,24 @@
 
     // List of active threads
     private final Map<JMeterThread, Thread> allThreads = new ConcurrentHashMap<>();
+    private final Object addThreadLock = new Object();
 
     /**
      * Is test (still) running?
      */
     private volatile boolean running = false;
 
+    private int groupNumber;
+
     /**
      * Are we using delayed startup?
      */
     private boolean delayedStartup;
 
+    private ListenerNotifier notifier;
+
+    private ListedHashTree threadGroupTree;
+
     /**
      * No-arg constructor.
      */
@@ -257,38 +264,46 @@
     }
 
     @Override
-    public void start(int groupCount, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
+    public void start(int groupNum, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
         running = true;
+        groupNumber = groupNum;
+        this.notifier = notifier;
+        this.threadGroupTree = threadGroupTree;
         int numThreads = getNumThreads();
         int rampUpPeriodInSeconds = getRampUp();
         float perThreadDelayInMillis = (float) (rampUpPeriodInSeconds * 1000) / (float) getNumThreads();
 
         delayedStartup = isDelayedStartup(); // Fetch once; needs to stay constant
-        log.info("Starting thread group number " + groupCount
+        log.info("Starting thread group number " + groupNumber
                 + " threads " + numThreads
                 + " ramp-up " + rampUpPeriodInSeconds
                 + " perThread " + perThreadDelayInMillis
                 + " delayedStart=" + delayedStartup);
         if (delayedStartup) {
-            threadStarter = new Thread(new ThreadStarter(groupCount, notifier, threadGroupTree, engine), getName()+"-ThreadStarter");
+            threadStarter = new Thread(new ThreadStarter(notifier, threadGroupTree, engine), getName()+"-ThreadStarter");
             threadStarter.setDaemon(true);
             threadStarter.start();
             // N.B. we don't wait for the thread to complete, as that would prevent parallel TGs
         } else {
             long now = System.currentTimeMillis(); // needs to be same time for all threads in the group
             final JMeterContext context = JMeterContextService.getContext();
-            for (int i = 0; running && i < numThreads; i++) {
-                JMeterThread jmThread = makeThread(groupCount, notifier, threadGroupTree, engine, i, context);
-                scheduleThread(jmThread, now); // set start and end time
-                jmThread.setInitialDelay((int)(i * perThreadDelayInMillis));
-                Thread newThread = new Thread(jmThread, jmThread.getThreadName());
-                registerStartedThread(jmThread, newThread);
-                newThread.start();
+            for (int threadNum = 0; running && threadNum < numThreads; threadNum++) {
+                startNewThread(notifier, threadGroupTree, engine, threadNum, context, now, (int)(threadNum * perThreadDelayInMillis));
             }
         }
-        log.info("Started thread group number "+groupCount);
+        log.info("Started thread group number "+groupNumber);
     }
 
+    private JMeterThread startNewThread(ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine,
+            int threadNum, final JMeterContext context, long now, int delay) {
+        JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, threadNum, context);
+        scheduleThread(jmThread, now); // set start and end time
+        jmThread.setInitialDelay(delay);
+        Thread newThread = new Thread(jmThread, jmThread.getThreadName());
+        registerStartedThread(jmThread, newThread);
+        newThread.start();
+        return jmThread;
+    }
     /**
      * Register Thread when it starts
      * @param jMeterThread {@link JMeterThread}
@@ -298,7 +313,7 @@
         allThreads.put(jMeterThread, newThread);
     }
 
-    private JMeterThread makeThread(int groupCount,
+    private JMeterThread makeThread(
             ListenerNotifier notifier, ListedHashTree threadGroupTree,
             StandardJMeterEngine engine, int i, 
             JMeterContext context) { // N.B. Context needs to be fetched in the correct thread
@@ -311,7 +326,7 @@
         jmeterThread.setThreadNum(i);
         jmeterThread.setThreadGroup(this);
         jmeterThread.setInitialContext(context);
-        final String threadName = groupName + " " + (groupCount) + "-" + (i + 1);
+        final String threadName = groupName + " " + groupNumber + "-" + (i + 1);
         jmeterThread.setThreadName(threadName);
         jmeterThread.setEngine(engine);
         jmeterThread.setOnErrorStopTest(onErrorStopTest);
@@ -321,6 +336,21 @@
         return jmeterThread;
     }
 
+    @Override
+    public JMeterThread addNewThread(int delay, StandardJMeterEngine engine) {
+        long now = System.currentTimeMillis();
+        JMeterContext context = JMeterContextService.getContext();
+        JMeterThread newJmThread;
+        synchronized (addThreadLock) {
+            int numThreads = getNumThreads();
+            newJmThread = startNewThread(notifier, threadGroupTree, engine, numThreads, context, now, delay);
+            setNumThreads(numThreads + 1);
+        }
+        JMeterContextService.addTotalThreads( 1 );
+        log.info("Started new thread in group " + groupNumber );
+        return newJmThread;
+    }
+
     /**
      * Stop thread called threadName:
      * <ol>
@@ -504,15 +534,13 @@
      */
     class ThreadStarter implements Runnable {
 
-        private final int groupCount;
         private final ListenerNotifier notifier;
         private final ListedHashTree threadGroupTree;
         private final StandardJMeterEngine engine;
         private final JMeterContext context;
 
-        public ThreadStarter(int groupCount, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
+        public ThreadStarter(ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
             super();
-            this.groupCount = groupCount;
             this.notifier = notifier;
             this.threadGroupTree = threadGroupTree;
             this.engine = engine;
@@ -584,7 +612,7 @@
                     if (usingScheduler && System.currentTimeMillis() > endtime) {
                         break; // no point continuing beyond the end time
                     }
-                    JMeterThread jmThread = makeThread(groupCount, notifier, threadGroupTree, engine, i, context);
+                    JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, i, context);
                     jmThread.setInitialDelay(0);   // Already waited
                     if (usingScheduler) {
                         jmThread.setScheduled(true);

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Author: pmouawad
Date: Fri Dec 30 17:59:35 2016
New Revision: 1776612

URL: http://svn.apache.org/viewvc?rev=1776612&view=rev
Log:
#4205 - Add API to create JMeter threads while test is running
Based on a contribution by Logan Mauzaize & Maxime Chassagneux
#4205

Modified:
jmeter/trunk/src/core/org/apache/jmeter/threads/AbstractThreadGroup.java
jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java
jmeter/trunk/src/core/org/apache/jmeter/threads/ThreadGroup.java
jmeter/trunk/xdocs/changes.xml

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

No branches or pull requests

1 participant