1/* 2 * Copyright (c) 2009, 2012, 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 24import java.util.*; 25import java.nio.*; 26import java.nio.charset.*; 27import java.util.concurrent.*; 28import java.util.regex.Pattern; 29 30/** 31 * Usage: java StringCodingBenchmark 32 * [-Diterations=N] [-Dsize=N] [-Dsubsize=N] [-Dmaxchar=N] 33 * [-Dfilter=REGEXP] [-DSecurityManager=true] 34 */ 35public class StrCodingBenchmark { 36 abstract static class Job { 37 private final String name; 38 public Job(String name) { this.name = name; } 39 public String name() { return name; } 40 public abstract void work() throws Throwable; 41 } 42 43 private static void collectAllGarbage() { 44 final java.util.concurrent.CountDownLatch drained 45 = new java.util.concurrent.CountDownLatch(1); 46 try { 47 System.gc(); // enqueue finalizable objects 48 new Object() { protected void finalize() { 49 drained.countDown(); }}; 50 System.gc(); // enqueue detector 51 drained.await(); // wait for finalizer queue to drain 52 System.gc(); // cleanup finalized objects 53 } catch (InterruptedException e) { throw new Error(e); } 54 } 55 56 /** 57 * Runs each job for long enough that all the runtime compilers 58 * have had plenty of time to warm up, i.e. get around to 59 * compiling everything worth compiling. 60 * Returns array of average times per job per run. 61 */ 62 public static long[] time0(Job ... jobs) throws Throwable { 63 //final long warmupNanos = 10L * 1000L * 1000L * 1000L; 64 final long warmupNanos = 100L * 100L; 65 long[] nanoss = new long[jobs.length]; 66 for (int i = 0; i < jobs.length; i++) { 67 collectAllGarbage(); 68 long t0 = System.nanoTime(); 69 long t; 70 int j = 0; 71 do { jobs[i].work(); j++; } 72 while ((t = System.nanoTime() - t0) < warmupNanos); 73 nanoss[i] = t/j; 74 } 75 return nanoss; 76 } 77 78 public static long[] time(Job ... jobs) throws Throwable { 79 80 long[] warmup = time0(jobs); // Warm up run 81 long[] nanoss = time0(jobs); // Real timing run 82 long[] milliss = new long[jobs.length]; 83 double[] ratios = new double[jobs.length]; 84 85 final String nameHeader = "Method"; 86 final String millisHeader = "Millis"; 87 final String ratioHeader = "Ratio"; 88 89 int nameWidth = nameHeader.length(); 90 int millisWidth = millisHeader.length(); 91 int ratioWidth = ratioHeader.length(); 92 93 for (int i = 0; i < jobs.length; i++) { 94 nameWidth = Math.max(nameWidth, jobs[i].name().length()); 95 96 milliss[i] = nanoss[i]/(1000L * 1000L); 97 millisWidth = Math.max(millisWidth, 98 String.format("%d", milliss[i]).length()); 99 100 ratios[i] = (double) nanoss[i] / (double) nanoss[0]; 101 ratioWidth = Math.max(ratioWidth, 102 String.format("%.3f", ratios[i]).length()); 103 } 104 String format = String.format("%%-%ds %%%dd %n", 105 nameWidth, millisWidth); 106 String headerFormat = String.format("%%-%ds %%%ds%n", 107 nameWidth, millisWidth); 108 System.out.printf(headerFormat, "Method", "Millis"); 109 110 // Print out absolute and relative times, calibrated against first job 111 for (int i = 0; i < jobs.length; i++) 112 System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]); 113 return milliss; 114 } 115 116 public static Job[] filter(Pattern filter, Job[] jobs) { 117 if (filter == null) return jobs; 118 Job[] newJobs = new Job[jobs.length]; 119 int n = 0; 120 for (Job job : jobs) 121 if (filter.matcher(job.name()).find()) 122 newJobs[n++] = job; 123 // Arrays.copyOf not available in JDK 5 124 Job[] ret = new Job[n]; 125 System.arraycopy(newJobs, 0, ret, 0, n); 126 return ret; 127 } 128 129 static class PermissiveSecurityManger extends SecurityManager { 130 @Override public void checkPermission(java.security.Permission p) { 131 } 132 } 133 134 public static void main(String[] args) throws Throwable { 135 final int itrs = Integer.getInteger("iterations", 100000); 136 final int size = Integer.getInteger("size", 2048); 137 final int subsize = Integer.getInteger("subsize", 128); 138 final int maxchar = Integer.getInteger("maxchar", 128); 139 final String regex = System.getProperty("filter"); 140 final Pattern filter = (regex == null) ? null : Pattern.compile(regex); 141 final boolean useSecurityManager = Boolean.getBoolean("SecurityManager"); 142 if (useSecurityManager) 143 System.setSecurityManager(new PermissiveSecurityManger()); 144 final Random rnd = new Random(); 145 146 for (Charset charset: Charset.availableCharsets().values()) { 147 if (!("ISO-8859-1".equals(charset.name()) || 148 "US-ASCII".equals(charset.name()) || 149 charset.newDecoder() instanceof sun.nio.cs.SingleByte.Decoder)) 150 continue; 151 final String csn = charset.name(); 152 final Charset cs = charset; 153 final StringBuilder sb = new StringBuilder(); 154 { 155 final CharsetEncoder enc = cs.newEncoder(); 156 for (int i = 0; i < size; ) { 157 char c = (char) rnd.nextInt(maxchar); 158 if (enc.canEncode(c)) { 159 sb.append(c); 160 i++; 161 } 162 } 163 } 164 final String string = sb.toString(); 165 final byte[] bytes = string.getBytes(cs); 166 167 System.out.printf("%n--------%s---------%n", csn); 168 for (int sz = 4; sz <= 2048; sz *= 2) { 169 System.out.printf(" [len=%d]%n", sz); 170 final byte[] bs = Arrays.copyOf(bytes, sz); 171 final String str = new String(bs, csn); 172 Job[] jobs = { 173 new Job("String decode: csn") { 174 public void work() throws Throwable { 175 for (int i = 0; i < itrs; i++) 176 new String(bs, csn); 177 }}, 178 179 new Job("String decode: cs") { 180 public void work() throws Throwable { 181 for (int i = 0; i < itrs; i++) 182 new String(bs, cs); 183 }}, 184 185 new Job("String encode: csn") { 186 public void work() throws Throwable { 187 for (int i = 0; i < itrs; i++) 188 str.getBytes(csn); 189 }}, 190 191 new Job("String encode: cs") { 192 public void work() throws Throwable { 193 for (int i = 0; i < itrs; i++) 194 str.getBytes(cs); 195 }}, 196 }; 197 time(filter(filter, jobs)); 198 } 199 } 200 } 201} 202