Sure. But OGNL will return similar results with 50 tests. Yet people have
run into performance problems. The issue is that you're not looking at
performance in terms of resource contention, and in terms of aggregate
resource usage.
Say you have a page which contains 20 expressions. And your pages are
getting hit 15 times a second (a reality in some high traffic sites).
That's 300 expressions running every second. Now, in insolation that's
probably chump change. But as resource contention rises in these situation,
the overall efficiency drops and resource usage is exaggerated as a result.
You might in term start to find that what is only 0ms in an isolate
closed-loop test (which is not a very good way to benchmark in Java, by the
way) could very well be something that contributes to a significant amount
of CPU time in systems with high load.
Take these real benchmarks (from MVEL 1.2--which is old):
Test Name : Deep Property
Expression : foo.bar.name
Iterations : 50000
Interpreted Results :
(OGNL) : 1955.20ms avg. (mem delta: -790kb)
[1936,1949,1943,1994,1954]
(MVEL) : 114.80ms avg. (mem delta: -112kb)
[119,113,110,117,115]
Compiled Results :
(OGNL Compiled) : 92.80ms avg. (mem delta: -580kb) [92,92,92,92,96]
(MVEL Compiled) : 1.80ms avg. (mem delta: -18kb) [1,2,2,2,2]
... 50,000 iterations on MVEL interpreted in 114.80ms. This is a 1000x more
iterations than your benchmark. If I divide 114.8ms / 1000 ... I get 0.1ms
(or what would otherwise be rounded down to 0ms). In OGNL's case, it did 50
iterations in 1.95ms (or what would be measured as 1ms -- as these time
measurements always round down because of the fact currentTimeMillis()
returns the result in MS).
But you can plainly see that as we scale up, those small minor millisecond
differences amplify.
Now look at the COMPILED results of MVEL and OGNL. OGNL would have done 50
iterations in 0.098ms. MVEL would have done 50 iterations in: 0.0018ms.
Because MVEL's compiled efficiency, it did 50,000 iterations in less than
2ms.
You can talk about "good enough" all you want, but faster is always better
when it comes to scale. :)
Brian Pontarelli wrote:
>
> Just as a quick update. I realized my tests weren't insulated from
> other code running and create a separate unit test to get performance.
> The results are now:
>
> Retrieving from a JavaBean property (user.age) 0ms
> Retrieving from a field (user.age) 0ms
> Retrieving from a JavaBean property (user.address['home'].zipcode) 0ms
> Retrieving from a field (user.address['home'].zipcode) 0ms
>
> Setting a JavaBean property (user.age) 0ms
> Setting a field (user.age) 0ms
> Setting a JavaBean property (user.address['home'].zipcode) 0ms
> Setting a field (user.address['home'].zipcode) 0ms
>
> I also ran a test setting the address zipcode field 50 times, which is
> about the highest number of HTTP parameters I could envision and that
> was 2ms.
>
> Here's the code:
>
> public void testPerformance() {
> // Set cases
>
> Object action = new ActionField();
> long start = System.currentTimeMillis();
> evaluator.setValue("user.age", action, array("32"), null);
> long end = System.currentTimeMillis();
> System.out.println("Setting field time was " + (end - start));
>
> start = System.currentTimeMillis();
> evaluator.setValue("user.addresses['home'].zipcode", action,
> array("80020"), null);
> end = System.currentTimeMillis();
> System.out.println("Setting field time was " + (end - start));
>
> action = new Action();
> start = System.currentTimeMillis();
> evaluator.setValue("user.age", action, array("32"), null);
> end = System.currentTimeMillis();
> System.out.println("Setting property time was " + (end -
> start));
>
> start = System.currentTimeMillis();
> evaluator.setValue("user.addresses['home'].zipcode", action,
> array("80020"), null);
> end = System.currentTimeMillis();
> System.out.println("Setting proeprty time was " + (end -
> start));
>
> // Get cases
>
> action = new ActionField();
> start = System.currentTimeMillis();
> evaluator.getValue("user.age", action);
> end = System.currentTimeMillis();
> System.out.println("Getting field time was " + (end - start));
>
> start = System.currentTimeMillis();
> evaluator.getValue("user.addresses['home'].zipcode", action);
> end = System.currentTimeMillis();
> System.out.println("Getting field time was " + (end - start));
>
> action = new Action();
> start = System.currentTimeMillis();
> evaluator.getValue("user.age", action);
> end = System.currentTimeMillis();
> System.out.println("Getting property time was " + (end -
> start));
>
> start = System.currentTimeMillis();
> evaluator.getValue("user.addresses['home'].zipcode", action);
> end = System.currentTimeMillis();
> System.out.println("Getting property time was " + (end -
> start));
>
> // Loop
>
> start = System.currentTimeMillis();
> for (int i = 0; i < 50; i++) {
> evaluator.getValue("user.addresses['home'].zipcode",
> action);
> }
> end = System.currentTimeMillis();
> System.out.println("50 times was " + (end - start));
> }
>
> And the output:
>
> [junit] Setting field time was 0
> [junit] Setting field time was 0
> [junit] Setting property time was 0
> [junit] Setting proeprty time was 0
> [junit] Getting field time was 0
> [junit] Getting field time was 0
> [junit] Getting property time was 0
> [junit] Getting property time was 0
> [junit] 50 times was 2
>
> That's definitely fast enough for any web application.
>
> -bp
>
> On Oct 12, 2008, at 11:46 AM, Chris Brock wrote:
>
>>
>> Well, I'd like to see an actual comparison. I somehow doubt your
>> parser,
>> which I note is using StringTokenizer will perform as well as MVEL's
>> parser,
>> which is a much more computationally efficient sliding-window parser.
>>
>>
>> Brian Pontarelli wrote:
>>>
>>> Right, but you can receive similar or better performance using a
>>> linear runtime evaluation if the language is simple enough and tuned
>>> for the web. And as you and I say, MVEL and most other languages
>>> aren't targeted to the web and have many extra features.
>>>
>>> I can't really believe that JUEL is that slow though. And if it
>>> really
>>> is, it should be extremely simple to make it just as fast as MVEL.
>>> But
>>> I couldn't say for certain because I don't know the code.
>>>
>>> I ran some simple tests on getting and setting properties for the
>>> JCatapult expression evaluator and here's what I got:
>>>
>>> Retrieving from a JavaBean property ("user.age") 1ms
>>> Retrieving from a public member field ("user.age") < 1ms
>>> Retrieving from a nested JavaBean property within a collection
>>> ("user.addresses['home'].zipcode") 1ms
>>> Retrieving from a nested public member field within a collection
>>> ("user.addresses['home'].zipcode") 1ms
>>>
>>> Setting a JavaBean property with type conversion ("user.age") 1ms
>>> Setting a nested JavaBean property, with collections and Object
>>> creation ("user.addresses['home'].zipcode") 2ms
>>>
>>> That's definitely fast enough for my web applications. ;)
>>>
>>> JCatapult does support using public member fields of classes and it
>>> does shave a little bit of time, but nothing that would make a huge
>>> difference. These are all runtime parsing and handling, nothing is
>>> compiled or cached.
>>>
>>> -bp
>>>
>>> On Oct 11, 2008, at 3:09 PM, Chris Brock wrote:
>>>
>>>>
>>>> The singleton pattern is used in MVEL, with knowledge of the
>>>> tradeoff. MVEL
>>>> has a strong emphasis on maintaining interpreted-mode performance.
>>>>
>>>> MVEL contains two runtime systems: an interpreter, and a compiler/
>>>> runtime.
>>>> Unlike other ELs, MVEL does not simply bootstrap the compiler, and
>>>> execute
>>>> that way. Instead, MVEL has a real-time interpreter which evaluates
>>>> to a
>>>> stack during parsing. Therefore, the general design decisions,
>>>> particularly
>>>> around extendability tend to favor singleton-patterns, instead of
>>>> heavyweight configuration sessions which would completely bog down
>>>> the
>>>> performance.
>>>>
>>>> http://artexpressive.blogspot.com/2007/11/juel-vs-mvel.html
>>>>
>>>> For an example of how performant MVEL's interpreter is with no
>>>> factory
>>>> caching.
>>>>
>>>> In a simple property expression, with no caching (so parsing before
>>>> executing every time), MVEL was able to parse/reduce the expression
>>>> "foo.bar" 100,000 times in 94ms. It took JUEL 2749ms to do the
>>>> same.
>>>>
>>>> Compiled performance was: 5.8ms to 34.2ms in favor of MVEL too.
>>>>
>>>> So I would err on the side of performance here. If that doesn't cut
>>>> it for
>>>> web applications, I guess that's fine. I don't really target MVEL
>>>> towards
>>>> web applications, really.
>>>>
>>>>
>>>>
>>>> Brian Pontarelli wrote:
>>>>>
>>>>> Taking a brief look at the MVEL type conversion API it could be
>>>>> somewhat difficult to get this information into the converter on a
>>>>> per
>>>>> request basis, especially if converters are singleton scoped. This
>>>>> information isn't available on the source in most cases. It is
>>>>> usually
>>>>> externalized in the request or the container object. The API
>>>>> looks a
>>>>> pretty lightweight, which is nice, but also restrictive. From
>>>>> what I
>>>>> could see I would have to monkey around with things and use
>>>>> something
>>>>> like a ThreadLocal to pass this information to the converter.
>>>>>
>>>>> The source-from-many pattern seems to be somewhat backwards for the
>>>>> web. It is more likely the case that a single converter will
>>>>> convert
>>>>> to many classes from a String or String[]. The JCatapult type
>>>>> converter passes in the type being converted to and then the String
>>>>> value(s). Although this is very web centric, it cleans up the API
>>>>> and
>>>>> makes things simpler to implement. MVEL is obviously more generic,
>>>>> which means some massaging is necessary to tune it for the web.
>>>>>
>>>>> It also seems to be lacking a good set of exceptions thrown out of
>>>>> the
>>>>> API. At least from the docs, since I couldn't find JavaDoc and the
>>>>> distribution only has source (ouch). This doesn't mean that Struts
>>>>> can't provide good runtime exceptions and then just catch those,
>>>>> but
>>>>> it leaves things much more open for developers writing new
>>>>> converters.
>>>>> I'd rather see the API define these exceptions clearly and for them
>>>>> to
>>>>> be checked.
>>>>>
>>>>> I think that using generic languages like OGNL or MVEL are decent
>>>>> solutions, but a web centric solution would be best. I'm also in
>>>>> favor
>>>>> or dropping most if not all of the extra features and only
>>>>> providing
>>>>> property/field getting and setting. I think adding in another
>>>>> language
>>>>> just clouds the waters. FreeMarker and JSP both have languages that
>>>>> cover most of the common cases.
>>>>>
>>>>> Feel free to take a look at the JCatapult MVC expression evaluator
>>>>> for
>>>>> what I feel should be supported.
>>>>>
>>>>> -bp
>>>>>
>>>>>
>>>>> On Oct 11, 2008, at 12:52 PM, Chris Brock wrote:
>>>>>
>>>>>>
>>>>>> MVEL has a pluggable type-conversion API, just like OGNL. Since
>>>>>> it's
>>>>>> source-from-many in it's design, you can easily design converters
>>>>>> that
>>>>>> perform as much introspection as necessary to determine
>>>>>> formatting,
>>>>>> etc.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Brian Pontarelli wrote:
>>>>>>>
>>>>>>> Yeah. That's good. The last thing I would toss in as criteria
>>>>>>> is a
>>>>>>> good type conversion interface. In JCatapult, I actually took
>>>>>>> things a
>>>>>>> step further. I found that complex types usually needed more
>>>>>>> information than just the data to perform the type conversion.
>>>>>>> For
>>>>>>> example, conversion of dates generally requires the date format.
>>>>>>> Likewise, conversion to money generally requires the currency
>>>>>>> code.
>>>>>>> In
>>>>>>> many MVCs this information is statically configured for the
>>>>>>> entire
>>>>>>> application, configured per action in XML or properties files or
>>>>>>> fixed
>>>>>>> and not configurable at all.
>>>>>>>
>>>>>>> For maximum flexibility, I built a system where tags could
>>>>>>> provide
>>>>>>> this additional data via extra attributes (it can also be
>>>>>>> configured
>>>>>>> application wide as well). My tags look like this:
>>>>>>>
>>>>>>> [EMAIL PROTECTED] name="user.lifeSavings" currencyCode="USD"/]
>>>>>>> [EMAIL PROTECTED] name="user.birthDay" dateTimeFormat="MM/dd/yyyy"/]
>>>>>>>
>>>>>>> This information then gets passed to the type converters as
>>>>>>> part of
>>>>>>> the API.
>>>>>>>
>>>>>>> This then reveals another shortcoming of OGNL and the wrapper in
>>>>>>> Struts, what if a required attribute is missing? This is a
>>>>>>> different
>>>>>>> case then if the type conversion fails. So, I created two
>>>>>>> distinct
>>>>>>> checked exceptions to handle these two cases. This makes the type
>>>>>>> conversion system more powerful and easy to interact with.
>>>>>>> Plus, it
>>>>>>> reveals good exceptions for coding problems.
>>>>>>>
>>>>>>> -bp
>>>>>>>
>>>>>>> On Oct 10, 2008, at 3:00 AM, Chris Brock wrote:
>>>>>>>
>>>>>>>>
>>>>>>>> MVEL will handle type coercion for method parameters,
>>>>>>>> properties,
>>>>>>>> and even on
>>>>>>>> egress of those values if the generic type information can be
>>>>>>>> deduced on
>>>>>>>> ingress. In situtations where the generic type is dependent on
>>>>>>>> the
>>>>>>>> root of
>>>>>>>> the object graph though, MVEL cannot infer generic type data
>>>>>>>> (ie. a
>>>>>>>> bound
>>>>>>>> variable, that's say a Map) because of erasure. There is no
>>>>>>>> generic
>>>>>>>> type
>>>>>>>> information held on a per-instance basis.
>>>>>>>>
>>>>>>>> However, if the parameterized type is a class member say:
>>>>>>>>
>>>>>>>> class Foo {
>>>>>>>> public Map<String, Integer> map;
>>>>>>>> }
>>>>>>>>
>>>>>>>> And you use an instance of Foo as a context or as a bound
>>>>>>>> variable,
>>>>>>>> MVEL's
>>>>>>>> compiler can certainly extract the generic type information, and
>>>>>>>> provide
>>>>>>>> automatic coercion and verification accordingly. MVEL's type
>>>>>>>> verifier will
>>>>>>>> always extrapolate whatever type data is available.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Brian Pontarelli wrote:
>>>>>>>>>
>>>>>>>>> This is not quite the same unless it can detect generics while
>>>>>>>>> setting
>>>>>>>>> values and creating values. An example might be values from a
>>>>>>>>> form
>>>>>>>>> going into something like:
>>>>>>>>>
>>>>>>>>> List<String>
>>>>>>>>>
>>>>>>>>> or
>>>>>>>>>
>>>>>>>>> Map<String, List<Integer>>
>>>>>>>>>
>>>>>>>>> or the always fun
>>>>>>>>>
>>>>>>>>> List<List<Integer>>
>>>>>>>>>
>>>>>>>>> that sorta thing. I know that OGNL had (might not any longer)
>>>>>>>>> many
>>>>>>>>> issues with generics in this respect. I think OGNL also got mad
>>>>>>>>> when
>>>>>>>>> it encountered something simple like:
>>>>>>>>>
>>>>>>>>> int[]
>>>>>>>>>
>>>>>>>>> or
>>>>>>>>>
>>>>>>>>> String[]
>>>>>>>>>
>>>>>>>>> coming from checkbox lists and multiple selects. I believe that
>>>>>>>>> it
>>>>>>>>> would stuff the values into the String[] like this:
>>>>>>>>>
>>>>>>>>> {"value1,value2,value3"}
>>>>>>>>>
>>>>>>>>> rather than
>>>>>>>>>
>>>>>>>>> {"value1", "value2", "value3"}
>>>>>>>>>
>>>>>>>>> This was a while ago, so all of this might be fixed.
>>>>>>>>>
>>>>>>>>> -bp
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Oct 9, 2008, at 7:32 PM, Chris Brock wrote:
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> MVEL 2.0 has full support for generics (and static typing):
>>>>>>>>>> http://mvel.codehaus.org/Strong+Typing+Mode
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Brian Pontarelli wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Oct 7, 2008, at 3:08 PM, Dave Newton wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Just to muddy the EL/templating waters:
>>>>>>>>>>>>
>>>>>>>>>>>> http://mvel.codehaus.org/Performance+of+MVEL
>>>>>>>>>>>>
>>>>>>>>>>>> (v. OGNL)
>>>>>>>>>>>
>>>>>>>>>>> Not sure about MVEL or OGNL at this point, but everything was
>>>>>>>>>>> lacking
>>>>>>>>>>> in support for generics, collections and arrays. I wrote my
>>>>>>>>>>> own
>>>>>>>>>>> for
>>>>>>>>>>> the JCatapult MVC and it was really not all that hard. It
>>>>>>>>>>> only
>>>>>>>>>>> handles
>>>>>>>>>>> getting and setting, but I figure that's all that should be
>>>>>>>>>>> allowed
>>>>>>>>>>> at
>>>>>>>>>>> that point anyways.
>>>>>>>>>>>
>>>>>>>>>>> -bp
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> ---------------------------------------------------------------------
>>>>>>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> View this message in context:
>>>>>>>>>> http://www.nabble.com/MVEL--tp19867360p19910418.html
>>>>>>>>>> Sent from the Struts - Dev mailing list archive at Nabble.com.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> ---------------------------------------------------------------------
>>>>>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> ---------------------------------------------------------------------
>>>>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> --
>>>>>>>> View this message in context:
>>>>>>>> http://www.nabble.com/MVEL--tp19867360p19914597.html
>>>>>>>> Sent from the Struts - Dev mailing list archive at Nabble.com.
>>>>>>>>
>>>>>>>>
>>>>>>>> ---------------------------------------------------------------------
>>>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> --
>>>>>> View this message in context:
>>>>>> http://www.nabble.com/MVEL--tp19867360p19935345.html
>>>>>> Sent from the Struts - Dev mailing list archive at Nabble.com.
>>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>
>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>
>>>>>
>>>>>
>>>> --
>>>> View this message in context:
>>>> http://www.nabble.com/MVEL--tp19867360p19936453.html
>>>> Sent from the Struts - Dev mailing list archive at Nabble.com.
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>
>>>
>>>
>> --
>> View this message in context:
>> http://www.nabble.com/MVEL--tp19867360p19943987.html
>> Sent from the Struts - Dev mailing list archive at Nabble.com.
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>> For additional commands, e-mail: [EMAIL PROTECTED]
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
>
--
View this message in context:
http://www.nabble.com/MVEL--tp19867360p19947427.html
Sent from the Struts - Dev mailing list archive at Nabble.com.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]