001    /*
002     * $Id: Performance.java 1188815 2011-10-25 17:31:01Z mcucchiara $
003     * Licensed to the Apache Software Foundation (ASF) under one
004     * or more contributor license agreements.  See the NOTICE file
005     * distributed with this work for additional information
006     * regarding copyright ownership.  The ASF licenses this file
007     * to you under the Apache License, Version 2.0 (the
008     * "License"); you may not use this file except in compliance
009     * with the License.  You may obtain a copy of the License at
010     *
011     * http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing,
014     * software distributed under the License is distributed on an
015     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016     * KIND, either express or implied.  See the License for the
017     * specific language governing permissions and limitations
018     * under the License.
019     */
020    package org.apache.commons.ognl.test;
021    
022    import org.apache.commons.ognl.Ognl;
023    import org.apache.commons.ognl.OgnlContext;
024    import org.apache.commons.ognl.OgnlException;
025    import org.apache.commons.ognl.SimpleNode;
026    import org.apache.commons.ognl.test.objects.Bean1;
027    
028    import java.lang.reflect.Method;
029    import java.text.DecimalFormat;
030    import java.text.NumberFormat;
031    
032    public class Performance
033    {
034    
035        private static int MAX_ITERATIONS = -1;
036    
037        private static boolean ITERATIONS_MODE;
038    
039        private static long MAX_TIME = -1L;
040    
041        private static boolean TIME_MODE;
042    
043        private static NumberFormat FACTOR_FORMAT = new DecimalFormat( "0.000" );
044    
045        private String _name;
046    
047        private OgnlContext _context = (OgnlContext) Ognl.createDefaultContext( null );
048    
049        private Bean1 _root = new Bean1();
050    
051        private SimpleNode _expression;
052    
053        private SimpleNode _compiledExpression;
054    
055        private Method _method;
056    
057        private int _iterations;
058    
059        private String _expressionString;
060    
061        private boolean _isMvel = false;
062    
063        private long t0;
064    
065        private long t1;
066    
067        /*
068         * =================================================================== Private static classes
069         * ===================================================================
070         */
071        private static class Results
072        {
073    
074            int iterations;
075    
076            long time;
077    
078            boolean mvel;
079    
080            public Results( int iterations, long time, boolean mvel )
081            {
082                super();
083                this.iterations = iterations;
084                this.time = time;
085                this.mvel = mvel;
086            }
087    
088            public String getFactor( Results otherResults )
089            {
090                String ret;
091    
092                if ( TIME_MODE )
093                {
094                    float factor;
095    
096                    if ( iterations < otherResults.iterations )
097                    {
098                        factor =
099                            Math.max( (float) otherResults.iterations, (float) iterations )
100                                / Math.min( (float) otherResults.iterations, (float) iterations );
101                    }
102                    else
103                    {
104                        factor =
105                            Math.min( (float) otherResults.iterations, (float) iterations )
106                                / Math.max( (float) otherResults.iterations, (float) iterations );
107                    }
108    
109                    ret = FACTOR_FORMAT.format( factor );
110                    if ( iterations > otherResults.iterations )
111                        ret += " times faster than ";
112                    else
113                        ret += " times slower than ";
114    
115                }
116                else
117                {
118                    float factor =
119                        Math.max( (float) otherResults.time, (float) time )
120                            / Math.min( (float) otherResults.time, (float) time );
121    
122                    ret = FACTOR_FORMAT.format( factor );
123                    if ( time < otherResults.time )
124                        ret += " times faster than ";
125                    else
126                        ret += " times slower than ";
127                }
128    
129                return ret;
130            }
131        }
132    
133        /*
134         * =================================================================== Public static methods
135         * ===================================================================
136         */
137        public static void main( String[] args )
138        {
139            for ( int i = 0; i < args.length; i++ )
140            {
141                if ( args[i].equals( "-time" ) )
142                {
143                    TIME_MODE = true;
144                    MAX_TIME = Long.parseLong( args[++i] );
145                }
146                else if ( args[i].equals( "-iterations" ) )
147                {
148                    ITERATIONS_MODE = true;
149                    MAX_ITERATIONS = Integer.parseInt( args[++i] );
150                }
151            }
152            if ( !TIME_MODE && !ITERATIONS_MODE )
153            {
154                TIME_MODE = true;
155                MAX_TIME = 1500;
156            }
157    
158            try
159            {
160                Performance[] tests =
161                    new Performance[] {
162                        new Performance( "Constant", "100 + 20 * 5", "testConstantExpression" ),
163                        // new Performance("Constant", "100 + 20 * 5", "testConstantExpression", false),
164                        new Performance( "Single Property", "bean2", "testSinglePropertyExpression" ),
165                        new Performance( "Property Navigation", "bean2.bean3.value", "testPropertyNavigationExpression" ),
166                        /*
167                         * new Performance("Property Setting with context key", "bean2.bean3.nullValue",
168                         * "testPropertyNavigationSetting"), new Performance("Property Setting with context key",
169                         * "bean2.bean3.nullValue", "testPropertyNavigationSetting", true),
170                         */
171                        new Performance( "Property Navigation and Comparison", "bean2.bean3.value <= 24",
172                                         "testPropertyNavigationAndComparisonExpression" ),
173                        /*
174                         * new Performance("Property Navigation with Indexed Access", "bean2.bean3.indexedValue[25]",
175                         * "testIndexedPropertyNavigationExpression"), new
176                         * Performance("Property Navigation with Indexed Access", "bean2.bean3.indexedValue[25]",
177                         * "testIndexedPropertyNavigationExpression", true),
178                         */
179                        new Performance( "Property Navigation with Map Access", "bean2.bean3.map['foo']",
180                                         "testPropertyNavigationWithMapExpression" ),
181                    /*
182                     * new Performance("Property Navigation with Map value set", "bean2.bean3.map['foo']",
183                     * "testPropertyNavigationWithMapSetting"), new Performance("Property Navigation with Map value set",
184                     * "bean2.bean3.map['foo']", "testPropertyNavigationWithMapSetting", true)
185                     */
186                    };
187    
188                boolean timeMode = TIME_MODE;
189                boolean iterMode = ITERATIONS_MODE;
190                long maxTime = MAX_TIME;
191                int maxIterations = MAX_ITERATIONS;
192    
193                // TIME_MODE = false;
194                // ITERATIONS_MODE = true;
195                // maxIterations = 1000;
196    
197                runTests( tests, false );
198    
199                TIME_MODE = timeMode;
200                ITERATIONS_MODE = iterMode;
201                MAX_TIME = maxTime;
202                MAX_ITERATIONS = maxIterations;
203    
204                System.out.println( "\n\n============================================================================\n" );
205    
206                Thread.sleep( 2500 );
207                runTests( tests, true );
208    
209                // Thread.sleep(2000);
210    
211                System.out.println( "\n\n============================================================================\n" );
212                // runTests(tests);
213    
214            }
215            catch ( Exception ex )
216            {
217                ex.printStackTrace();
218            }
219        }
220    
221        static void runTests( Performance[] tests, boolean output )
222            throws Exception
223        {
224            for ( Performance perf : tests )
225            {
226                try
227                {
228    
229                    Results javaResults = perf.testJava( ), interpretedResults = perf.testExpression( false ),
230                        compiledResults = perf.testExpression( true );
231    
232                    if ( !output )
233                    {
234                        return;
235                    }
236    
237                    System.out.println( ( compiledResults.mvel ? "MVEL" : "OGNL" ) + " " + perf.getName( ) + ": "
238                                            + perf.getExpression( ) );
239                    System.out.println(
240                        "       java: " + javaResults.iterations + " iterations in " + javaResults.time + " ms" );
241    
242                    System.out.println(
243                        "   compiled: " + compiledResults.iterations + " iterations in " + compiledResults.time + " ms ("
244                            + compiledResults.getFactor( javaResults ) + "java)" );
245    
246                    System.out.println(
247                        "interpreted: " + interpretedResults.iterations + " iterations in " + interpretedResults.time
248                            + " ms (" + interpretedResults.getFactor( javaResults ) + "java)" );
249    
250                    System.out.println( );
251    
252                }
253                catch ( OgnlException ex )
254                {
255                    ex.printStackTrace( );
256                }
257            }
258        }
259    
260        /*
261         * =================================================================== Constructors
262         * ===================================================================
263         */
264        public Performance( String name, String expressionString, String javaMethodName )
265            throws Exception
266        {
267            this( name, expressionString, javaMethodName, false );
268        }
269    
270        public Performance( String name, String expressionString, String javaMethodName, boolean mvel )
271            throws Exception
272        {
273            _name = name;
274            _isMvel = mvel;
275            _expressionString = expressionString;
276    
277            try
278            {
279                _method = getClass().getMethod( javaMethodName, new Class[] {} );
280            }
281            catch ( Exception ex )
282            {
283                throw new OgnlException( "java method not found", ex );
284            }
285    
286            if ( !_isMvel )
287            {
288                _expression = (SimpleNode) Ognl.parseExpression( expressionString );
289                _compiledExpression = (SimpleNode) Ognl.compileExpression( _context, _root, expressionString );
290                Ognl.getValue( _expression, _context, _root );
291                _context.put( "contextValue", "cvalue" );
292            }
293            else
294            {
295                // _mvelCompiled = MVEL.compileExpression(expressionString);
296            }
297        }
298    
299        /*
300         * =================================================================== Protected methods
301         * ===================================================================
302         */
303        protected void startTest()
304        {
305            _iterations = 0;
306            t0 = t1 = System.currentTimeMillis();
307        }
308    
309        protected Results endTest()
310        {
311            return new Results( _iterations, t1 - t0, _isMvel );
312        }
313    
314        protected boolean done()
315        {
316            _iterations++;
317            t1 = System.currentTimeMillis();
318    
319            if ( TIME_MODE )
320            {
321                return ( t1 - t0 ) >= MAX_TIME;
322            }
323            else
324            {
325                if ( ITERATIONS_MODE )
326                {
327                    return _iterations >= MAX_ITERATIONS;
328                }
329                else
330                {
331                    throw new RuntimeException( "no maximums specified" );
332                }
333            }
334        }
335    
336        /*
337         * =================================================================== Public methods
338         * ===================================================================
339         */
340        public String getName()
341        {
342            return _name;
343        }
344    
345        public String getExpression()
346        {
347            return _expressionString;
348        }
349    
350        public Results testExpression( boolean compiled )
351            throws Exception
352        {
353            startTest();
354            do
355            {
356                if ( !_isMvel )
357                {
358                    if ( compiled )
359                        Ognl.getValue( _compiledExpression.getAccessor(), _context, _root );
360                    else
361                        Ognl.getValue( _expression, _context, _root );
362                }
363                else
364                {
365                    /*
366                     * if (compiled) MVEL.executeExpression(_mvelCompiled, _root); else MVEL.eval(_expressionString, _root);
367                     */
368                }
369            }
370            while ( !done() );
371            return endTest();
372        }
373    
374        public Results testJava()
375            throws OgnlException
376        {
377            try
378            {
379                return (Results) _method.invoke( this );
380            }
381            catch ( Exception ex )
382            {
383                throw new OgnlException( "invoking java method '" + _method.getName() + "'", ex );
384            }
385        }
386    
387        public Results testConstantExpression()
388            throws OgnlException
389        {
390            startTest();
391            do
392            {
393                @SuppressWarnings( "unused" )
394                int result = 100 + 20 * 5;
395            }
396            while ( !done() );
397            return endTest();
398        }
399    
400        public Results testSinglePropertyExpression()
401            throws OgnlException
402        {
403            startTest();
404            do
405            {
406                _root.getBean2();
407            }
408            while ( !done() );
409            return endTest();
410        }
411    
412        public Results testPropertyNavigationExpression()
413            throws OgnlException
414        {
415            startTest();
416            do
417            {
418                _root.getBean2().getBean3().getValue();
419            }
420            while ( !done() );
421            return endTest();
422        }
423    
424        public Results testPropertyNavigationSetting()
425            throws OgnlException
426        {
427            startTest();
428            do
429            {
430                _root.getBean2().getBean3().setNullValue( "a value" );
431            }
432            while ( !done() );
433            return endTest();
434        }
435    
436        public Results testPropertyNavigationAndComparisonExpression()
437            throws OgnlException
438        {
439            startTest();
440            do
441            {
442                @SuppressWarnings( "unused" )
443                boolean result = _root.getBean2().getBean3().getValue() < 24;
444            }
445            while ( !done() );
446            return endTest();
447        }
448    
449        public Results testIndexedPropertyNavigationExpression()
450            throws OgnlException
451        {
452            startTest();
453            do
454            {
455                _root.getBean2().getBean3().getIndexedValue( 25 );
456            }
457            while ( !done() );
458            return endTest();
459        }
460    
461        public Results testPropertyNavigationWithMapSetting()
462            throws OgnlException
463        {
464            startTest();
465            do
466            {
467                _root.getBean2().getBean3().getMap().put( "bam", "bam" );
468            }
469            while ( !done() );
470            return endTest();
471        }
472    
473        public Results testPropertyNavigationWithMapExpression()
474            throws OgnlException
475        {
476            startTest();
477            do
478            {
479                _root.getBean2().getBean3().getMap().get( "foo" );
480            }
481            while ( !done() );
482            return endTest();
483        }
484    }