diff --git a/src/test/java/com/github/rjeschke/txtmark/Benchmark.java b/src/test/java/com/github/rjeschke/txtmark/Benchmark.java new file mode 100644 index 0000000..ff745b0 --- /dev/null +++ b/src/test/java/com/github/rjeschke/txtmark/Benchmark.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2011-2015 René Jeschke + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.rjeschke.txtmark; + +import java.util.Random; + +import org.junit.Test; + +public class Benchmark +{ + // random seed to use for text generation, >= 0 sets seed, < 0 uses random + private static final long SEED = 0; + // number of runs + private static final int RUNS = 8; + // perform an additional (hidden) warm-up run + private static final boolean WARMUP_RUN = true; + private static final int MIN_WORD_LENGTH = 3; + private static final int MAX_WORD_LENGTH = 10; + private static final int MAX_LINE_LENGTH = 80; + private static final int LINES_PER_PARAGRAPH = 20; + // number of paragraphs to create + private static final int NUM_PARAGRAPHS = 30; + + // scratch area + private static int REF_COUNTER = 0; + + private static String createWord(final Random rnd, final int minLength, final int maxLength) + { + final int len = rnd.nextInt(maxLength - minLength) + minLength; + final char[] ret = new char[len]; + for (int i = 0; i < len; i++) + { + ret[i] = (char)('a' + rnd.nextInt(26)); + } + return new String(ret); + } + + private interface WLDecorator + { + public String decorate(String word); + } + + private interface ParagraphDecorator + { + public void startParagraph(StringBuilder out); + + public void endParagraph(StringBuilder out); + } + + private final static String createText( + final WLDecorator wordDecorator, + final WLDecorator lineDecorator, + final ParagraphDecorator paragraphDecorator) + { + final Random rnd = new Random(); + if (SEED >= 0) + { + rnd.setSeed(SEED); + } + + final StringBuilder sb = new StringBuilder(); + final StringBuilder line = new StringBuilder(); + + boolean initParagraph = true; + + for (int lineLength = 0, lineCount = 0, paraCount = 0; paraCount < NUM_PARAGRAPHS;) + { + if (initParagraph) + { + if (paragraphDecorator != null) + { + paragraphDecorator.startParagraph(sb); + } + initParagraph = false; + } + + final String word = createWord(rnd, MIN_WORD_LENGTH, MAX_WORD_LENGTH); + final String decorated = wordDecorator != null ? wordDecorator.decorate(word) : word; + + lineLength += word.length(); + line.append(decorated); + + if (lineLength < MAX_LINE_LENGTH) + { + lineLength++; + line.append(' '); + } + else + { + if (lineDecorator != null) + { + sb.append(lineDecorator.decorate(line.toString())); + } + else + { + sb.append(line); + } + sb.append('\n'); + lineCount++; + lineLength = 0; + line.setLength(0); + + if (lineCount >= LINES_PER_PARAGRAPH) + { + lineCount = 0; + sb.append('\n'); + paraCount++; + if (paragraphDecorator != null) + { + paragraphDecorator.endParagraph(sb); + } + initParagraph = true; + } + } + } + + return sb.toString(); + } + + private final static WLDecorator EMPHASIS = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "*" + word + "*"; + } + }; + + private final static WLDecorator STRONG = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "**" + word + "**"; + } + }; + + private final static WLDecorator EMPHASIS_STRONG = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "***" + word + "***"; + } + }; + + private final static WLDecorator INLINE_CODE = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "`" + word + "`"; + } + }; + + private final static WLDecorator LINKS = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "[" + word + "](http://www.example.com/" + word + ")"; + } + }; + + private final static WLDecorator REF_LINKS = new WLDecorator() + { + @Override + public String decorate(final String word) + { + final int id = REF_COUNTER++; + return "[" + word + "][id" + id + "]"; + } + }; + + private final static ParagraphDecorator REF_LINKS_PARA = new ParagraphDecorator() + { + private int startId = 0; + + @Override + public void startParagraph(final StringBuilder out) + { + this.startId = REF_COUNTER; + } + + @Override + public void endParagraph(final StringBuilder out) + { + for (int i = this.startId; i < REF_COUNTER; i++) + { + out.append("[id"); + out.append(i); + out.append("]: http://www.example.com/"); + out.append(i); + out.append('\n'); + } + } + }; + + private final static WLDecorator HTML_WRAP = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "" + word + ""; + } + }; + + private final static WLDecorator MANUAL_LINE_BREAKS = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return word + " "; + } + }; + + private final static WLDecorator CODE_LINES = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return " " + word; + } + }; + + private final static WLDecorator BLOCK_QUOTE = new WLDecorator() + { + @Override + public String decorate(final String word) + { + return "> " + word; + } + }; + + private static class Settings + { + private final WLDecorator wordDecorator; + private final WLDecorator lineDecorator; + private final ParagraphDecorator paragraphDecorator; + private final String name; + + private Settings(final String name) + { + this(name, null, null, null); + } + + private Settings(final String name, final WLDecorator wordDecorator) + { + this(name, wordDecorator, null, null); + } + + private Settings(final String name, final WLDecorator wordDecorator, final WLDecorator lineDecorator) + { + this(name, wordDecorator, lineDecorator, null); + } + + private Settings(final String name, final WLDecorator wordDecorator, final WLDecorator lineDecorator, + final ParagraphDecorator paragraphDecorator) + { + this.name = name; + this.wordDecorator = wordDecorator; + this.lineDecorator = lineDecorator; + this.paragraphDecorator = paragraphDecorator; + } + } + + private final static Settings[] SETTINGS = + { + new Settings("default"), + new Settings("manual linebreaks", null, MANUAL_LINE_BREAKS), + new Settings("emphasis", EMPHASIS), + new Settings("strong", STRONG), + new Settings("emphasis+strong", EMPHASIS_STRONG), + new Settings("inline code", INLINE_CODE), + new Settings("full links", LINKS), + new Settings(" wrap", HTML_WRAP), + new Settings("code blocks", null, CODE_LINES), + new Settings("blockquote", null, BLOCK_QUOTE), + new Settings("ref links", REF_LINKS, null, REF_LINKS_PARA), + }; + + private static long timedProcess(final String text) + { + final long t0 = System.nanoTime(); + Processor.process(text); + final long t1 = System.nanoTime(); + return t1 - t0; + } + + private static void runTest(final Settings settings, final int runs) + { + final String testText = createText(settings.wordDecorator, settings.lineDecorator, settings.paragraphDecorator); + + if (WARMUP_RUN) + { + System.gc(); + timedProcess(testText); + } + + final long[] times = new long[runs]; + for (int i = 0; i < runs; i++) + { + System.gc(); + times[i] = timedProcess(testText); + } + + System.out.printf("%20s |", settings.name); + long sum = 0; + for (int i = 0; i < runs; i++) + { + System.out.printf(" %8d |", times[i] / 1000); + sum += times[i]; + } + System.out.printf(" %8d |", sum / (runs * 1000)); + System.out.println(); + } + + @Test + public void benchmark() + { + System.out.printf("%20s |", "Performance test"); + for (int i = 0; i < RUNS; i++) + { + System.out.printf(" %8s |", "run #" + (i + 1)); + } + System.out.printf(" %8s |", "average"); + System.out.println(); + + System.out.print("---------------------|"); + for (int i = 0; i < RUNS + 1; i++) + { + System.out.print("----------|"); + } + System.out.println(); + + for (final Settings s : SETTINGS) + { + runTest(s, RUNS); + } + + System.out.print("---------------------|"); + for (int i = 0; i < RUNS + 1; i++) + { + System.out.print("----------|"); + } + System.out.println(); + System.out.println("All times are given in milliseconds"); + } +}