Wednesday, December 12, 2012

Another micro benchmark - Formatting


Which one of these formats is faster?  The answer surprised me. 

package examples;

import java.text.MessageFormat;

import com.google.caliper.Param;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;

/**
 * Tests the performance of various StringBuilder methods.
 */
public class StringFormatBenchmark extends SimpleBenchmark {

    @Param({"1", "2", "3", "4", "5"}) private int inserts;
    public String [] s = new String [5];

    public void timeStringFormat(final int reps) {
        for (int i = 0; i < reps; ++i) {
            s[0] = String.format("asdf %s", i);
            if (inserts > 1) {
                s[1] = String.format("asdf %s asdf %s ", i, s[0]);
            }
            if (inserts > 2) {
                s[2] = String.format("asdf %s asdf %s asdf %s ", i, s[0], s[1]);
            }
            if (inserts > 3) {
                s[3] = String.format("asdf %s asdf %s asdf %s asdf %s ", i, s[0], s[1], s[2]);
            }
            if (inserts > 4) {
                s[4] = String.format("asdf %s asdf %s asdf %s asdf %s asdf %s ", i, s[0], s[1], s[2], s[3]);
            }
        }
    }

    public void timeMessageFormat(final int reps) {
        for (int i = 0; i < reps; ++i) {
            s[0] = MessageFormat.format("asdf {0}", i);
            if (inserts > 1) {
                s[1] = MessageFormat.format("asdf {0} asdf {1} ", i, s[0]);
            }
            if (inserts > 2) {
                s[2] = MessageFormat.format("asdf {0} asdf {1} asdf {2} ", i, s[0], s[1]);
            }
            if (inserts > 3) {
                s[3] = MessageFormat.format("asdf {0} asdf {1} asdf {2} asdf {3} ", i, s[0], s[1], s[2]);
            }
            if (inserts > 4) {
                s[3] = MessageFormat.format("asdf {0} asdf {1} asdf {2} asdf {3} asdf {4} ", i, s[0], s[1], s[2], s[3]);
            }
        }
    }

    public void timeStringBuilder(final int reps) {
        for (int i = 0; i < reps; ++i) {
            s[0] = new StringBuilder("asdf ").append(i).toString();
            if (inserts > 1) {
                s[1] = new StringBuilder("asdf ").append(i).append(" asdf ").append(s[0]).toString();
            }
            if (inserts > 2) {
                s[2] = new StringBuilder("asdf ").append(i).append(" asdf ").append(s[0]).append(" asdf ").append(s[1]).toString();
            }
            if (inserts > 3) {
                s[3] = new StringBuilder("asdf ").append(i).append(" asdf ").append(s[0]).append(" asdf ").append(s[1]).append(" asdf ").append(s[2]).toString();
            }
            if (inserts > 4) {
                s[4] = new StringBuilder("asdf ").append(i).append(" asdf ").append(s[0]).append(" asdf ").append(s[1]).append(" asdf ").append(s[2]).append(" asdf ").append(s[3]).toString();
            }
        }
    }

    public void timeStringConcat(final int reps) {
        for (int i = 0; i < reps; ++i) {
            s[0] = "asdf " + i;
            if (inserts > 1) {
                s[1] = "asdf " + i + " asdf " + (s[0]);
            }
            if (inserts > 2) {
                s[2] = "asdf " + i + " asdf " + (s[0]) + " asdf " + (s[1]);
            }
            if (inserts > 3) {
                s[3] = "asdf " + i + " asdf " + (s[0]) + " asdf " + (s[1]) + " asdf " + (s[2]);
            }
            if (inserts > 4) {
                s[4] = "asdf " + i + " asdf " + (s[0]) + " asdf " + (s[1]) + " asdf " + (s[2]) + " asdf " + (s[3]);
            }
        }
    }

    public static void main(final String[] args) throws Exception {
        Runner.main(StringFormatBenchmark.class, args);
    }
}

Caliper shows:  

    benchmark inserts    ns linear runtime
 StringFormat       1  2665 ==
 StringFormat       2  6686 ======
 StringFormat       3 12506 ============
 StringFormat       4 19548 ==================
 StringFormat       5 28582 ===========================
MessageFormat       1  4765 ====
MessageFormat       2  9845 =========
MessageFormat       3 15853 ===============
MessageFormat       4 23116 ======================
MessageFormat       5 31258 ==============================
StringBuilder       1   156 =
StringBuilder       2   427 =
StringBuilder       3   889 =
StringBuilder       4  1799 =
StringBuilder       5  2940 ==
 StringConcat       1   153 =
 StringConcat       2   425 =
 StringConcat       3   914 =
 StringConcat       4  1725 =
 StringConcat       5  2969 ==

Surprised?