DeflateComparison.java

  1. package gov.usgs.earthquake.distribution;

  2. import gov.usgs.earthquake.product.FileContent;
  3. import gov.usgs.earthquake.product.Product;
  4. import gov.usgs.earthquake.product.ProductId;
  5. import gov.usgs.earthquake.product.io.BinaryProductHandler;
  6. import gov.usgs.earthquake.product.io.ObjectProductSource;
  7. import gov.usgs.util.StreamUtils;

  8. import java.io.ByteArrayInputStream;
  9. import java.io.ByteArrayOutputStream;
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.OutputStream;
  14. import java.net.URL;
  15. import java.util.Date;
  16. import java.util.zip.Deflater;
  17. import java.util.zip.DeflaterOutputStream;


  18. public class DeflateComparison {

  19.     /**
  20.      * Deflate an input stream.
  21.      *
  22.      * @param level
  23.      *            deflate level.
  24.      * @param in
  25.      *            input stream to deflate.
  26.      * @return output length in bytes.
  27.      * @throws IOException if IO error occurs
  28.      */
  29.     public long deflateStream(final int level, final InputStream in)
  30.             throws IOException {
  31.         CountingOutputStream cos = new CountingOutputStream();
  32.         DeflaterOutputStream dos = new DeflaterOutputStream(cos, new Deflater(
  33.                 level));
  34.         StreamUtils.transferStream(in, new StreamUtils.UnclosableOutputStream(
  35.                 dos));
  36.         dos.finish();
  37.         dos.close();
  38.         return cos.getTotalBytes();
  39.     }

  40.     /**
  41.      * Transfer an input stream.
  42.      *
  43.      * @param in
  44.      *            input stream to transfer.
  45.      * @return output length in bytes.
  46.      * @throws IOException if IO error occurs
  47.      */
  48.     public long transferStream(final InputStream in) throws IOException {
  49.         CountingOutputStream cos = new CountingOutputStream();
  50.         StreamUtils.transferStream(in, cos);
  51.         return cos.getTotalBytes();
  52.     }

  53.     /**
  54.      * Test different compression levels and speeds for a file.
  55.      *
  56.      * Reads file into memory to avoid disk io overhead.
  57.      *
  58.      * @param file
  59.      *            file to test.
  60.      * @throws IllegalArgumentException if illegal arg
  61.      * @throws IOException if IO error occurs
  62.      */
  63.     public void testFile(final File file) throws IllegalArgumentException,
  64.             IOException {
  65.         // read into memory to avoid disk io overhead
  66.         byte[] fileContent = StreamUtils.readStream(StreamUtils
  67.                 .getInputStream(file));
  68.         testByteArray(file.getCanonicalPath(), fileContent);
  69.     }

  70.     /**
  71.      * Test different compression levels and speeds for a byte array.
  72.      *
  73.      * @param name
  74.      *            given name
  75.      * @param content
  76.      *            content to test.
  77.      * @throws IllegalArgumentException if illegal arg
  78.      * @throws IOException if IO error occurs
  79.      */
  80.     public void testByteArray(final String name, final byte[] content)
  81.             throws IOException {
  82.         Date start;
  83.         long totalBytes = content.length;

  84.         System.err.println(name + ", length = " + totalBytes + " bytes");

  85.         System.err.println("no compression");
  86.         start = new Date();
  87.         long noCompression = transferStream(new ByteArrayInputStream(content));
  88.         long noCompressionTime = new Date().getTime() - start.getTime();
  89.         formatResult(totalBytes, noCompression, noCompressionTime);

  90.         System.err.println("default compression (-1)");
  91.         start = new Date();
  92.         long deflateDefault = deflateStream(Deflater.DEFAULT_COMPRESSION,
  93.                 new ByteArrayInputStream(content));
  94.         long deflateDefaultTime = new Date().getTime() - start.getTime();
  95.         formatResult(totalBytes, deflateDefault, deflateDefaultTime);

  96.         System.err.println("best speed (1)");
  97.         start = new Date();
  98.         long deflateBestSpeed = deflateStream(Deflater.BEST_SPEED,
  99.                 new ByteArrayInputStream(content));
  100.         long deflateBestSpeedTime = new Date().getTime() - start.getTime();
  101.         formatResult(totalBytes, deflateBestSpeed, deflateBestSpeedTime);

  102.         System.err.println("best compression (9)");
  103.         start = new Date();
  104.         long deflateBestCompression = deflateStream(Deflater.BEST_COMPRESSION,
  105.                 new ByteArrayInputStream(content));
  106.         long deflateBestCompressionTime = new Date().getTime()
  107.                 - start.getTime();
  108.         formatResult(totalBytes, deflateBestCompression,
  109.                 deflateBestCompressionTime);
  110.     }

  111.     /**
  112.      * For calculating for properly formatting the results
  113.      *
  114.      * @param totalBytes totalBytes
  115.      * @param transferredBytes Bytes transferred
  116.      * @param elapsedTime total elapsed time
  117.      */
  118.     protected void formatResult(final long totalBytes,
  119.             final long transferredBytes, final long elapsedTime) {
  120.         long savedBytes = totalBytes - transferredBytes;
  121.         System.err.printf("\t%.3fs, %.1f%% reduction (%d fewer bytes)%n",
  122.                 elapsedTime / 1000.0,
  123.                 100 * (savedBytes / ((double) totalBytes)), savedBytes);
  124.     }

  125.     /**
  126.      * An output stream that counts how many bytes are written, and otherwise
  127.      * ignores output.
  128.      */
  129.     private static class CountingOutputStream extends OutputStream {
  130.         // number of bytes output
  131.         private long totalBytes = 0L;

  132.         public long getTotalBytes() {
  133.             return totalBytes;
  134.         }

  135.         @Override
  136.         public void write(byte[] b) {
  137.             totalBytes += b.length;
  138.         }

  139.         @Override
  140.         public void write(byte[] b, int offset, int length) {
  141.             totalBytes += length;
  142.         }

  143.         @Override
  144.         public void write(int arg0) throws IOException {
  145.             totalBytes++;
  146.         }

  147.     }

  148.     /**
  149.      * A main method for accessing tests using custom files.
  150.      *
  151.      * @param args
  152.      *            a list of files or directorys to include in compression
  153.      *            comparison.
  154.      * @throws Exception if error occurs
  155.      */
  156.     public static void main(final String[] args) throws Exception {
  157.         if (args.length == 0) {
  158.             System.err.println("Usage: DeflateComparison FILE [FILE ...]");
  159.             System.err
  160.                     .println("where FILE is a file or directory to include in comparison");
  161.             System.exit(1);
  162.         }

  163.         Product product = new Product(new ProductId("test", "test", "test"));
  164.         try {
  165.             product.setTrackerURL(new URL("http://localhost/tracker"));
  166.         } catch (Exception e) {
  167.             // ignore
  168.         }

  169.         // treat all arguments as files or directories to be added as content
  170.         for (String arg : args) {
  171.             File file = new File(arg);
  172.             if (!file.exists()) {
  173.                 System.err.println(file.getCanonicalPath() + " does not exist");
  174.                 System.exit(1);
  175.             }

  176.             if (file.isDirectory()) {
  177.                 product.getContents().putAll(
  178.                         FileContent.getDirectoryContents(file));
  179.             } else {
  180.                 product.getContents()
  181.                         .put(file.getName(), new FileContent(file));
  182.             }
  183.         }

  184.         // convert product to byte array in binary format
  185.         System.err.println("Reading files into memory");
  186.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  187.         new ObjectProductSource(product)
  188.                 .streamTo(new BinaryProductHandler(baos));
  189.         new DeflateComparison().testByteArray("product contents",
  190.                 baos.toByteArray());
  191.     }

  192. }