StrCodingBenchmark.java revision 964:4faf788c4949
177218Sphk/* 277218Sphk * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. 377218Sphk * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 477218Sphk * 577218Sphk * This code is free software; you can redistribute it and/or modify it 677218Sphk * under the terms of the GNU General Public License version 2 only, as 777218Sphk * published by the Free Software Foundation. 877218Sphk * 977218Sphk * This code is distributed in the hope that it will be useful, but WITHOUT 1077218Sphk * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1177218Sphk * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1291454Sbrooks * version 2 for more details (a copy is included in the LICENSE file that 1391454Sbrooks * accompanied this code). 1477218Sphk * 1577218Sphk * You should have received a copy of the GNU General Public License version 1677218Sphk * 2 along with this work; if not, write to the Free Software Foundation, 1777218Sphk * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1877218Sphk * 1977218Sphk * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 2077218Sphk * CA 95054 USA or visit www.sun.com if you need additional information or 2177218Sphk * have any questions. 2277218Sphk */ 2377218Sphk 2477218Sphkimport java.util.*; 2577218Sphkimport java.nio.*; 2677218Sphkimport java.nio.charset.*; 2777218Sphkimport java.util.concurrent.*; 2877218Sphkimport java.util.regex.Pattern; 2977218Sphk 3077218Sphk/** 3177218Sphk * Usage: java StringCodingBenchmark 3277218Sphk * [-Diterations=N] [-Dsize=N] [-Dsubsize=N] [-Dmaxchar=N] 3377218Sphk * [-Dfilter=REGEXP] [-DSecurityManager=true] 3477218Sphk */ 3577218Sphkpublic class StrCodingBenchmark { 3677218Sphk abstract static class Job { 3777218Sphk private final String name; 3877218Sphk public Job(String name) { this.name = name; } 3977218Sphk public String name() { return name; } 4077218Sphk public abstract void work() throws Throwable; 4177218Sphk } 4277218Sphk 4377218Sphk private static void collectAllGarbage() { 4477218Sphk final java.util.concurrent.CountDownLatch drained 4577218Sphk = new java.util.concurrent.CountDownLatch(1); 4677218Sphk try { 4777218Sphk System.gc(); // enqueue finalizable objects 4877218Sphk new Object() { protected void finalize() { 4977218Sphk drained.countDown(); }}; 5077218Sphk System.gc(); // enqueue detector 5177218Sphk drained.await(); // wait for finalizer queue to drain 5277218Sphk System.gc(); // cleanup finalized objects 5377218Sphk } catch (InterruptedException e) { throw new Error(e); } 5477218Sphk } 5577218Sphk 5677218Sphk /** 5777218Sphk * Runs each job for long enough that all the runtime compilers 5877218Sphk * have had plenty of time to warm up, i.e. get around to 5977218Sphk * compiling everything worth compiling. 6077218Sphk * Returns array of average times per job per run. 6177218Sphk */ 6277218Sphk public static long[] time0(Job ... jobs) throws Throwable { 6377218Sphk //final long warmupNanos = 10L * 1000L * 1000L * 1000L; 6477218Sphk final long warmupNanos = 100L * 100L; 6577218Sphk long[] nanoss = new long[jobs.length]; 6677218Sphk for (int i = 0; i < jobs.length; i++) { 6777218Sphk collectAllGarbage(); 6877218Sphk long t0 = System.nanoTime(); 6977218Sphk long t; 7077218Sphk int j = 0; 7177218Sphk do { jobs[i].work(); j++; } 7277218Sphk while ((t = System.nanoTime() - t0) < warmupNanos); 7377218Sphk nanoss[i] = t/j; 7477218Sphk } 7577218Sphk return nanoss; 7677218Sphk } 7777218Sphk 78116957Ssam public static void time(Job ... jobs) throws Throwable { 79116957Ssam 8077218Sphk long[] warmup = time0(jobs); // Warm up run 8177218Sphk long[] nanoss = time0(jobs); // Real timing run 8277218Sphk long[] milliss = new long[jobs.length]; 8377218Sphk double[] ratios = new double[jobs.length]; 8477218Sphk 8577218Sphk final String nameHeader = "Method"; 8677218Sphk final String millisHeader = "Millis"; 8777218Sphk final String ratioHeader = "Ratio"; 8877218Sphk 8977218Sphk int nameWidth = nameHeader.length(); 9077218Sphk int millisWidth = millisHeader.length(); 9177218Sphk int ratioWidth = ratioHeader.length(); 9277218Sphk 9377218Sphk for (int i = 0; i < jobs.length; i++) { 9477218Sphk nameWidth = Math.max(nameWidth, jobs[i].name().length()); 9577218Sphk 9677218Sphk milliss[i] = nanoss[i]/(1000L * 1000L); 9777218Sphk millisWidth = Math.max(millisWidth, 9877218Sphk String.format("%d", milliss[i]).length()); 9977218Sphk 10077218Sphk ratios[i] = (double) nanoss[i] / (double) nanoss[0]; 10177218Sphk ratioWidth = Math.max(ratioWidth, 10277218Sphk String.format("%.3f", ratios[i]).length()); 10377218Sphk } 10477218Sphk String format = String.format("%%-%ds %%%dd %n", 10588748Sambrisko nameWidth, millisWidth); 10688748Sambrisko String headerFormat = String.format("%%-%ds %%%ds%n", 10788748Sambrisko nameWidth, millisWidth); 10888748Sambrisko System.out.printf(headerFormat, "Method", "Millis"); 10988748Sambrisko 11077218Sphk // Print out absolute and relative times, calibrated against first job 11177218Sphk for (int i = 0; i < jobs.length; i++) 11277218Sphk System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]); 11377218Sphk } 11477218Sphk 11577218Sphk public static Job[] filter(Pattern filter, Job[] jobs) { 11677218Sphk if (filter == null) return jobs; 11777218Sphk Job[] newJobs = new Job[jobs.length]; 11877218Sphk int n = 0; 11977218Sphk for (Job job : jobs) 12077218Sphk if (filter.matcher(job.name()).find()) 12177218Sphk newJobs[n++] = job; 12277218Sphk // Arrays.copyOf not available in JDK 5 12377218Sphk Job[] ret = new Job[n]; 12477218Sphk System.arraycopy(newJobs, 0, ret, 0, n); 12577218Sphk return ret; 12677218Sphk } 12777218Sphk 12877218Sphk static class PermissiveSecurityManger extends SecurityManager { 12977218Sphk @Override public void checkPermission(java.security.Permission p) { 13077218Sphk } 13177218Sphk } 13277218Sphk 13377218Sphk public static void main(String[] args) throws Throwable { 134116957Ssam final int itrs = Integer.getInteger("iterations", 100000); 135116957Ssam final int size = Integer.getInteger("size", 2048); 136116957Ssam final int subsize = Integer.getInteger("subsize", 128); 137116957Ssam final int maxchar = Integer.getInteger("maxchar", 128); 13877218Sphk final String regex = System.getProperty("filter"); 13977218Sphk final Pattern filter = (regex == null) ? null : Pattern.compile(regex); 14077218Sphk final boolean useSecurityManager = Boolean.getBoolean("SecurityManager"); 14177218Sphk if (useSecurityManager) 14277218Sphk System.setSecurityManager(new PermissiveSecurityManger()); 14377218Sphk final Random rnd = new Random(); 14477218Sphk 14591454Sbrooks for (Charset charset: Charset.availableCharsets().values()) { 14677218Sphk if (!("ISO-8859-1".equals(charset.name()) || 14791454Sbrooks "US-ASCII".equals(charset.name()) || 14877218Sphk charset.newDecoder() instanceof sun.nio.cs.SingleByte.Decoder)) 14991454Sbrooks continue; 15077218Sphk final String csn = charset.name(); 15177218Sphk final Charset cs = charset; 15277218Sphk final StringBuilder sb = new StringBuilder(); 15377218Sphk { 15477218Sphk final CharsetEncoder enc = cs.newEncoder(); 15577218Sphk for (int i = 0; i < size; ) { 15677218Sphk char c = (char) rnd.nextInt(maxchar); 15777218Sphk if (enc.canEncode(c)) { 15877218Sphk sb.append(c); 15977218Sphk i++; 16077218Sphk } 16177218Sphk } 16277218Sphk } 16391454Sbrooks final String string = sb.toString(); 16477218Sphk final byte[] bytes = string.getBytes(cs); 16591454Sbrooks 16677218Sphk System.out.printf("%n--------%s---------%n", csn); 16791454Sbrooks for (int sz = 4; sz <= 2048; sz *= 2) { 16877218Sphk System.out.printf(" [len=%d]%n", sz); 16991454Sbrooks final byte[] bs = Arrays.copyOf(bytes, sz); 17077218Sphk final String str = new String(bs, csn); 17191454Sbrooks Job[] jobs = { 17277218Sphk new Job("String decode: csn") { 17377218Sphk public void work() throws Throwable { 17477218Sphk for (int i = 0; i < itrs; i++) 17577218Sphk new String(bs, csn); 17677218Sphk }}, 17777218Sphk 17877218Sphk new Job("String decode: cs") { 17977218Sphk public void work() throws Throwable { 18077218Sphk for (int i = 0; i < itrs; i++) 18177218Sphk new String(bs, cs); 18277218Sphk }}, 18377218Sphk 18477218Sphk new Job("String encode: csn") { 18577218Sphk public void work() throws Throwable { 18677218Sphk for (int i = 0; i < itrs; i++) 18777218Sphk str.getBytes(csn); 18877218Sphk }}, 18977218Sphk 19077218Sphk new Job("String encode: cs") { 19177218Sphk public void work() throws Throwable { 19277218Sphk for (int i = 0; i < itrs; i++) 19377218Sphk str.getBytes(cs); 19477218Sphk }}, 19577218Sphk }; 19677218Sphk time(filter(filter, jobs)); 19777218Sphk } 19877218Sphk } 19977218Sphk } 20077218Sphk} 20177218Sphk