diff options
author | sherman <none@none> | 2009-03-23 09:19:23 -0700 |
---|---|---|
committer | sherman <none@none> | 2009-03-23 09:19:23 -0700 |
commit | f2f0f51d76022a63d5a0263d71584f6d656471ab (patch) | |
tree | 247274dc1ffaf67d2a8ce5b843a853af6adf1afe /test/sun/nio | |
parent | 19268abd81b6c33f1754691ca288939ad1fe0af5 (diff) |
6636323: Optimize handling of builtin charsets
6636319: Encoders should implement isLegalReplacement(byte[] repl)
Summary: optimized new String(byte[], cs/csn) and String.getBytes(cs/csn) for speed and memory consumption in singlebyte case.
Reviewed-by: alanb
Diffstat (limited to 'test/sun/nio')
-rw-r--r-- | test/sun/nio/cs/FindEncoderBugs.java | 1 | ||||
-rw-r--r-- | test/sun/nio/cs/StrCodingBenchmark.java | 200 | ||||
-rw-r--r-- | test/sun/nio/cs/TestStringCoding.java | 151 |
3 files changed, 351 insertions, 1 deletions
diff --git a/test/sun/nio/cs/FindEncoderBugs.java b/test/sun/nio/cs/FindEncoderBugs.java index 0f4c406d4..54bc5b268 100644 --- a/test/sun/nio/cs/FindEncoderBugs.java +++ b/test/sun/nio/cs/FindEncoderBugs.java @@ -526,4 +526,3 @@ public class FindEncoderBugs { System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} } - diff --git a/test/sun/nio/cs/StrCodingBenchmark.java b/test/sun/nio/cs/StrCodingBenchmark.java new file mode 100644 index 000000000..73256eb2b --- /dev/null +++ b/test/sun/nio/cs/StrCodingBenchmark.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.concurrent.*; +import java.util.regex.Pattern; + +/** + * Usage: java StringCodingBenchmark + * [-Diterations=N] [-Dsize=N] [-Dsubsize=N] [-Dmaxchar=N] + * [-Dfilter=REGEXP] [-DSecurityManager=true] + */ +public class StrCodingBenchmark { + abstract static class Job { + private final String name; + public Job(String name) { this.name = name; } + public String name() { return name; } + public abstract void work() throws Throwable; + } + + private static void collectAllGarbage() { + final java.util.concurrent.CountDownLatch drained + = new java.util.concurrent.CountDownLatch(1); + try { + System.gc(); // enqueue finalizable objects + new Object() { protected void finalize() { + drained.countDown(); }}; + System.gc(); // enqueue detector + drained.await(); // wait for finalizer queue to drain + System.gc(); // cleanup finalized objects + } catch (InterruptedException e) { throw new Error(e); } + } + + /** + * Runs each job for long enough that all the runtime compilers + * have had plenty of time to warm up, i.e. get around to + * compiling everything worth compiling. + * Returns array of average times per job per run. + */ + public static long[] time0(Job ... jobs) throws Throwable { + //final long warmupNanos = 10L * 1000L * 1000L * 1000L; + final long warmupNanos = 100L * 100L; + long[] nanoss = new long[jobs.length]; + for (int i = 0; i < jobs.length; i++) { + collectAllGarbage(); + long t0 = System.nanoTime(); + long t; + int j = 0; + do { jobs[i].work(); j++; } + while ((t = System.nanoTime() - t0) < warmupNanos); + nanoss[i] = t/j; + } + return nanoss; + } + + public static void time(Job ... jobs) throws Throwable { + + long[] warmup = time0(jobs); // Warm up run + long[] nanoss = time0(jobs); // Real timing run + long[] milliss = new long[jobs.length]; + double[] ratios = new double[jobs.length]; + + final String nameHeader = "Method"; + final String millisHeader = "Millis"; + final String ratioHeader = "Ratio"; + + int nameWidth = nameHeader.length(); + int millisWidth = millisHeader.length(); + int ratioWidth = ratioHeader.length(); + + for (int i = 0; i < jobs.length; i++) { + nameWidth = Math.max(nameWidth, jobs[i].name().length()); + + milliss[i] = nanoss[i]/(1000L * 1000L); + millisWidth = Math.max(millisWidth, + String.format("%d", milliss[i]).length()); + + ratios[i] = (double) nanoss[i] / (double) nanoss[0]; + ratioWidth = Math.max(ratioWidth, + String.format("%.3f", ratios[i]).length()); + } + String format = String.format("%%-%ds %%%dd %n", + nameWidth, millisWidth); + String headerFormat = String.format("%%-%ds %%%ds%n", + nameWidth, millisWidth); + System.out.printf(headerFormat, "Method", "Millis"); + + // Print out absolute and relative times, calibrated against first job + for (int i = 0; i < jobs.length; i++) + System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]); + } + + public static Job[] filter(Pattern filter, Job[] jobs) { + if (filter == null) return jobs; + Job[] newJobs = new Job[jobs.length]; + int n = 0; + for (Job job : jobs) + if (filter.matcher(job.name()).find()) + newJobs[n++] = job; + // Arrays.copyOf not available in JDK 5 + Job[] ret = new Job[n]; + System.arraycopy(newJobs, 0, ret, 0, n); + return ret; + } + + static class PermissiveSecurityManger extends SecurityManager { + @Override public void checkPermission(java.security.Permission p) { + } + } + + public static void main(String[] args) throws Throwable { + final int itrs = Integer.getInteger("iterations", 100000); + final int size = Integer.getInteger("size", 2048); + final int subsize = Integer.getInteger("subsize", 128); + final int maxchar = Integer.getInteger("maxchar", 128); + final String regex = System.getProperty("filter"); + final Pattern filter = (regex == null) ? null : Pattern.compile(regex); + final boolean useSecurityManager = Boolean.getBoolean("SecurityManager"); + if (useSecurityManager) + System.setSecurityManager(new PermissiveSecurityManger()); + final Random rnd = new Random(); + + for (Charset charset: Charset.availableCharsets().values()) { + if (!("ISO-8859-1".equals(charset.name()) || + "US-ASCII".equals(charset.name()) || + charset.newDecoder() instanceof sun.nio.cs.SingleByte.Decoder)) + continue; + final String csn = charset.name(); + final Charset cs = charset; + final StringBuilder sb = new StringBuilder(); + { + final CharsetEncoder enc = cs.newEncoder(); + for (int i = 0; i < size; ) { + char c = (char) rnd.nextInt(maxchar); + if (enc.canEncode(c)) { + sb.append(c); + i++; + } + } + } + final String string = sb.toString(); + final byte[] bytes = string.getBytes(cs); + + System.out.printf("%n--------%s---------%n", csn); + for (int sz = 4; sz <= 2048; sz *= 2) { + System.out.printf(" [len=%d]%n", sz); + final byte[] bs = Arrays.copyOf(bytes, sz); + final String str = new String(bs, csn); + Job[] jobs = { + new Job("String decode: csn") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + new String(bs, csn); + }}, + + new Job("String decode: cs") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + new String(bs, cs); + }}, + + new Job("String encode: csn") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + str.getBytes(csn); + }}, + + new Job("String encode: cs") { + public void work() throws Throwable { + for (int i = 0; i < itrs; i++) + str.getBytes(cs); + }}, + }; + time(filter(filter, jobs)); + } + } + } +} diff --git a/test/sun/nio/cs/TestStringCoding.java b/test/sun/nio/cs/TestStringCoding.java new file mode 100644 index 000000000..8d0c8f94f --- /dev/null +++ b/test/sun/nio/cs/TestStringCoding.java @@ -0,0 +1,151 @@ +/* + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6636323 6636319 + @summary Test if StringCoding and NIO result have the same de/encoding result + * @run main/timeout=2000 TestStringCoding + */ + +import java.util.*; +import java.nio.*; +import java.nio.charset.*; + +public class TestStringCoding { + public static void main(String[] args) throws Throwable { + + for (Boolean hasSM: new boolean[] { false, true }) { + if (hasSM) + System.setSecurityManager(new PermissiveSecurityManger()); + for (Charset cs: Charset.availableCharsets().values()) { + if ("ISO-2022-CN".equals(cs.name()) || + "x-COMPOUND_TEXT".equals(cs.name()) || + "x-JISAutoDetect".equals(cs.name())) + continue; + System.out.printf("Testing(sm=%b) " + cs.name() + "....", hasSM); + // full bmp first + char[] bmpCA = new char[0x10000]; + for (int i = 0; i < 0x10000; i++) { + bmpCA[i] = (char)i; + } + byte[] sbBA = new byte[0x100]; + for (int i = 0; i < 0x100; i++) { + sbBA[i] = (byte)i; + } + test(cs, bmpCA, sbBA); + // "randomed" sizes + Random rnd = new Random(); + for (int i = 0; i < 10; i++) { + int clen = rnd.nextInt(0x10000); + int blen = rnd.nextInt(0x100); + //System.out.printf(" blen=%d, clen=%d%n", blen, clen); + test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen)); + //add a pair of surrogates + int pos = clen / 2; + if ((pos + 1) < blen) { + bmpCA[pos] = '\uD800'; + bmpCA[pos+1] = '\uDC00'; + } + test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen)); + } + System.out.println("done!"); + } + } + } + + static void test(Charset cs, char[] bmpCA, byte[] sbBA) throws Throwable { + String bmpStr = new String(bmpCA); + CharsetDecoder dec = cs.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + CharsetEncoder enc = cs.newEncoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + //getBytes(csn); + byte[] baSC = bmpStr.getBytes(cs.name()); + ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA)); + byte[] baNIO = new byte[bf.limit()]; + bf.get(baNIO, 0, baNIO.length); + if (!Arrays.equals(baSC, baNIO)) + throw new RuntimeException("getBytes(csn) failed -> " + cs.name()); + + //getBytes(cs); + baSC = bmpStr.getBytes(cs); + if (!Arrays.equals(baSC, baNIO)) + throw new RuntimeException("getBytes(cs) failed -> " + cs.name()); + + //new String(csn); + String strSC = new String(sbBA, cs.name()); + String strNIO = dec.reset().decode(ByteBuffer.wrap(sbBA)).toString(); + if(!strNIO.equals(strSC)) + throw new RuntimeException("new String(csn) failed -> " + cs.name()); + + //new String(cs); + strSC = new String(sbBA, cs); + if (!strNIO.equals(strSC)) + throw new RuntimeException("new String(cs) failed -> " + cs.name()); + + //encode unmappable surrogates + if (enc instanceof sun.nio.cs.ArrayEncoder && + cs.contains(Charset.forName("ASCII"))) { + enc.replaceWith(new byte[] { (byte)'A'}); + sun.nio.cs.ArrayEncoder cae = (sun.nio.cs.ArrayEncoder)enc; + + String str = "ab\uD800\uDC00\uD800\uDC00cd"; + byte[] ba = new byte[str.length() - 2]; + int n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 6 || !"abAAcd".equals(new String(ba, cs.name()))) + throw new RuntimeException("encode1(surrogates) failed -> " + + cs.name()); + + ba = new byte[str.length()]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 6 || !"abAAcd".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode2(surrogates) failed -> " + + cs.name()); + str = "ab\uD800B\uDC00Bcd"; + ba = new byte[str.length()]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 8 || !"abABABcd".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode3(surrogates) failed -> " + + cs.name()); + + ba = new byte[str.length() - 1]; + n = cae.encode(str.toCharArray(), 0, str.length(), ba); + if (n != 7 || !"abABABc".equals(new String(ba, 0, n, + cs.name()))) + throw new RuntimeException("encode4(surrogates) failed -> " + + cs.name()); + } + + } + + static class PermissiveSecurityManger extends SecurityManager { + @Override public void checkPermission(java.security.Permission p) {} + } +} |