FlaterCriticalArray.java revision 12745:f068a4ffddd2
1/* 2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/** 25 * ZIP inflater/deflater performance. 26 */ 27 28/* 29 * Run this test on JDK 6 and on later 30 * JDKs to compare results: 31 * java -server -Xms1024M -Xmx1024M -Ddebug=true FlaterCriticalArray 32 * 33 * The performance issues can be readily seen on JDK 6, and so this code is 34 * written to compile on that platform: it does *not* use any JDK 7 - specific 35 * features. 36 */ 37 38import java.io.*; 39import java.nio.*; 40import java.util.*; 41import java.util.zip.*; 42 43public class FlaterCriticalArray { 44 // If true, print information about performance 45 private static final boolean debug = System.getProperty("debug") != null; 46 47 private static void debug(String s) { 48 if (debug) System.out.println(s); 49 } 50 51 private static void debug(String name, String inOut, long time, int length) { 52 debug(name + ": Duration of " + inOut + "(in ms): " + time); 53 debug(name + ": " + inOut + "d data length: " + length + " bytes"); 54 } 55 56 private static byte[] grow(byte[] a, int capacity) { 57 while (a.length < capacity) { 58 byte[] a2 = new byte[a.length * 2]; 59 System.arraycopy(a, 0, a2, 0, a.length); 60 a = a2; 61 } 62 return a; 63 } 64 65 private static byte[] trim(byte[] a, int length) { 66 byte[] res = new byte[length]; 67 System.arraycopy(a, 0, res, 0, length); 68 return res; 69 } 70 71 /* 72 * Base class for individual test cases 73 */ 74 private abstract static class TestCase { 75 protected String name; // For information in debug messages 76 protected byte data[]; // Data to be deflated and subsequently inflated 77 protected int level; // Compression level for deflater 78 79 protected TestCase(String name, byte data[]) { 80 this(name, data, -1); 81 } 82 83 protected TestCase(String name, byte data[], int level) { 84 this.name = name; 85 this.data = data; 86 this.level = level; 87 } 88 89 public void runTest() throws Throwable { 90 long time0, time1; 91 byte deflated[], inflated[]; 92 93 debug(""); 94 95 time0 = System.currentTimeMillis(); 96 deflated = deflate(data, level); 97 time1 = System.currentTimeMillis(); 98 inform("Deflate", time1 - time0, deflated.length); 99 100 time0 = System.currentTimeMillis(); 101 inflated = inflate(deflated); 102 time1 = System.currentTimeMillis(); 103 inform("Inflate", time1 - time0, inflated.length); 104 105 check(Arrays.equals(data, inflated), 106 name + ": Inflated and deflated arrays do not match"); 107 } 108 109 private void inform(String inOut, long duration, int length) { 110 debug(name, inOut, duration, length); 111 } 112 113 protected abstract byte[] deflate(byte data[], int level) throws Throwable; 114 115 protected abstract byte[] inflate(byte deflated[]) throws Throwable; 116 } 117 118 /* 119 * Following are the individual test cases 120 */ 121 122 private static class StrideTest extends TestCase { 123 static final int STRIDE = 1024; 124 125 public StrideTest(byte data[], int level) { 126 super("STRIDE", data, level); 127 } 128 129 protected byte[] deflate(byte in[], int level) throws Throwable { 130 final int len = in.length; 131 final Deflater deflater = new Deflater(level); 132 final byte[] smallBuffer = new byte[32]; 133 byte[] flated = new byte[32]; 134 int count = 0; 135 for (int i = 0; i<len; i+= STRIDE) { 136 deflater.setInput(in, i, Math.min(STRIDE, len-i)); 137 while (!deflater.needsInput()) { 138 int n = deflater.deflate(smallBuffer); 139 flated = grow(flated, count + n); 140 System.arraycopy(smallBuffer, 0, flated, count, n); 141 count += n; 142 } 143 } 144 deflater.finish(); 145 int n; 146 do { 147 n = deflater.deflate(smallBuffer); 148 flated = grow(flated, count + n); 149 System.arraycopy(smallBuffer, 0, flated, count, n); 150 count += n; 151 } while (n > 0); 152 return trim(flated, count); 153 } 154 155 protected byte[] inflate(byte in[]) throws Throwable { 156 final int len = in.length; 157 final Inflater inflater = new Inflater(); 158 final byte[] smallBuffer = new byte[3200]; 159 160 byte[] flated = new byte[32]; 161 int count = 0; 162 163 for (int i = 0; i<len; i+= STRIDE) { 164 inflater.setInput(in, i, Math.min(STRIDE, len-i)); 165 while (!inflater.needsInput()) { 166 int n; 167 while ((n = inflater.inflate(smallBuffer)) > 0) { 168 flated = grow(flated, count + n); 169 System.arraycopy(smallBuffer, 0, flated, count, n); 170 count += n; 171 } 172 } 173 } 174 return trim(flated, count); 175 } 176 } 177 178 private static class NoStrideTest extends TestCase { 179 public NoStrideTest(byte data[], int level) { 180 super("NO STRIDE", data, level); 181 } 182 183 public byte[] deflate(byte in[], int level) throws Throwable { 184 final Deflater flater = new Deflater(level); 185 flater.setInput(in); 186 flater.finish(); 187 final byte[] smallBuffer = new byte[32]; 188 byte[] flated = new byte[32]; 189 int count = 0; 190 int n; 191 while ((n = flater.deflate(smallBuffer)) > 0) { 192 flated = grow(flated, count + n); 193 System.arraycopy(smallBuffer, 0, flated, count, n); 194 count += n; 195 } 196 return trim(flated, count); 197 } 198 199 public byte[] inflate(byte in[]) throws Throwable { 200 final Inflater flater = new Inflater(); 201 flater.setInput(in); 202 final byte[] smallBuffer = new byte[32]; 203 byte[] flated = new byte[32]; 204 int count = 0; 205 int n; 206 while ((n = flater.inflate(smallBuffer)) > 0) { 207 flated = grow(flated, count + n); 208 System.arraycopy(smallBuffer, 0, flated, count, n); 209 count += n; 210 } 211 return trim(flated, count); 212 } 213 } 214 215 /** 216 * Check Deflater{In,Out}putStream by way of GZIP{In,Out}putStream 217 */ 218 private static class GZIPTest extends TestCase { 219 public GZIPTest(byte data[]) { 220 super("GZIP", data); 221 } 222 223 public byte[] deflate(byte data[], int ignored) throws Throwable { 224 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 225 OutputStream gzos = new GZIPOutputStream(baos); 226 gzos.write(data, 0, data.length); 227 gzos.close(); 228 return baos.toByteArray(); 229 } 230 231 public byte[] inflate(byte deflated[]) throws Throwable { 232 InputStream bais = new ByteArrayInputStream(deflated); 233 GZIPInputStream gzis = new GZIPInputStream(bais); 234 byte[] inflated = new byte[data.length]; 235 int numRead = 0; 236 int count = 0; 237 while ((numRead = gzis.read(inflated, count, data.length - count)) > 0) { 238 count += numRead; 239 } 240 check(count == data.length, name + ": Read " + count + "; expected " + data.length); 241 return inflated; 242 } 243 } 244 245 public static void realMain(String[] args) throws Throwable { 246 byte data[]; 247 int level = -1; 248 if (args.length > 0) { 249 level = Integer.parseInt(args[0]); 250 } 251 debug("Using level " + level); 252 253 if (args.length > 1) { 254 FileInputStream fis = new FileInputStream(args[1]); 255 int len = fis.available(); 256 data = new byte[len]; 257 check(fis.read(data, 0, len) == len, "Did not read complete file"); 258 debug("Original data from " + args[1]); 259 fis.close(); 260 } else { 261 ByteBuffer bb = ByteBuffer.allocate(8); 262 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 263 for (int i = 0; i < 1024 * 64; i++) { // data length 264 bb.putDouble(0, Math.random()); 265 baos.write(bb.array(), 0, 8); 266 } 267 data = baos.toByteArray(); 268 debug("Original data from random byte array"); 269 } 270 debug("Original data length: " + data.length + " bytes"); 271 272 new StrideTest(data, level).runTest(); 273 new NoStrideTest(data, level).runTest(); 274 new GZIPTest(data).runTest(); 275 } 276 277 //--------------------- Infrastructure --------------------------- 278 static volatile int passed = 0, failed = 0; 279 static void pass() {passed++;} 280 static void pass(String msg) {System.out.println(msg); passed++;} 281 static void fail() {failed++; Thread.dumpStack();} 282 static void fail(String msg) {System.out.println(msg); fail();} 283 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 284 static void unexpected(Throwable t, String msg) { 285 System.out.println(msg); failed++; t.printStackTrace();} 286 static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} 287 static boolean check(boolean cond, String msg) {if (cond) pass(); else fail(msg); return cond;} 288 static void equal(Object x, Object y) { 289 if (x == null ? y == null : x.equals(y)) pass(); 290 else fail(x + " not equal to " + y);} 291 public static void main(String[] args) throws Throwable { 292 try {realMain(args);} catch (Throwable t) {unexpected(t);} 293 System.out.println("\nPassed = " + passed + " failed = " + failed); 294 if (failed > 0) throw new AssertionError("Some tests failed");} 295} 296