Author: sebb
Date: Mon May  8 16:25:03 2006
New Revision: 405219

URL: http://svn.apache.org/viewcvs?rev=405219&view=rev
Log:
Bug 39447 - new Constant Throughput Timer algorithm

Modified:
    
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java
    
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerBeanInfo.java
    
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerResources.properties
    jakarta/jmeter/branches/rel-2-1/xdocs/usermanual/component_reference.xml

Modified: 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java
URL: 
http://svn.apache.org/viewcvs/jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java?rev=405219&r1=405218&r2=405219&view=diff
==============================================================================
--- 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java
 (original)
+++ 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java
 Mon May  8 16:25:03 2006
@@ -17,6 +17,9 @@
 
 package org.apache.jmeter.timers;
 
+import java.util.Hashtable;
+import java.util.Map;
+
 import org.apache.jmeter.engine.event.LoopIterationEvent;
 import org.apache.jmeter.testbeans.TestBean;
 import org.apache.jmeter.testelement.AbstractTestElement;
@@ -28,13 +31,20 @@
 
 /**
  * This class implements a constant throughput timer. A Constant Throughtput
- * Timer paces the samplers under it's influence so that the total number of
+ * Timer paces the samplers under its influence so that the total number of
  * samples per unit of time approaches a given constant as much as possible.
  * 
+ * There are two different ways of pacing the requests:
+ * - delay each thread according to when it last ran
+ * - delay each thread according to when any thread last ran 
  */
 public class ConstantThroughputTimer extends AbstractTestElement implements 
Timer, TestListener, TestBean {
        private static final long serialVersionUID = 3;
 
+    private static class ThroughputInfo{
+        final Object MUTEX = new Object();
+        long lastScheduledTime = 0;
+    }
        private static final Logger log = LoggingManager.getLoggerForClass();
 
        private static final double MILLISEC_PER_MIN = 60000.0;
@@ -55,6 +65,13 @@
         */
        private double throughput;
 
+    //For calculating throughput across all threads
+    private final static ThroughputInfo allThreadsInfo = new ThroughputInfo();
+    
+    //For holding the ThrougputInfo objects for all ThreadGroups. Keyed by 
ThreadGroup objects
+    private final static Map threadGroupsInfoMap = new Hashtable();
+    
+
        /**
         * Constructor for a non-configured ConstantThroughputTimer.
         */
@@ -85,9 +102,9 @@
        }
 
        public void setCalcMode(String mode) {
-               // TODO find better way to get modeInt
+        this.calcMode = mode;
+        // TODO find better way to get modeInt
                this.modeInt = 
ConstantThroughputTimerBeanInfo.getCalcModeAsInt(calcMode);
-               this.calcMode = mode;
        }
 
        /**
@@ -123,23 +140,64 @@
 
        // Calculate the delay based on the mode
        private long calculateDelay() {
-               long offset = 0;
+               long delay = 0;
         // N.B. we fetch the throughput each time, as it may vary during a test
-               long rate = (long) (MILLISEC_PER_MIN / getThroughput());
+               long msPerRequest = (long) (MILLISEC_PER_MIN / getThroughput());
                switch (modeInt) {
                case 1: // Total number of threads
-                       offset = JMeterContextService.getNumberOfThreads() * 
rate;
+                       delay = JMeterContextService.getNumberOfThreads() * 
msPerRequest;
                        break;
+            
                case 2: // Active threads in this group
-                       offset = 
JMeterContextService.getContext().getThread().getThreadGroup().getNumberOfThreads()
 * rate;
+                       delay = 
JMeterContextService.getContext().getThreadGroup().getNumberOfThreads() * 
msPerRequest;
                        break;
+            
+        case 3: // All threads - alternate calculation
+            delay = calculateSharedDelay(allThreadsInfo,msPerRequest);
+            break;
+            
+        case 4: //All threads in this group - alternate calculation
+            final org.apache.jmeter.threads.ThreadGroup group = 
+                JMeterContextService.getContext().getThreadGroup();
+            ThroughputInfo groupInfo;
+            synchronized (threadGroupsInfoMap) {
+                groupInfo = (ThroughputInfo)threadGroupsInfoMap.get(group);
+                if (groupInfo == null) {
+                    groupInfo = new ThroughputInfo();
+                    threadGroupsInfoMap.put(group, groupInfo);
+                }
+            }
+            delay = calculateSharedDelay(groupInfo,msPerRequest);
+            break;
+            
                default:
-                       offset = rate; // i.e. rate * 1
+                       delay = msPerRequest; // i.e. * 1
                        break;
                }
-               return offset;
+               return delay;
        }
 
+    private long calculateSharedDelay(ThroughputInfo info, long 
milliSecPerRequest) {
+        final long now = System.currentTimeMillis();
+        final long calculatedDelay;
+
+        //Synchronize on the info object's MUTEX to ensure
+        //Multiple threads don't update the scheduled time simultaneously
+        synchronized (info.MUTEX) {
+            final long nextRequstTime = info.lastScheduledTime + 
milliSecPerRequest;
+            info.lastScheduledTime = Math.max(now, nextRequstTime);
+            calculatedDelay = info.lastScheduledTime - now;
+        }
+        
+        return Math.max(calculatedDelay, 0);
+    }
+
+    private synchronized void reset() {
+        allThreadsInfo.lastScheduledTime = 0;
+        threadGroupsInfoMap.clear();
+        previousTime = 0;
+    }   
+
        /**
         * Provide a description of this timer class.
         * 
@@ -157,10 +215,10 @@
         * 
         * @see org.apache.jmeter.testelement.TestListener#testStarted()
         */
-       public synchronized void testStarted()// synch to protect targetTime
+       public void testStarted()
        {
                log.debug("Test started - reset throughput calculation.");
-               previousTime = 0;
+        reset();
        }
 
        /*

Modified: 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerBeanInfo.java
URL: 
http://svn.apache.org/viewcvs/jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerBeanInfo.java?rev=405219&r1=405218&r2=405219&view=diff
==============================================================================
--- 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerBeanInfo.java
 (original)
+++ 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerBeanInfo.java
 Mon May  8 16:25:03 2006
@@ -1,6 +1,5 @@
-// $Header$
 /*
- * Copyright 2004 The Apache Software Foundation.
+ * Copyright 2004,2006 The Apache Software Foundation.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,26 +25,29 @@
 /**
  * BeanInfo for the ConstantThroughputTimer.
  * 
- * @version $Revision$ updated on $Date$
  */
 public class ConstantThroughputTimerBeanInfo extends BeanInfoSupport {
-       private static final String[] tags = new String[3];
+       private static final String[] tags = new String[5];
 
        public ConstantThroughputTimerBeanInfo() {
                super(ConstantThroughputTimer.class);
 
                ResourceBundle rb = (ResourceBundle) 
getBeanDescriptor().getValue(RESOURCE_BUNDLE);
-               tags[0] = rb.getString("calcMode.1");// These must agree with 
the
-                                                                               
                // Timer
-               tags[1] = rb.getString("calcMode.2");
-               tags[2] = rb.getString("calcMode.3");
-               createPropertyGroup("delay", new String[] { "throughput", 
"calcMode" });
+//       These must agree with the Timer resources
+        tags[0] = rb.getString("calcMode.1"); //$NON-NLS-1$
+               tags[1] = rb.getString("calcMode.2"); //$NON-NLS-1$
+               tags[2] = rb.getString("calcMode.3"); //$NON-NLS-1$
+        tags[3] = rb.getString("calcMode.4"); //$NON-NLS-1$
+        tags[4] = rb.getString("calcMode.5"); //$NON-NLS-1$
+               createPropertyGroup("delay",  //$NON-NLS-1$
+                new String[] { "throughput", //$NON-NLS-1$
+                "calcMode" }); //$NON-NLS-1$
 
-               PropertyDescriptor p = property("throughput");
+               PropertyDescriptor p = property("throughput"); //$NON-NLS-1$
                p.setValue(NOT_UNDEFINED, Boolean.TRUE);
                p.setValue(DEFAULT, new Double(0.0));
 
-               p = property("calcMode");
+               p = property("calcMode"); //$NON-NLS-1$
                p.setValue(NOT_UNDEFINED, Boolean.TRUE);
                p.setValue(DEFAULT, tags[0]);
                p.setValue(NOT_OTHER, Boolean.TRUE);

Modified: 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerResources.properties
URL: 
http://svn.apache.org/viewcvs/jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerResources.properties?rev=405219&r1=405218&r2=405219&view=diff
==============================================================================
--- 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerResources.properties
 (original)
+++ 
jakarta/jmeter/branches/rel-2-1/src/components/org/apache/jmeter/timers/ConstantThroughputTimerResources.properties
 Mon May  8 16:25:03 2006
@@ -6,4 +6,6 @@
 calcMode.shortDescription=The Constant Throughput Timer used to delay each 
thread as though it was the only thread in the test.  Now, it calculates the 
delay taking into account the number of active threads in the test or the 
thread group.
 calcMode.1=this thread only
 calcMode.2=all active threads
-calcMode.3=all active threads in current thread group
\ No newline at end of file
+calcMode.3=all active threads in current thread group
+calcMode.4=all active threads (shared)
+calcMode.5=all active threads in current thread group (shared)
\ No newline at end of file

Modified: 
jakarta/jmeter/branches/rel-2-1/xdocs/usermanual/component_reference.xml
URL: 
http://svn.apache.org/viewcvs/jakarta/jmeter/branches/rel-2-1/xdocs/usermanual/component_reference.xml?rev=405219&r1=405218&r2=405219&view=diff
==============================================================================
--- jakarta/jmeter/branches/rel-2-1/xdocs/usermanual/component_reference.xml 
(original)
+++ jakarta/jmeter/branches/rel-2-1/xdocs/usermanual/component_reference.xml 
Mon May  8 16:25:03 2006
@@ -2445,11 +2445,19 @@
   <property name="Calculate Throughput based on" required="Yes">
    <ul>
     <li>this thread only - each thread will try to maintain the target 
throughput. The overall throughput will be proportional to the number of active 
threads.</li>
-    <li>all active threads in current thread group - the target throughput is 
divided amongst all the active threads in the group.</li>
-    <li>all active threads - the target throughput is divided amongst all the 
active threads in all Thread Groups. 
+    <li>all active threads in current thread group - the target throughput is 
divided amongst all the active threads in the group. 
+    Each thread will delay as needed, based on when it last ran.</li>
+    <li>all active threads - the target throughput is divided amongst all the 
active threads in all Thread Groups.
+    Each thread will delay as needed, based on when it last ran.
     In this case, each other Thread Group will need a Constant Throughput 
timer with the same settings.</li>
    </ul>
+    <li>all active threads in current thread group (shared) - as above, but 
each thread is delayed based on when any thread in the group last ran.</li>
+    <li>all active threads (shared) - as above; each thread is delayed based 
on when any thread last ran.</li>
+   </ul>
   </property>
+  <p>The shared and non-shared algorithms both aim to generate the desired 
thoughput, and will produce similar results.
+  The shared algorithm should generate a more accurate overall transaction 
rate.
+  The non-shared algortihm should generate a more even spread of transactions 
across threads.</p>
 </properties>
 
 </component>



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to