You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by Michael Stover <ms...@apache.org> on 2004/06/07 16:10:00 UTC

Re: [PATCH] IfController Should Evaluate Once Per Iteration

On Mon, 2004-06-07 at 10:46, Chris Povirk wrote:
> After having problems with the IfController in JMeter 2.0.0, I downloaded the latest CVS code, which improved the situation.  Now the IfController is no longer removed from the tree when it returns false; however, some problems remained.
> 
> The problems occur because JMeter usually tests the IfController condition multiple times per iteration.  This happens because the evaulation occurs (for most conditions) once per child controller of IfController, plus once when no children remain.  In some cases this isn't a problem; something along the lines of ${__threadNum}==2; isn't going to evaluate to true once and false another time for the same iteration of the same thread.  Unfortunately, this is not the case for, say, (0.5<=Math.random()); or ${__counter(TRUE,count)}==10;  Both can be avoided -- the first by using a Random Controller (assuming that there is no complex Javascript involved and all you want is a random probability, which is the case here), and the second by incrementing your counter elsewhere and changing the condition to ${count}==10; -- but it is, at the least, counterintuitive for a controller that is supposed to mimic...
> 
> if(condition)
> {
>   // do thing 1
>   // do thing 2
> }
> 
> ...to actually perform...
> 
> if(condition)
> {
>   // do thing 1
> }
> if(condition)
> {
>   // do thing 2
> }

I suspect that this second case is the desired behavior.  Many would
want to use the IfController to break out of the iteration on error. 
Your examples of how it might be undesireable are A) avoidable as you
say, and B) both have other controllers that more effectively achieve
those results (ie loop controller and throughput controller).  But, the
documentation should reflect the difference.

> 
> I address all this by evaluating the condition only when isFirst() is true.  The result is saved to a private boolean field and tested in later calls to next().  (I also cleared out some documentation that doesn't apply to revisions after 1.5.)

It could be a checkbox parameter that one can check to switch between
the two behavior types.

> 
> There is another subtle problem allowed by the current code when the condition evaluates to true for the first child and false for the second.  Here's the implementation:
>       if (result)
>         return super.next();
>       else
>         return null;
> The problem here is that "return null," unlike "return nextIsNull()," doesn't reset the IfController to its first child.  As a result, the first child may be run on one iteration, while the second is not, and (with the IfController picking up where it left off) the second child may be run on another iteration, while the first is not.  Since the IfController evaluates the condition only once per iteration now, this particular behavior can't occur; however, "return nextIsNull()" is again necessary, this time because it properly resets isFirst() so that the IfController knows it must reevaluate its condition when it is called again (i.e., during the next iteration).
> 
Good catch.

-Mike

> The diff is included below; I've also uploaded a test plan that demonstrates the sample problems above.  A summary of how it works, along with a link to it, is above the diff.
> 
> I think that's it.  Let me know if there are any problems.
> 
> --Chris Povirk
> 
> 
> Test Plan
>   Thread Group (1 thread, 100 repititions)
>     HTTP Request ("Count")
>     If Controller: (0.5<=Math.random());
>       HTTP Request ("50Percent")
>       HTTP Request ("After50")
>     IF Controller: ${__counter(TRUE,count)}==10;
>       HTTP Request: "Tenth Time Only Request 1"
>       HTTP Request: "Tenth Time Only Request 2"
> 
> On a typical run with the old IfController, the Aggregate Report shows:
> Count: 100
> 50Percent: 27
> After50: 27
> Tenth Time Only Request 1: 1
> Tenth Time Only Request 2: (not shown; 0)
> 50Percent and After50 are not always run during the same iteration
> 
> On a typical run with the new IfController, the Aggregate Report shows:
> Count: 100
> 50Percent: 49
> After50: 49
> Tenth Time Only Request 1: 1
> Tenth Time Only Request 2: 1
> 50Percent and After50 are always run during the same iteration
> 
> 
> LINKS
> Diff:
> http://www.pitt.edu/~crp11/jmeter/IfController.diff
> New Java Source:
> http://www.pitt.edu/~crp11/jmeter/IfController.java
> Test Plan to Demonstrate New Behavior:
> http://www.pitt.edu/~crp11/jmeter/SimpleRandomJavascript.jmx
> 
> 
> --- jakarta-jmeter/src/core/org/apache/jmeter/control/IfController.java.orig	2004-06-04 16:52:12.000000000 -0500
> +++ jakarta-jmeter/src/core/org/apache/jmeter/control/IfController.java	2004-06-07 09:24:26.086878920 -0500
> @@ -58,6 +58,9 @@
>  			LoggingManager.getLoggerForClass();
>  	  private final static String CONDITION = "IfController.condition";
>  
> +    // condition is now evaluated once per initialization and stored here
> +    private boolean result = false;
> +
>  	  /**
>  	   * constructor
>  	   */
> @@ -73,6 +76,20 @@
>  			this.setCondition(condition);
>  	  }
>  
> +    /**
> +     * Evaluate the condition clause, and save the result so that it is not
> +     * recalculated for other Samplers under this IfController.
> +     */
> +    private void evaluateAndSetResult() {
> +        result = false;
> +        try {
> +            result = evaluateCondition();
> +        }
> +        catch (Exception e) {
> +            logger.error(e.getMessage(),e);
> +        }
> +    }
> +
>  	  /**
>  	   * Condition Accessor - this is gonna be like     ${count}<10
>  	   */
> @@ -136,7 +153,8 @@
>  	  /**
>  	   * This is overriding the parent method.
>  	   * IsDone indicates whether the termination condition is reached.
> -	   * I.e. if the condition evaluates to False - then isDone() returns TRUE
> +	   * An IfController is never "done" because we do not know if it will
> +     * evaluate to true in the future.
>  	   */
>  	public boolean isDone() {
>  //		boolean result = true;
> @@ -156,26 +174,39 @@
>  	   * 'JMeterThread' iterates thru the Controller by calling this method.
>  	   * IF a valid 'Sampler' is returned, then it executes the sampler
>  	   * (calls sampler.sampler(xxx) method) .
> -	   * So here we make sure that the samplers belonging to this
> -	   * Controller do not get called
> -	   *    - if isDone is true
> -	   *    - if its the first time this is run. The first time is special
> -	   *       cause it is called prior the iteration even starts !
> +     * 
> +     * First be sure that we have evaluated and set the result value.
> +     * If the condition is false, we return no samplers, and nextIsNull() will
> +     * reInitialize() the IfController, ensuring that the condition will be
> +     * recalculated the next time this controller is reached.
> +     * Otherwise, we return the next sampler in under the Controller.
>  	   */
>  	  public Sampler next() {
> -			boolean result = false;
> +      if(isFirst()) {
> +        evaluateAndSetResult();
> +      }
> +
> +      Sampler next = null;
> +      if(result) {
> +        next = super.next();
> +      }
> +      else {
> +        try {
> +          next = nextIsNull();
> +        }
> +        catch(NextIsNullException e) {
> +          next = null;
> +        }
> +      }
> +      return next;
> +			/*boolean result = false;
>  			try {
>  				result = evaluateCondition();
>  			}
>  			catch (Exception e)
>  			{
>  				logger.error(e.getMessage(),e);
> -			}
> -			if (result)
> -				return super.next();
> -			else
> -				return null;
> -				
> +			}*/
>  	  }
>  
>  ////////////////////////////// Start of Test Code ///////////////////////////
> @@ -237,4 +268,4 @@
>  			}
>  	  }
>  
> -}
> \ No newline at end of file
> +}
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org
-- 
Michael Stover <ms...@apache.org>
Apache Software Foundation


---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org


Re: [PATCH] IfController Should Evaluate Once Per Iteration

Posted by Chris Povirk <ch...@paytec.com>.
On Wed, 09 Jun 2004 14:09:14 -0400
Michael Stover wrote:

> I think the IfController could be used to check a variable set by an
> assertion, and end the iteration depending on that value.  
> 
> -Mike

I'd been under the impression that the controls for a Thread Group let you end the iteration on error like this, but apparently I'm wrong, since it either stops the whole test for good, stops the whole thread for good, or does nothing.

However, assertions mark samplers as failures; they don't set any variables (so far as I can tell), so I don't think this sort of use is possible.  Perhaps I'm missing something else...?

(On a related note, it sounds as though the request for a "break keyword" at http://nagoya.apache.org/bugzilla/show_bug.cgi?id=12144 is related to the behavior you suggest.  Presumably it would be another option for Thread Groups and Result Status Actions alongside "Stop Test," "Stop Thread," and "Continue," but I'm not sure how it could be implemented easily.)

--Chris

---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org


Re: [PATCH] IfController Should Evaluate Once Per Iteration

Posted by Michael Stover <ms...@apache.org>.
I think the IfController could be used to check a variable set by an
assertion, and end the iteration depending on that value.  

-Mike

On Tue, 2004-06-08 at 14:39, Chris Povirk wrote:
> On Mon, 07 Jun 2004 10:10:00 -0400
> Michael Stover wrote:
> 
> > > 
> > > if(condition)
> > > {
> > >   // do thing 1
> > >   // do thing 2
> > > }
> > > 
> > > ...to actually perform...
> > > 
> > > if(condition)
> > > {
> > >   // do thing 1
> > > }
> > > if(condition)
> > > {
> > >   // do thing 2
> > > }
> > 
> > I suspect that this second case is the desired behavior.  Many would
> > want to use the IfController to break out of the iteration on error. 
> > Your examples of how it might be undesireable are A) avoidable as you
> > say, and B) both have other controllers that more effectively achieve
> > those results (ie loop controller and throughput controller).  But, the
> > documentation should reflect the difference.
> *snip*
> > It could be a checkbox parameter that one can check to switch between
> > the two behavior types.
> 
> A documentation change would probably be sufficient.  In any case, I don't think a checkbox to configure the behavior is worth it, but that may just be my personal preference.  As you say, there are ways to fake the single-evaluation method, and if I hadn't been experimenting with the broken 2.0.0 IfController, I probably would not have used it this specific way (with Math.random()).
> 
> A question, though: Could you clarify what you mean by using IfController with the current behavior "to break out of the iteration on error?"  Just a simple example or something -- I don't quite understand what you mean.
> 
> Regardless, it seems to me that the null --> nextIsNull() change would be a good thing....  If you do "break out" of the iteration due to an error, you'll presumably want to start over the next time through.  Then again, as I said, I'm not sure I understand this use of IfController.
> 
> Thanks.
> 
> --Chris
> 
> --- jakarta-jmeter-2.0.0-cvs/src/core/org/apache/jmeter/control/IfController.java.orig  2004-05-24 18:12:30.000000000 -0500
> +++ jakarta-jmeter-2.0.0-cvs/src/core/org/apache/jmeter/control/IfController.java       2004-06-08 13:21:14.834024536 -0500
> @@ -174,7 +174,7 @@
>                         if (result)
>                                 return super.next();
>                         else
> -                               return null;
> +                               return nextIsNull();
>                                 
>           }
>  
> @@ -237,4 +237,4 @@
>                         }
>           }
>  
> -}
> \ No newline at end of file
> +}
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org
-- 
Michael Stover <ms...@apache.org>
Apache Software Foundation


---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org


Re: [PATCH] IfController Should Evaluate Once Per Iteration

Posted by Chris Povirk <ch...@paytec.com>.
On Mon, 07 Jun 2004 10:10:00 -0400
Michael Stover wrote:

> > 
> > if(condition)
> > {
> >   // do thing 1
> >   // do thing 2
> > }
> > 
> > ...to actually perform...
> > 
> > if(condition)
> > {
> >   // do thing 1
> > }
> > if(condition)
> > {
> >   // do thing 2
> > }
> 
> I suspect that this second case is the desired behavior.  Many would
> want to use the IfController to break out of the iteration on error. 
> Your examples of how it might be undesireable are A) avoidable as you
> say, and B) both have other controllers that more effectively achieve
> those results (ie loop controller and throughput controller).  But, the
> documentation should reflect the difference.
*snip*
> It could be a checkbox parameter that one can check to switch between
> the two behavior types.

A documentation change would probably be sufficient.  In any case, I don't think a checkbox to configure the behavior is worth it, but that may just be my personal preference.  As you say, there are ways to fake the single-evaluation method, and if I hadn't been experimenting with the broken 2.0.0 IfController, I probably would not have used it this specific way (with Math.random()).

A question, though: Could you clarify what you mean by using IfController with the current behavior "to break out of the iteration on error?"  Just a simple example or something -- I don't quite understand what you mean.

Regardless, it seems to me that the null --> nextIsNull() change would be a good thing....  If you do "break out" of the iteration due to an error, you'll presumably want to start over the next time through.  Then again, as I said, I'm not sure I understand this use of IfController.

Thanks.

--Chris

--- jakarta-jmeter-2.0.0-cvs/src/core/org/apache/jmeter/control/IfController.java.orig  2004-05-24 18:12:30.000000000 -0500
+++ jakarta-jmeter-2.0.0-cvs/src/core/org/apache/jmeter/control/IfController.java       2004-06-08 13:21:14.834024536 -0500
@@ -174,7 +174,7 @@
                        if (result)
                                return super.next();
                        else
-                               return null;
+                               return nextIsNull();
                                
          }
 
@@ -237,4 +237,4 @@
                        }
          }
 
-}
\ No newline at end of file
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org