1 /* 2 * Copyright (c) 2009, 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 import java.util.*; 25 import java.nio.*; 26 import java.nio.charset.*; 27 import java.util.concurrent.*; 28 import 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 */ 35 public 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 void 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 } 114 115 public static Job[] filter(Pattern filter, Job[] jobs) { 116 if (filter == null) return jobs; 117 Job[] newJobs = new Job[jobs.length]; 118 int n = 0; 119 for (Job job : jobs) 120 if (filter.matcher(job.name()).find()) 121 newJobs[n++] = job; 122 // Arrays.copyOf not available in JDK 5 123 Job[] ret = new Job[n]; 124 System.arraycopy(newJobs, 0, ret, 0, n); 125 return ret; 126 } 127 128 static class PermissiveSecurityManger extends SecurityManager { 129 @Override public void checkPermission(java.security.Permission p) { 130 } 131 } 132 133 public static void main(String[] args) throws Throwable { 134 final int itrs = Integer.getInteger("iterations", 100000); 135 final int size = Integer.getInteger("size", 2048); 136 final int subsize = Integer.getInteger("subsize", 128); 137 final int maxchar = Integer.getInteger("maxchar", 128); 138 final String regex = System.getProperty("filter"); 139 final Pattern filter = (regex == null) ? null : Pattern.compile(regex); 140 final boolean useSecurityManager = Boolean.getBoolean("SecurityManager"); 141 if (useSecurityManager) 142 System.setSecurityManager(new PermissiveSecurityManger()); 143 final Random rnd = new Random(); 144 145 for (Charset charset: Charset.availableCharsets().values()) { 146 if (!("ISO-8859-1".equals(charset.name()) || 147 "US-ASCII".equals(charset.name()) || 148 charset.newDecoder() instanceof sun.nio.cs.SingleByte.Decoder)) 149 continue; 150 final String csn = charset.name(); 151 final Charset cs = charset; 152 final StringBuilder sb = new StringBuilder(); 153 { 154 final CharsetEncoder enc = cs.newEncoder(); 155 for (int i = 0; i < size; ) { 156 char c = (char) rnd.nextInt(maxchar); 157 if (enc.canEncode(c)) { 158 sb.append(c); 159 i++; 160 } 161 } 162 } 163 final String string = sb.toString(); 164 final byte[] bytes = string.getBytes(cs); 165 166 System.out.printf("%n--------%s---------%n", csn); 167 for (int sz = 4; sz <= 2048; sz *= 2) { 168 System.out.printf(" [len=%d]%n", sz); 169 final byte[] bs = Arrays.copyOf(bytes, sz); 170 final String str = new String(bs, csn); 171 Job[] jobs = { 172 new Job("String decode: csn") { 173 public void work() throws Throwable { 174 for (int i = 0; i < itrs; i++) 175 new String(bs, csn); 176 }}, 177 178 new Job("String decode: cs") { 179 public void work() throws Throwable { 180 for (int i = 0; i < itrs; i++) 181 new String(bs, cs); 182 }}, 183 184 new Job("String encode: csn") { 185 public void work() throws Throwable { 186 for (int i = 0; i < itrs; i++) 187 str.getBytes(csn); 188 }}, 189 190 new Job("String encode: cs") { 191 public void work() throws Throwable { 192 for (int i = 0; i < itrs; i++) 193 str.getBytes(cs); 194 }}, 195 }; 196 time(filter(filter, jobs)); 197 } 198 } 199 } 200 }