You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2012/05/26 16:29:55 UTC

svn commit: r1342903 - /commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java

Author: damjan
Date: Sat May 26 14:29:55 2012
New Revision: 1342903

URL: http://svn.apache.org/viewvc?rev=1342903&view=rev
Log:
Include a test utility for timing and memory in project example classes.

Jira issue key: IMAGING-61
Submitted by: Gary Lucas <gwlucas at sonalysts dot com>


Added:
    commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java   (with props)

Added: commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java?rev=1342903&view=auto
==============================================================================
--- commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java (added)
+++ commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java Sat May 26 14:29:55 2012
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+
+/****************************************************************
+ * Explanation of Use and Rationale For Procedures
+ * 
+ * This class is intended to serve as a "test stand" for loading
+ * images using the Apache Imaging (nee "Sanselan") package.
+ * It performs a loop that loads a specified image multiple times
+ * recording both memory and time required for the loading process.
+ * 
+ * The notes given below explain some of the operations of this
+ * test class and the reasons they were designed as they are.
+ * This test is by no means to be considered the "last word" in how
+ * to write a test application. The techniques described below have
+ * demonstrated themselves useful and relevant in developing speed
+ * enhancements for some of the Apache Imaging operations. But I know
+ * I haven't thought of everything and am actually hoping that
+ * someone will have suggestions for improvements.
+ * 
+ * 
+ * Prerequisites to Testing  --------------------------------
+ * 
+ * Whenever testing software performance, particularly timing, 
+ * there are a few important considerations that should be observed:
+ * 
+ *   a) Get a clean testing environment. In a modern computer 
+ *      system, there are dozens of processes running.  To whatever
+ *      degree possible, make sure you are not running competing
+ *      processes that will consume computer resources and contaminate
+ *      your timing results.
+ * 
+ *   b) Make sure you are testing what you think you are testing.
+ *      This guideline is especially true when comparing two different
+ *      approaches.  Eliminate as many variables from the analysis
+ *      as you possible can.
+ * 
+ *   c) When writing or modifying code, remember that no matter how
+ *      obvious and self-evidentially superior a particular approach
+ *      may seem, you don't really know if it's an improvement until you
+ *      test it. If nothing else, the experience of computer programming
+ *      teaches us to not to take anything for granted.
+ * 
+ *   d) Make sure the JVM is allowed a sufficiently large maximum
+ *      memory size.   Putting aside the fact that the default size
+ *      for the maximum memory use of the JVM could be too small for
+ *      handling test images, we also want to allocate a sufficiently
+ *      large memory size to ensure that it doesn't get too close to
+ *      the maximum size when performing timing tests.   When the JVM
+ *      detects that it is running up against the limits of its 
+ *      maximum memory size setting, it triggers garbage collection
+ *      operations that can contaminate timing values.
+ *        I usually try to set the maximum memory size to be at least
+ *      twice what I think I will need.  Traditionally, the memory 
+ *      size for the JVM is quite modest, perhaps 256 megabytes.  You
+ *      can alter that value by using something like the following
+ *      specification (check your own JVM version for alternate values):
+ *            -Xmx768M   (maximum of 768 megabytes)
+ *      
+ *  
+ * 
+ *  
+ * What the Test Application Does and Why ----------------------
+ * 
+ * 0.  Functions  ------------------
+ * This class reads the path to a graphics file from the command
+ * line and attempts to read it several times, measuring the time
+ * required to read it.   If you prefer, you may hardwire the code
+ * to use a specific file.  Take whatever approach is easiest... it
+ * shouldn't affect the accuracy of the results.
+ * 
+ * 1)  Specific Instances of Classes to Be Tested  -----------------
+ * The Apache Imagine package includes a set of "parsers" for
+ * reading different graphics file formats.  The package also includes 
+ * a general-purpose class called "Imaging" that determines
+ * the format an arbitrarily specified input
+ * file and internally processes it using the appropriate parser.
+ *    However, unless you wish to test the performance of the Imaging
+ * class itself, it is better to instantiate the proper subject-matter
+ * parser explicitly in your code.  In ordinary applications, it is often
+ * more convenient to use the Imaging class and let it take care
+ * of the details for you.  But in that "taking care of details" 
+ * operation, the Imaging class loads and instantiates a large
+ * number of different subject-matter parsers.  These operations take
+ * time, consume memory, and will color the results of any timing
+ * and memory-use measurements you perform.
+ * 
+ * 2) Repetition -----------------------------------------
+ * The example output from this program included below, shows that
+ * it performs multiple image-loading operations, recording both
+ * the time required for each individual load time and the overall
+ * average time required for most of the load operations (times are
+ * in milliseconds).  
+ * 
+ *  image size: 10000 by 10000
+ *  time to load image               memory
+ *  time ms      avg ms         used mb   total mb
+ * 15559.150     0.000    --    384.845   397.035 
+ *  8544.926     0.000    --    410.981   568.723 
+ *  8471.012  8471.012    --    411.563   695.723 
+ *  8626.015  8548.513    --    384.791   397.039 
+ * 
+ * Note that in the example output, the times for the first two load 
+ * operations are not included in the average.  The reason for this is
+ * that the first time a Java application performs some operation,
+ * it is likely to take a little longer than for subsequent
+ * operations due to the overhead for class loading and the 
+ * just-in-time (JIT) compiler.  Unless you're specifically interested
+ * in measuring the cost of start-up operations, the time they take
+ * will contaminate any timing values for the functions of interest.
+ *    My experience under Windows is that the overhead only affects the
+ * first time I load an image.  In Linux, I've noticed that it can sometimes
+ * carry over into the second.  In either case, two loop iterations
+ * has proven to be enough to isolate the start costs... but keep an eye
+ * on the individual times to make sure nothing unwanted is happening.
+ * 
+ * 3) Clean Up Memory Between Load Operations --------------------
+ * This test application specifically invokes the garbage collection
+ * method provided by the Java Runtime class.  It then executes a one-second
+ * sleep operation.
+ *    Recall that in Java, the JVM performs garbage collection in a 
+ * separate thread that runs whenever Java thinks it important to do so.
+ * We want to do what we can to ensure that the garbage collection operation,
+ * which consumes processor resources, doesn't do so while the application
+ * is loading an image.  To that end, the application invokes 
+ * Runtime.gc() and then allows the JVM one second to initiate and 
+ * complete the garbage collection.  However, the .gc() method is, at best,
+ * a "suggestion" that the JVM should run garbage collection.
+ * It does not guarantee that the garbage collection will be executed and
+ * completed immediately.  Thus the relatively long one-second delay
+ * between loop iterations.
+ * 
+ * ---------------------------------------------------------------------
+ * Good luck in using the class for testing.
+ * Feel free to modify it to suit your own requirements... Nothing
+ * I've done in this code is beyond improvement.   I hope it works
+ * well for you.
+ *                Gary Lucas --  May 2012.
+ * ---------------------------------------------------------------
+ * 
+ */
+package org.apache.commons.imaging.examples;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.Formatter;
+import java.util.HashMap;
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
+import org.apache.commons.imaging.formats.tiff.TiffImageParser;
+
+/**
+ * A "test stand" for evaluating the speed an memory use
+ * of different Apache Imaging operations
+ */
+public class ApacheImagingSpeedAndMemoryTest
+{
+
+    /**
+     * Create an instance of the speed and memory test class
+     * and execute a test loop for the specified file.
+     * @param args the path to the file to be processed
+     */
+    public static void main(String[] args)
+    {
+        String name = args[0];
+        
+        ApacheImagingSpeedAndMemoryTest testStand =
+                new ApacheImagingSpeedAndMemoryTest();
+
+        testStand.performTest(name);
+    }
+
+    /**
+     * Loads the input file multiple times, measuring the
+     * time and memory use for each iteration.
+     * @param name the path for the input image file to be tested 
+     */
+    private void performTest(String name)
+    {
+        File target = new File(name);
+        Formatter fmt = new Formatter(System.out);
+        
+        double sumTime = 0;
+        int n = 1;
+        for (int i = 0; i < 10; i++) {
+            try {
+                ByteSourceFile byteSource = new ByteSourceFile(target);
+                //    This test code allows you to test cases where the
+                //    input is processed using Apache Imaging's
+                //    ByteSourceInputStream rather than the ByteSourceFile.
+                //    You might also want to experiment with ByteSourceArray.
+                //    FileInputStream fins = new FileInputStream(target);
+                //    BufferedInputStream bins = new BufferedInputStream(fins);
+                //    ByteSourceInputStream byteSource = 
+                //        new ByteSourceInputStream(bins, target.getName());
+                
+                // ready the parser (you may modify this code block
+                // to use your parser of choice)
+                HashMap params = new HashMap();
+                TiffImageParser tiffImageParser = new TiffImageParser();
+                
+                // load the file and record time needed to do so
+                long time0 = System.nanoTime();
+                BufferedImage bImage =
+                        tiffImageParser.getBufferedImage(byteSource, params);
+                long time1 = System.nanoTime();
+                
+                // tabulate results
+                double testTime = (time1 - time0) / 1000000.0;
+                if (i > 1) {
+                    n = i - 1;
+                    sumTime += testTime;
+                }
+                double avgTime = sumTime / n;
+
+                // tabulate the memory results.  Note that the
+                // buffered image, the byte source, and the parser
+                // are all still in scope.  This approach is taken 
+                // to get some sense of peak memory use, but Java
+                // may have already started collecting garbage,
+                // so there are limits to the reliability of these 
+                // statistics
+                Runtime r = Runtime.getRuntime();
+                long freeMemory = r.freeMemory();
+                long totalMemory = r.totalMemory();
+                long usedMemory = totalMemory - freeMemory;
+
+                if (i == 0) {
+                    // print header info
+                    fmt.format("\n");
+                    fmt.format("Processing file: %s\n", target.getName());
+                    fmt.format(" image size: %d by %d\n\n", 
+                           bImage.getWidth(), 
+                           bImage.getHeight());
+                    fmt.format(
+                           " time to load image    --         memory\n");
+                    fmt.format(
+                           " time ms      avg ms   --    used mb   total mb\n");
+                }
+                fmt.format("%9.3f %9.3f    --  %9.3f %9.3f \n",
+                        testTime,
+                        avgTime,
+                        usedMemory / (1024.0 * 1024.0),
+                        totalMemory / (1024.0 * 1024.0));
+                bImage = null;
+                byteSource = null;
+                params = null;
+                tiffImageParser = null;
+            } catch (ImageReadException ire) {
+                ire.printStackTrace();
+                System.exit(-1);
+            } catch (IOException ioex) {
+                ioex.printStackTrace();
+                System.exit(-1);
+            }
+
+            try {
+                // sleep between loop iterations allows time
+                // for the JVM to clean up memory.  The Netbeans IDE
+                // doesn't "get" the fact that we're doing this operation
+                // deliberately and is apt offer hints 
+                // suggesting that the code should be modified
+                Runtime.getRuntime().gc();
+                Thread.sleep(1000);
+            } catch (InterruptedException iex) {
+                // this isn't fatal, but shouldn't happen
+                iex.printStackTrace();
+            }
+
+        }
+    }
+}
+

Propchange: commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/ApacheImagingSpeedAndMemoryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native