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