Created attachment 32588 [details] the gui design for my pacingtimer plugin. With parent mode on TransactionCotroller. The isTransactionSampleEvent() on SampleEvent object always returns "false" even with TransactionSampler. Please make it return "TRUE" with TransactionSampler not only “non parent mode” but also “parent mode” Reason) I am trying the develop the PacingTimer(similar functionality which is provided by commercial testing tools), and i want to define the target mode of “Iteration”, “Transaction” and “Sampler” to which applying the pacing time since many of people is familiar with Transaction pacing and Iteration pacing too. To implement this “Transaction mode” requirement, I need a way to say whether it is parent mode or not. I could modify the JmeterThread codes as below, however I never wants to touch the JMeter released build. Here what I tested for my requset, I had to change couple of code of JmeterThread.java <<<original>>>> (method : process_sampler) if(transactionSampler != null) { : notifyListeners(transactionPack.getSampleListeners(), transactionResult); : } (mdthod notifyListeners) SampleEvent event = new SampleEvent(result, threadGroup.getName(), threadVars); notifier.notifyListeners(event, listeners); private void notifyListeners(List<SampleListener> listeners, SampleResult result, boolean isTransactionSampleEvent) { SampleEvent event = new SampleEvent(result, threadGroup.getName(), threadVars,isTransactionSampleEvent); notifier.notifyListeners(event, listeners); } <<<<<changes .... >>>> (method : process_sampler) if(transactionSampler != null) { : notifyListeners(transactionPack.getSampleListeners(), transactionResult, true); //add parameter for transaction sampler : } (mdthod notifyListeners ) private void notifyListeners(List<SampleListener> listeners, SampleResult result) { notifyListeners(listeners,result,false); } private void notifyListeners(List<SampleListener> listeners, SampleResult result, boolean isTransactionSampleEvent) { SampleEvent event = new SampleEvent(result, threadGroup.getName(), threadVars,isTransactionSampleEvent); notifier.notifyListeners(event, listeners); } best regards myoung
Hello, Thanks for your report, but it is not clear for me. Could you provide a patch ? Also I am requalifying it as enhancement as it is related to a potential new feature. Maybe it would be better to rename it and provide the full patch for Pacing Timer. Thanks Regards
I have pasted the codes for my plugin(dynamic pacing time), at the moment this one works fine with 2.12 and 2.13 (excep the transaction parent mode). Am i attached the patch as you asked? If not please let me know best regards myoung <--- timer code.----------------> package myoung.jmeter.timer; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.jmeter.engine.event.LoopIterationEvent; import org.apache.jmeter.engine.event.LoopIterationListener; import org.apache.jmeter.testbeans.TestBean; import org.apache.jmeter.testelement.AbstractTestElement; import org.apache.jmeter.testelement.TestStateListener; import org.apache.jmeter.testelement.property.JMeterProperty; import org.apache.jmeter.timers.Timer; import org.apache.jorphan.logging.LoggingManager; import org.apache.log.Logger; import org.apache.soap.providers.com.Log; import org.apache.jmeter.threads.JMeterContextService; import org.apache.jmeter.threads.JMeterVariables; import org.apache.jmeter.control.TransactionSampler; import org.apache.jmeter.samplers.SampleEvent; import org.apache.jmeter.samplers.SampleResult; import org.apache.jmeter.samplers.Sampler; import org.apache.jmeter.samplers.SampleListener; public class DynamicPacingTimer extends AbstractTestElement implements Timer, TestBean, SampleListener, LoopIterationListener { // Timer excluded //public class DynamicPacingTimer extends AbstractTestElement implements TestBean, SampleListener, LoopIterationListener { private static final long serialVersionUID = 7750524238843015040L; private static final Logger log = LoggingManager.getLoggerForClass(); private long previousTime =0;//??double -> long private boolean isFirstIteration = true; private boolean isRandomMaxSet = false; // to calculate random timer private int randomMax; //will be used to calculate max private long pacingtimemin; // private java.util.Random randomgen = new java.util.Random(); private boolean delaySamploccured = false; // fields on the gui private long pacingtime; private double percentmin; private double percentmax; private PacingMode pacingmode; // = PacingMode.modeIteration; public enum PacingMode { modeSampler("Pacingmode.1"), modeTransaction("Pacingmode.2"), modeIteration("Pacingmode.3"), ; private final String propertyName; PacingMode(String propertyName) { this.propertyName = propertyName; } public String toString() { return propertyName; } } //end of PacingMode public void setPacingtime(long pacingtime) { this.pacingtime = pacingtime; } public long getPacingtime() { return pacingtime; } public void setPercentmin(double percentmin) { this.percentmin = percentmin; } public double getPercentmin() { return percentmin; } public void setPercentmax(double percentmax) { this.percentmax = percentmax; if (! isRandomMaxSet) { //this logic must be stay on the last this.pacingtimemin = this.pacingtime; double pacingtimemax = this.pacingtime; double tmpDouble; if (this.percentmin > 0 ) { tmpDouble = this.pacingtime * ((100.0 - this.percentmin) / 100.0); this.pacingtimemin = (long)tmpDouble; } if (this.percentmax > 0 ) { pacingtimemax = this.pacingtime * ((100.0 + this.percentmax) / 100.0); } this.randomMax = (int)( pacingtimemax - this.pacingtimemin); log.debug("(pacingtime)"+ this.pacingtime + " pacingmin:"+pacingtimemin + " randommax:" +this.randomMax ); isRandomMaxSet = true; } } public double getPercentmax() { return percentmax; } public int getPacingmode() { return pacingmode.ordinal(); } public void setPacingmode(int pacingmode) { this.pacingmode = PacingMode.values()[pacingmode]; } /* * public int getCalcMode() { return mode.ordinal(); } public void setCalcMode(int mode) { this.mode = Mode.values()[mode]; } * * */ public DynamicPacingTimer() { } public long delay() { switch (pacingmode) { case modeSampler: // calculateNdelay(JMeterContextService.getContext().getCurrentSampler().getName());//calculateNdelay( ); default: break; } return 0; } private void calculateNdelay() { calculateNdelay(""); } private void calculateNdelay(String label) { long delay = 0 ; long currentTime = System.currentTimeMillis(); //---- for debug // int minutes; // java.util.Calendar cal; // String currTimeString = ""; // String prevTimeString = ""; // cal = java.util.Calendar.getInstance(); // // cal.setTimeInMillis(currentTime); //minutes = cal.get(java.util.Calendar.MINUTE); // currTimeString = new java.text.SimpleDateFormat("mm:ss.SSS").format(cal.getTime()); // cal.setTimeInMillis(previousTime); //minutes = cal.get(java.util.Calendar.MINUTE); // prevTimeString = new java.text.SimpleDateFormat("mm:ss.SSS").format(cal.getTime()); //--- for debug (end) long tmppacingtime = pacingtimemin; if (randomMax > 0 ) {tmppacingtime = randomgen.nextInt(randomMax) + pacingtimemin;} long currentTarget = previousTime + tmppacingtime; if (currentTarget < currentTime ) { previousTime = currentTime; //no delay : // We're behind schedule delay = 0; } else {// response time is in the target time previousTime = currentTarget; // calculate delay delay = currentTarget - currentTime; } //log.debug(" (__calculeateNdelay)prev:" + prevTimeString + " now:" + currTimeString + " delay:" + delay + " pacing:" + tmppacingtime + " :::" +currSampler.getName()); log.debug(" (__calculeateNdelay):" + previousTime + " now:" + currentTime + " delay:" + delay + " pacing:" + tmppacingtime + " :::" + label); try { Thread.sleep(delay); } catch (InterruptedException e) { } //return delay; /* log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + " curr:" + currSampler.getClass() +"_"+ currSampler.getName() ); //log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + " prev:" + currSampler.getClass() +"_"+ currSampler.getName() ); System.out.println(" " + Thread.currentThread().getStackTrace()[1].getMethodName() + " curr:" + currSampler.getClass() +"_"+ currSampler.getName()); if ((currSampler instanceof TransactionSampler)) { } else { //System.out.println (" Not Transaction Sampler :" + prevSampler.getClass() +"_"+ currSampler.getClass()) ; } long currentTime = System.currentTimeMillis(); long currentTarget = previousTime; if (currentTime > currentTarget) { // We're behind schedule -- try to catch up: previousTime = currentTime; // assume the sample will run immediately return 0; } previousTime = currentTarget; // assume the sample will run as soon as the delay has expired //System.out.println(previousTime+ " " + currentTime + " " + (currentTarget - currentTime)); return (long)(currentTarget - currentTime); */ } private void reset() { previousTime = 0; } public String toString() { return ""; } @Override public void setProperty(JMeterProperty property) { super.setProperty(property); } //---- LoopIterationListener : when iterartion(per thread group started) public void iterationStart(LoopIterationEvent iterEvent) { if (isFirstIteration){ previousTime = System.currentTimeMillis(); isFirstIteration = false; } log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + "------------> ITERATION" //+" lastSample:"+ JMeterContextService.getContext().getVariables().get("JMeterThread.last_sample_ok") + "_"+ iterEvent.getSource().getName() + " count:" + iterEvent.getIteration()); switch (pacingmode) { case modeIteration: // Total number of threads calculateNdelay(iterEvent.getSource().getName() );//calculateNdelay( ); break; default: break; } } @Override // !! Transaction Parent mode: it is not invoked with samplers with non-partnet mode of transaction public void sampleOccurred(SampleEvent se) { //log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() // + "*isTranSampleEvent:" + se.isTransactionSampleEvent()//+ "_sampleDepth:" + travleSampleEvent(se) // ); switch (pacingmode) { case modeTransaction: // It does not work with Transaction Parent mode if (se.isTransactionSampleEvent() ) { calculateNdelay(se.getResult().getSampleLabel()); //calculateNdelay( ); } case modeIteration: break; default: break; } } @Override public void sampleStarted(SampleEvent e) { log.debug(Thread.currentThread().getStackTrace()[1].getMethodName()); } @Override public void sampleStopped(SampleEvent e) { if (e.isTransactionSampleEvent() ) { log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + " TRANSACTION SAMPLE" ); } else { log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + " SAMPLE" ); } } }