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