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

Excludes timer duration from Transaction Controller runtime in report #1851

Closed
asfimport opened this issue Jan 19, 2007 · 14 comments
Closed

Comments

@asfimport
Copy link
Collaborator

Holger Isenberg (Bug 41418):
The Transaction Controller can be used to simplify the Summary
Report. However, when you need the runtime summary for all elements
of a transaction controller, the timer durations are added.

With this patch (against SVN rel-2-2 r497856) a check box is added to
the Transaction Controller to exclude all timer durations from the
Summary Report.

Votes in Bugzilla: 2
OS: All

@asfimport
Copy link
Collaborator Author

Holger Isenberg (migrated from Bugzilla):
Created attachment transcation-timer-exclusion.patch: adds checkbox to Transaction Controller to exclude timer durations

transcation-timer-exclusion.patch
Index: src/components/org/apache/jmeter/control/gui/TransactionControllerGui.java
===================================================================
--- src/components/org/apache/jmeter/control/gui/TransactionControllerGui.java	(revision 497882)
+++ src/components/org/apache/jmeter/control/gui/TransactionControllerGui.java	(working copy)
@@ -20,16 +20,28 @@
 
 import java.awt.BorderLayout;
 
+import org.apache.jmeter.control.ForeachController;
 import org.apache.jmeter.control.TransactionController;
 import org.apache.jmeter.control.gui.AbstractControllerGui;
+import org.apache.jmeter.gui.util.VerticalPanel;
 import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterUtils;
 
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
 /**
  * A Transaction controller component.
  * 
  * @version $Revision$ on $Date$
  */
 public class TransactionControllerGui extends AbstractControllerGui {
+
+	// add duration of timers to total con
+	private JCheckBox includeTimers;
+
 	/**
 	 * Create a new TransactionControllerGui instance.
 	 */
@@ -37,6 +49,20 @@
 		init();
 	}
 
+	/**
+	 * A newly created component can be initialized with the contents of a Test
+	 * Element object by calling this method. The component is responsible for
+	 * querying the Test Element object for the relevant information to display
+	 * in its GUI.
+	 * 
+	 * @param element
+	 *            the TestElement to configure
+	 */
+	public void configure(TestElement element) {
+		super.configure(element);
+		includeTimers.setSelected(((TransactionController) element).getIncludeTimers());
+	}
+	
 	/* Implements JMeterGUIComponent.createTestElement() */
 	public TestElement createTestElement() {
 		TransactionController lc = new TransactionController();
@@ -45,8 +71,11 @@
 	}
 
 	/* Implements JMeterGUIComponent.modifyTestElement(TestElement) */
-	public void modifyTestElement(TestElement el) {
-		configureTestElement(el);
+	public void modifyTestElement(TestElement lc) {
+		configureTestElement(lc);
+		if (lc instanceof TransactionController) {
+			((TransactionController) lc).setIncludeTimers(includeTimers.isSelected());
+		}
 	}
 
 	public String getLabelResource() {
@@ -60,5 +89,24 @@
 		setLayout(new BorderLayout());
 		setBorder(makeBorder());
 		add(makeTitlePanel(), BorderLayout.NORTH);
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(createPanel(), BorderLayout.NORTH);
+		add(mainPanel, BorderLayout.CENTER);
 	}
+	
+	/**
+	 * Create a GUI panel containing the possible options
+	 * 
+	 * @return a GUI panel containing the possible options
+	 */
+	private JPanel createPanel() {
+		VerticalPanel panel = new VerticalPanel();
+
+		// Checkbox
+		includeTimers = new JCheckBox(JMeterUtils.getResString("transaction_controller_include_timers"), true);
+
+		panel.add(includeTimers);
+
+		return panel;
+	}
 }
Index: src/components/org/apache/jmeter/control/TransactionController.java
===================================================================
--- src/components/org/apache/jmeter/control/TransactionController.java	(revision 497882)
+++ src/components/org/apache/jmeter/control/TransactionController.java	(working copy)
@@ -21,8 +21,10 @@
 import java.io.Serializable;
 
 import org.apache.jmeter.samplers.SampleEvent;
+import org.apache.jmeter.samplers.SampleListener;
 import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.samplers.Sampler;
+import org.apache.jmeter.testelement.property.BooleanProperty;
 import org.apache.jmeter.threads.JMeterContext;
 import org.apache.jmeter.threads.JMeterThread;
 import org.apache.jmeter.threads.JMeterVariables;
@@ -35,15 +37,19 @@
  * Transaction Controller to measure transaction times
  * 
  */
-public class TransactionController extends GenericController implements Controller, Serializable {
+public class TransactionController extends GenericController implements Controller, SampleListener, Serializable {
 	protected static final Logger log = LoggingManager.getLoggerForClass();
 
+	private final static String INCLUDE_TIMERS = "TransactionController.includeTimers";
+
 	transient private String threadName;
 
 	transient private ListenerNotifier lnf;
 
 	transient private SampleResult res;
 
+	transient private long pauseTime, prevEndTime;
+	
 	/**
 	 * Creates a Transaction Controller
 	 */
@@ -76,6 +82,8 @@
 			calls = 0;
 			res = new SampleResult();
 			res.sampleStart();
+			prevEndTime = res.getStartTime();
+			pauseTime = 0;
 		}
 
 		calls++;
@@ -88,6 +96,7 @@
 			if (res == null) {
 				log_debug("already called");
 			} else {
+				res.incIdleTime(pauseTime);
 				res.sampleEnd();
 				res.setSuccessful(true);
 				res.setSampleLabel(getName());
@@ -111,4 +120,26 @@
 
 		return returnValue;
 	}
+	
+	public void sampleOccurred(SampleEvent e) {
+		if (!getIncludeTimers()) {
+			SampleResult r = e.getResult();
+			pauseTime += r.getEndTime() - r.getTime() - prevEndTime;
+			prevEndTime = r.getEndTime();
+		}
+	}
+	
+	public void sampleStarted(SampleEvent e) {
+	}
+	
+	public void sampleStopped(SampleEvent e) {
+	}
+	
+	public void setIncludeTimers(boolean b) {
+		setProperty(new BooleanProperty(INCLUDE_TIMERS, b));
+	}
+
+	public boolean getIncludeTimers() {
+		return getPropertyAsBoolean(INCLUDE_TIMERS, false);
+	}
 }
Index: src/core/org/apache/jmeter/resources/messages.properties
===================================================================
--- src/core/org/apache/jmeter/resources/messages.properties	(revision 497856)
+++ src/core/org/apache/jmeter/resources/messages.properties	(working copy)
@@ -712,6 +712,7 @@
 timelim=Time limit
 time_format=Format string for SimpleDateFormat (optional)
 transaction_controller_title=Transaction Controller
+transaction_controller_include_timers=Include timer duration in runtime summary.
 unbind=Thread Unbind
 uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
 uniform_timer_memo=Adds a random delay with a uniform distribution

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
Seems to be a bit missing -

The method incIdleTime() is not defined for SampleResult

@asfimport
Copy link
Collaborator Author

Holger Isenberg (migrated from Bugzilla):
Created attachment transcation-timer-exclusion-part2.patch: missing part 2 of patch above

transcation-timer-exclusion-part2.patch
Index: src/core/org/apache/jmeter/samplers/SampleResult.java
===================================================================
--- src/core/org/apache/jmeter/samplers/SampleResult.java	(revision 497868)
+++ src/core/org/apache/jmeter/samplers/SampleResult.java	(working copy)
@@ -724,6 +724,10 @@
 		setEndTime(end);
 	}
 
+	public void incIdleTime(long pause) {
+		idleTime += pause;
+	}
+	
 	/**
 	 * Record the start time of a sample
 	 * 

@asfimport
Copy link
Collaborator Author

Alf Hogemark (migrated from Bugzilla):
This suggested patch adds a jmeter.properties option to control how the
duration o f the TransactionSample is made. I do not have time to add an GUI
option at the moment, and I'm guessing that a property to control the behaviour
should be sufficient short term.

Currently, the TransactionSample will have the start of the first subsample as
it's start time, and the end of the last subsample of the transaction as it's
end times. This means that the time it takes to run pre-, postprocessors,
assertions and timers inside a TransactionController will be included in the
duration of the transaction sample.

With this patch, and the jmeter.properties option set to true, the transaction
sample will report the sum of the subsamples as it's duration. This will then
not include the time for pre-, postprocessors, timers and assertions.

Created attachment patch_for_41418.patch: Suggested patch

patch_for_41418.patch
Index: C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/src/core/org/apache/jmeter/control/TransactionSampler.java
===================================================================
--- C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/src/core/org/apache/jmeter/control/TransactionSampler.java	(revision 552554)
+++ C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/src/core/org/apache/jmeter/control/TransactionSampler.java	(working copy)
@@ -27,13 +27,18 @@
 import org.apache.jmeter.samplers.Entry;
 import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.samplers.Sampler;
+import org.apache.jmeter.samplers.TransactionSampleResult;
+import org.apache.jmeter.util.JMeterUtils;
 
 /**
  * Transaction Controller to measure transaction times
  * 
  */
 public class TransactionSampler extends AbstractSampler {
-  private boolean transactionDone = false;
+	private static final boolean DURATION_AS_SUM_OF_SUBSAMPLES 
+    = JMeterUtils.getPropDefault("TransactionController.duration_is_sum_of_subsamples", false);// $NON-NLS-1$
+	
+	private boolean transactionDone = false;
 
     private TransactionController transactionController; 
     
@@ -52,7 +57,15 @@
 	public TransactionSampler(TransactionController controller, String name) {
         transactionController = controller;
 		setName(name); // ensure name is available for debugging
-		transactionSampleResult = new SampleResult();
+		// Check if duration should be reported as actual time to
+		// complete the transaction, or just as the sum of the duration
+		// of the subsamples
+		if(!DURATION_AS_SUM_OF_SUBSAMPLES) {
+			transactionSampleResult = new SampleResult();
+		}
+		else {
+			transactionSampleResult = new TransactionSampleResult();
+		}
 		transactionSampleResult.setSampleLabel(name);
 		// Assume success
 		transactionSampleResult.setSuccessful(true);
Index: C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/src/core/org/apache/jmeter/samplers/TransactionSampleResult.java
===================================================================
--- C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/src/core/org/apache/jmeter/samplers/TransactionSampleResult.java	(revision 0)
+++ C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/src/core/org/apache/jmeter/samplers/TransactionSampleResult.java	(revision 0)
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+
+package org.apache.jmeter.samplers;
+
+/**
+ * This is a class for handling TransactionSample results, so that the
+ * duration is reported as the sum of the duration of the subsamples of
+ * the transaction.
+ */
+public class TransactionSampleResult extends SampleResult {
+    private boolean hasCalculatedDuration = false;
+
+	/**
+	 * @return the end time
+	 */
+	public long getEndTime() {
+		if(!hasCalculatedDuration) {
+			calculateDuration();
+		}
+		return super.getEndTime();
+	}
+	
+	public long getTime() {
+		if(!hasCalculatedDuration) {
+			calculateDuration();
+		}
+		return super.getTime();
+	}
+	
+	private void calculateDuration() {
+		SampleResult[] subResults = getSubResults();
+		if(subResults != null) {
+			long duration = 0l;
+			for(int i = 0; i < subResults.length; i++) {
+				duration = subResults[i].getTime();
+			}
+			setEndTime(getStartTime() + duration);
+		}
+		hasCalculatedDuration = true;
+	}
+}
Index: C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/bin/jmeter.properties
===================================================================
--- C:/Documents and Settings/alf/workspace/Jmeter 2.2 writable/bin/jmeter.properties	(revision 552554)
@@ -528,6 +530,15 @@
 # Default is true. Use false to revert to original behaviour
 #CookieManager.delete_null_cookies=true
 
+# TransactionController behaviour - should duration be reported as actual
+# duration from start of transaction until transaction is done. This will
+# include time spent running Jmeter pre- and postprocessors, timers,
+# and assertions.
+# If the flag is false, or not present, actual duation will be reported.
+# If the flag is true, then the duration will be reported as the sum of
+# the duration of the subsamples.
+#TransactionController.duration_is_sum_of_subsamples=true
+
 # (2.0.3) JMeterThread behaviour has been changed to set the started flag before
 # the controllers are initialised. This is so controllers can access variables earlier. 
 # In case this causes problems, the previous behaviour can be restored by uncommenting

@asfimport
Copy link
Collaborator Author

Alf Hogemark (migrated from Bugzilla):
The attached testplan shows that both timers are included in the duration of
the transaction sample.
So to correct my statement above slightly : by default, the end timestamp of
the transaction sample is set to the timestamp when the transaction controller
figures out that there are no more subsamples to sample in the transaction, and
not to the end time of the last subsample, as I said in my previous comment.

Created attachment test_tc_timer.jmx: Simple testplan to show that timer is included

test_tc_timer.jmx
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="1.8">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Trådgruppe" enabled="true">
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Løkke kontroller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">1</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <longProp name="ThreadGroup.start_time">1183198107000</longProp>
        <longProp name="ThreadGroup.end_time">1183198107000</longProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>
      <hashTree>
        <TransactionController guiclass="TransactionControllerGui" testclass="TransactionController" testname="Transaction Controller" enabled="true"/>
        <hashTree>
          <ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Konstant timer" enabled="true">
            <stringProp name="ConstantTimer.delay">1000</stringProp>
          </ConstantTimer>
          <hashTree/>
          <JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java Request" enabled="true">
            <elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
              <collectionProp name="Arguments.arguments">
                <elementProp name="Sleep_Time" elementType="Argument">
                  <stringProp name="Argument.name">Sleep_Time</stringProp>
                  <stringProp name="Argument.value">100</stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="Sleep_Mask" elementType="Argument">
                  <stringProp name="Argument.name">Sleep_Mask</stringProp>
                  <stringProp name="Argument.value">0xFF</stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="Label" elementType="Argument">
                  <stringProp name="Argument.name">Label</stringProp>
                  <stringProp name="Argument.value"></stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="ResponseCode" elementType="Argument">
                  <stringProp name="Argument.name">ResponseCode</stringProp>
                  <stringProp name="Argument.value"></stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="ResponseMessage" elementType="Argument">
                  <stringProp name="Argument.name">ResponseMessage</stringProp>
                  <stringProp name="Argument.value"></stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="Status" elementType="Argument">
                  <stringProp name="Argument.name">Status</stringProp>
                  <stringProp name="Argument.value">OK</stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="SamplerData" elementType="Argument">
                  <stringProp name="Argument.name">SamplerData</stringProp>
                  <stringProp name="Argument.value"></stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
                <elementProp name="ResultData" elementType="Argument">
                  <stringProp name="Argument.name">ResultData</stringProp>
                  <stringProp name="Argument.value"></stringProp>
                  <stringProp name="Argument.metadata">=</stringProp>
                </elementProp>
              </collectionProp>
            </elementProp>
            <stringProp name="classname">org.apache.jmeter.protocol.java.test.JavaTest</stringProp>
          </JavaSampler>
          <hashTree/>
          <ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Konstant timer" enabled="true">
            <stringProp name="ConstantTimer.delay">2000</stringProp>
          </ConstantTimer>
          <hashTree/>
          <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="Vis resultattre" enabled="true">
            <boolProp name="ResultCollector.error_logging">false</boolProp>
            <objProp>
              <value class="SampleSaveConfiguration">
                <time>true</time>
                <latency>true</latency>
                <timestamp>true</timestamp>
                <success>true</success>
                <label>true</label>
                <code>true</code>
                <message>true</message>
                <threadName>true</threadName>
                <dataType>true</dataType>
                <encoding>false</encoding>
                <assertions>true</assertions>
                <subresults>true</subresults>
                <responseData>false</responseData>
                <samplerData>false</samplerData>
                <xml>true</xml>
                <fieldNames>false</fieldNames>
                <responseHeaders>false</responseHeaders>
                <requestHeaders>false</requestHeaders>
                <responseDataOnError>false</responseDataOnError>
                <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
                <assertionsResultsToSave>0</assertionsResultsToSave>
                <bytes>true</bytes>
              </value>
              <name>saveConfig</name>
            </objProp>
            <stringProp name="filename"></stringProp>
          </ResultCollector>
          <hashTree/>
          <ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
            <boolProp name="ResultCollector.error_logging">false</boolProp>
            <objProp>
              <value class="SampleSaveConfiguration">
                <time>true</time>
                <latency>true</latency>
                <timestamp>true</timestamp>
                <success>true</success>
                <label>true</label>
                <code>true</code>
                <message>true</message>
                <threadName>true</threadName>
                <dataType>true</dataType>
                <encoding>false</encoding>
                <assertions>true</assertions>
                <subresults>true</subresults>
                <responseData>false</responseData>
                <samplerData>false</samplerData>
                <xml>true</xml>
                <fieldNames>false</fieldNames>
                <responseHeaders>false</responseHeaders>
                <requestHeaders>false</requestHeaders>
                <responseDataOnError>false</responseDataOnError>
                <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
                <assertionsResultsToSave>0</assertionsResultsToSave>
                <bytes>true</bytes>
              </value>
              <name>saveConfig</name>
            </objProp>
            <stringProp name="filename"></stringProp>
          </ResultCollector>
          <hashTree/>
        </hashTree>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

@asfimport
Copy link
Collaborator Author

Holger Isenberg (migrated from Bugzilla):
This is an updated version of my patch against the current svn version 2.3
r575019

Created attachment transaction-timer-exclusion.patch: Updated patch against current svn version (2.3 r575019)

transaction-timer-exclusion.patch
Index: src/core/org/apache/jmeter/control/gui/TransactionControllerGui.java
===================================================================
--- src/core/org/apache/jmeter/control/gui/TransactionControllerGui.java	(revision 575246)
+++ src/core/org/apache/jmeter/control/gui/TransactionControllerGui.java	(working copy)
@@ -32,6 +32,8 @@
 public class TransactionControllerGui extends AbstractControllerGui {
 
 	private JCheckBox parent; // If selected, then generate parent sample, otherwise as per original controller
+	
+	private JCheckBox includeTimers; // if selected, add duration of timers to total runtime
 
 	/**
 	 * Create a new TransactionControllerGui instance.
@@ -50,12 +52,15 @@
 	public void configure(TestElement el) {
 		super.configure(el);
 		parent.setSelected(((TransactionController) el).isParent());
+		includeTimers.setSelected(((TransactionController) el).isIncludeTimers());
 	}
 
 	/* Implements JMeterGUIComponent.modifyTestElement(TestElement) */
 	public void modifyTestElement(TestElement el) {
 		configureTestElement(el);
-		((TransactionController) el).setParent(parent.isSelected());
+		TransactionController tc = ((TransactionController) el);
+		tc.setParent(parent.isSelected());
+		tc.setIncludeTimers(includeTimers.isSelected());
 	}
 
 	public String getLabelResource() {
@@ -71,5 +76,7 @@
 		add(makeTitlePanel());
 		parent = new JCheckBox(JMeterUtils.getResString("transaction_controller_parent")); // $NON-NLS-1$
 		add(parent);
-	}
+		includeTimers = new JCheckBox(JMeterUtils.getResString("transaction_controller_include_timers"), true); // $NON-NLS-1$
+		add(includeTimers);
+	}	
 }
Index: src/core/org/apache/jmeter/control/TransactionController.java
===================================================================
--- src/core/org/apache/jmeter/control/TransactionController.java	(revision 575251)
+++ src/core/org/apache/jmeter/control/TransactionController.java	(working copy)
@@ -52,10 +52,14 @@
     
     transient private int calls;
 
-    transient private int noFailingSamples;
+	transient private int noFailingSamples;
+	
+	transient private long pauseTime, prevEndTime;
     
 	private static final String PARENT = "TransactionController.parent";// $NON-NLS-1$
-
+	
+	private final static String INCLUDE_TIMERS = "TransactionController.includeTimers";
+	
 	/**
 	 * Creates a Transaction Controller
 	 */
@@ -76,6 +80,14 @@
 		return getPropertyAsBoolean(PARENT);
 	}
 
+	public void setIncludeTimers(boolean b) {
+		setProperty(new BooleanProperty(INCLUDE_TIMERS, b));
+	}
+	
+	public boolean isIncludeTimers() {
+		return getPropertyAsBoolean(INCLUDE_TIMERS, false);
+	}
+	
 	public Sampler next(){
 		if (isParent()){
 			return next1();
@@ -149,6 +161,8 @@
             // Assume success
             res.setSuccessful(true);
 			res.sampleStart();
+			prevEndTime = res.getStartTime();
+			pauseTime = 0;
 		}
 
         Sampler returnValue = super.next();
@@ -156,6 +170,7 @@
 		if (returnValue == null) // Must be the end of the controller
 		{
 			if (res != null) {
+				res.incIdleTime(pauseTime);
 				res.sampleEnd();
                 res.setResponseMessage("Number of samples in transaction : " + calls + ", number of failing samples : " + noFailingSamples);
                 if(res.isSuccessful()) {
@@ -190,7 +205,11 @@
     	if (!isParent()) {
 	        // Check if we are still sampling our children
 	        if(res != null) {
-	            SampleResult sampleResult = se.getResult(); 
+	            SampleResult sampleResult = se.getResult();
+	            if (!isIncludeTimers()) {
+		           	pauseTime += sampleResult.getEndTime() - sampleResult.getTime() - prevEndTime;
+					prevEndTime = sampleResult.getEndTime();
+				}
 	            res.setThreadName(sampleResult.getThreadName());
 	            res.setBytes(res.getBytes() + sampleResult.getBytes());
 	            if(!sampleResult.isSuccessful()) {
Index: src/core/org/apache/jmeter/samplers/SampleResult.java
===================================================================
--- src/core/org/apache/jmeter/samplers/SampleResult.java	(revision 575246)
+++ src/core/org/apache/jmeter/samplers/SampleResult.java	(working copy)
@@ -742,6 +742,10 @@
 		setEndTime(end);
 	}
 
+	public void incIdleTime(long pause) {
+		idleTime += pause;
+	}
+	
 	/**
 	 * Record the start time of a sample
 	 * 
Index: src/core/org/apache/jmeter/resources/messages.properties
===================================================================
--- src/core/org/apache/jmeter/resources/messages.properties	(revision 575280)
+++ src/core/org/apache/jmeter/resources/messages.properties	(working copy)
@@ -702,6 +702,7 @@
 string_from_file_seq_start=Start file sequence number
 summariser_title=Generate Summary Results
 summary_report=Summary Report
+summary_report_include_transactions_only=Include Transactions Controllers only.
 switch_controller_label=Switch Value
 switch_controller_title=Switch Controller
 table_visualizer_bytes=Bytes
@@ -748,6 +749,7 @@
 timelim=Time limit
 transaction_controller_parent=Generate parent sample
 transaction_controller_title=Transaction Controller
+transaction_controller_include_timers=Include timer duration in runtime summary.
 unbind=Thread Unbind
 uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
 uniform_timer_memo=Adds a random delay with a uniform distribution
Index: src/core/org/apache/jmeter/resources/messages_de.properties
===================================================================
--- src/core/org/apache/jmeter/resources/messages_de.properties	(revision 575280)
+++ src/core/org/apache/jmeter/resources/messages_de.properties	(working copy)
@@ -151,6 +151,8 @@
 stopping_test_title=Stoppe den Test
 threadgroup=Thread Gruppe
 thread_group_title=Thread Gruppe
+transaction_controller_parent=Untergeordnete Samplers im Ergebnis ausblenden.
+transaction_controller_include_timers=Pausenzeiten zu Gesamtzeit addieren.
 upload=Datei hochladen
 upper_bound=obere Grenze
 url_config_title=HTTP Request Default Einstellungen

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Hello,
I find this enhancement very useful.
Attached is the updated patch of Alf Hogemark done against current trunk.

I just changed default value of "Include timer duration in runtime summary" to true to ensure ascending compatibility and commented some code.
I also tested it successfully.

Philippe
http://www.ubik-ingenierie.com

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Created attachment patch-41418.patch: Updated patch against trunk of 6/10/2009

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
I tested this feature in last load tests campaign.
Found no bugs and it is really very useful.
A good enhancement would be to remove TestAction times.

Philippe.

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
I've been looking at the patch dated 2009-10-06 11:17 UTC.
[Not all that easy to follow, as there are lots and lots of spurious white-space changes in the SampleResult part. Please try to submit minimum necessary changes in future.]

There is one part of the patch I don't understand:

TransactionController.java
...
@@ -152,6 +164,8 @@
// Assume success
res.setSuccessful(true);
res.sampleStart();

  •        prevEndTime = res.getStartTime();
    
  •        pauseTime = 0;
       }
    

It does not seem correct to use the StartTime as the initial value for the previous End Time. Is the patch correct - if so why? If not, what should it be?

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Hello,
First thanks for taking into account this patch and other ones I submitted.
I am sorry for the patch with lot of spaces, you are right, it s hard to read.

Now about your question, here is the concept of the patch as I understood it (originial writer is Alf Hogemark):

  • pauseTime cumulates time taken by all transaction timers and this is done by recording "previous end time" of a Sample.
    So prevEndTime is used only to compute timer(s) time between samples.

pauseTime for each sample is computed by doing (sample endTime - Time taken by sample) (which would be the sample start time) - previous sample EndTime in same transaction.

Do you see a pb in this ?
Thanks
Philippe.

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Cleaned up patch

Created attachment patch-41418.patch: Patch to trunk (22/11/2009 21h39)

patch-41418.patch
Index: src/core/org/apache/jmeter/samplers/SampleResult.java
===================================================================
--- src/core/org/apache/jmeter/samplers/SampleResult.java	(revision 883115)
+++ src/core/org/apache/jmeter/samplers/SampleResult.java	(working copy)
@@ -1089,4 +1089,11 @@
     public void removeSubResults() {
         this.subResults = null;
     }
+
+	/**
+	 * @param pause
+	 */
+	public void incIdleTime(long pause) {
+		idleTime += pause;
+	}
 }
Index: src/core/org/apache/jmeter/control/TransactionController.java
===================================================================
--- src/core/org/apache/jmeter/control/TransactionController.java	(revision 883115)
+++ src/core/org/apache/jmeter/control/TransactionController.java	(working copy)
@@ -56,7 +56,18 @@
 
     private transient int noFailingSamples;
 
+    /**
+     * Cumulated pause time to exclude timer and post/pre processor times
+     */
+    private transient long pauseTime;
+    
+    /**
+     * Previous end time
+     */
+    private transient long prevEndTime;
+     
     private static final String PARENT = "TransactionController.parent";// $NON-NLS-1$
+    private final static String INCLUDE_TIMERS = "TransactionController.includeTimers";// $NON-NLS-1$
 
     /**
      * Creates a Transaction Controller
@@ -152,6 +163,8 @@
             // Assume success
             res.setSuccessful(true);
             res.sampleStart();
+            prevEndTime = res.getStartTime();
+            pauseTime = 0;
         }
 
         Sampler returnValue = super.next();
@@ -159,7 +172,8 @@
         if (returnValue == null) // Must be the end of the controller
         {
             if (res != null) {
-                res.sampleEnd();
+            	res.incIdleTime(pauseTime);
+            	res.sampleEnd();
                 res.setResponseMessage("Number of samples in transaction : " + calls + ", number of failing samples : " + noFailingSamples);
                 if(res.isSuccessful()) {
                     res.setResponseCodeOK();
@@ -196,6 +210,10 @@
                 SampleResult sampleResult = se.getResult();
                 res.setThreadName(sampleResult.getThreadName());
                 res.setBytes(res.getBytes() + sampleResult.getBytes());
+                if (!isIncludeTimers()) {
+                	pauseTime += sampleResult.getEndTime() - sampleResult.getTime() - prevEndTime;
+                	prevEndTime = sampleResult.getEndTime();
+                }
                 if(!sampleResult.isSuccessful()) {
                     res.setSuccessful(false);
                     noFailingSamples++;
@@ -212,4 +230,20 @@
 
     public void sampleStopped(SampleEvent e) {
     }
+    
+    /**
+     * Include timer and pre/post processor time
+     * @param b
+     */
+    public void setIncludeTimers(boolean b) {
+    	setProperty(new BooleanProperty(INCLUDE_TIMERS, b));
+    }
+
+    /**
+     * Include timer and pre/post processor time
+     * @return boolean (defaults to true for Ascending compatibility)
+     */
+    public boolean isIncludeTimers() {
+    	return getPropertyAsBoolean(INCLUDE_TIMERS, true);
+    }
 }
Index: src/core/org/apache/jmeter/control/gui/TransactionControllerGui.java
===================================================================
--- src/core/org/apache/jmeter/control/gui/TransactionControllerGui.java	(revision 883115)
+++ src/core/org/apache/jmeter/control/gui/TransactionControllerGui.java	(working copy)
@@ -32,6 +32,8 @@
 public class TransactionControllerGui extends AbstractControllerGui {
 
     private JCheckBox parent; // If selected, then generate parent sample, otherwise as per original controller
+	
+    private JCheckBox includeTimers; // if selected, add duration of timers to total runtime
 
     /**
      * Create a new TransactionControllerGui instance.
@@ -51,12 +53,16 @@
     public void configure(TestElement el) {
         super.configure(el);
         parent.setSelected(((TransactionController) el).isParent());
+		includeTimers.setSelected(((TransactionController) el).isIncludeTimers());
     }
 
     /* Implements JMeterGUIComponent.modifyTestElement(TestElement) */
     public void modifyTestElement(TestElement el) {
         configureTestElement(el);
-        ((TransactionController) el).setParent(parent.isSelected());
+        TransactionController tc = ((TransactionController) el);
+        tc.setParent(parent.isSelected());
+        tc.setIncludeTimers(includeTimers.isSelected());
+
     }
 
     public String getLabelResource() {
@@ -72,5 +78,7 @@
         add(makeTitlePanel());
         parent = new JCheckBox(JMeterUtils.getResString("transaction_controller_parent")); // $NON-NLS-1$
         add(parent);
+        includeTimers = new JCheckBox(JMeterUtils.getResString("transaction_controller_include_timers"), true); // $NON-NLS-1$
+        add(includeTimers);
     }
 }

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
Thanks for the patch; it seems to work fine.

Patch committed to SVN:

URL: http://svn.apache.org/viewvc?rev=890526&view=rev
Log:
#1851 - Exclude timer duration from Transaction Controller runtime in report

@asfimport
Copy link
Collaborator Author

jens_0 (migrated from Bugzilla):
Excluding timer duration does not work if the transaction controller's option "Generate parent sample" is on.

See #2411

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