From 409b81e5a41e9e6bb806e5935050c78b2fc230cc Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Thu, 6 Dec 2018 19:21:29 -0200 Subject: [PATCH 01/24] update framework versions --- pom.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 74e3a7b..7fc22fa 100644 --- a/pom.xml +++ b/pom.xml @@ -11,17 +11,17 @@ UTF-8 - 1.7.1 + 1.21 benchmarks - 1.5.2 - 0.9.0 - 2.3.22 - 1.7 - 2.1.4.RELEASE + 3.0.6 + 0.9.5 + 2.3.28 + 2.0 + 3.0.11.RELEASE 4.11 - 1.8.1.Final - 0.9.0 + 2.5.0.Final + 1.2.0 @@ -120,7 +120,7 @@ - com.mitchellbosecke + io.pebbletemplates pebble ${pebble.version} @@ -136,7 +136,7 @@ org.apache.velocity - velocity + velocity-engine-core ${velocity.version} From 6462f5cba21d667e9767d3d12768834749bdebca Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Thu, 6 Dec 2018 19:24:40 -0200 Subject: [PATCH 02/24] Fix for velocity 2.0 --- src/main/resources/templates/stocks.velocity.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/templates/stocks.velocity.html b/src/main/resources/templates/stocks.velocity.html index c3217ce..ab02f8a 100755 --- a/src/main/resources/templates/stocks.velocity.html +++ b/src/main/resources/templates/stocks.velocity.html @@ -54,9 +54,9 @@

Stock Prices

#foreach($item in $items) - #if($velocityCount % 2 == 0) #set($klass = "even") #else #set($klass = "odd") #end + #if($foreach.count % 2 == 0) #set($klass = "even") #else #set($klass = "odd") #end - ${velocityCount} + ${foreach.count} ${item.symbol} From 195775cc263412207351799570be9aeb37a00d29 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Thu, 6 Dec 2018 19:26:08 -0200 Subject: [PATCH 03/24] Fix for Thymeleaf 3 --- src/main/resources/templates/stocks.thymeleaf.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/templates/stocks.thymeleaf.html b/src/main/resources/templates/stocks.thymeleaf.html index a1667f6..ebf45a9 100755 --- a/src/main/resources/templates/stocks.thymeleaf.html +++ b/src/main/resources/templates/stocks.thymeleaf.html @@ -55,7 +55,7 @@

Stock Prices

+ th:class="${itemStat.odd}? 'odd' : 'even'"> @@ -70,4 +70,4 @@

Stock Prices

- \ No newline at end of file + From f6dea9865edbc6296aad2c5384ee48b7326a4baf Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Thu, 6 Dec 2018 19:28:42 -0200 Subject: [PATCH 04/24] Fix code for Pebble 3 --- src/main/java/com/mitchellbosecke/benchmark/Pebble.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/mitchellbosecke/benchmark/Pebble.java b/src/main/java/com/mitchellbosecke/benchmark/Pebble.java index cdf5d3a..f19ad06 100644 --- a/src/main/java/com/mitchellbosecke/benchmark/Pebble.java +++ b/src/main/java/com/mitchellbosecke/benchmark/Pebble.java @@ -20,8 +20,7 @@ public class Pebble extends BaseBenchmark { @Setup public void setup() throws PebbleException { - PebbleEngine engine = new PebbleEngine(); - engine.getExtension(EscaperExtension.class).setAutoEscaping(false); + PebbleEngine engine = new PebbleEngine.Builder().extension(new EscaperExtension()).autoEscaping(false).build(); template = engine.getTemplate("templates/stocks.pebble.html"); this.context = getContext(); } From fbf3a5a0ddc29548eee19ceb68d87539493d23b0 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Fri, 7 Dec 2018 14:06:42 -0200 Subject: [PATCH 05/24] Azure Pipeline --- azure-pipelines.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..679bd7f --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,32 @@ +pool: + vmImage: 'Ubuntu 16.04' + +steps: +- task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + mavenOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.10' + jdkArchitectureOption: 'x64' + publishJUnitResults: true + testResultsFiles: '**/TEST-*.xml' + goals: 'package' + +# Publish Cobertura or JaCoCo code coverage results from a build +- task: PublishCodeCoverageResults@1 + inputs: + codeCoverageTool: 'JaCoCo' + summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/site/jacoco/jacoco.xml' + reportDirectory: '$(System.DefaultWorkingDirectory)/**/site/jacoco' + failIfCoverageEmpty: true + +- task: CopyFiles@2 + inputs: + contents: '**/*.jar' + targetFolder: '$(build.artifactStagingDirectory)' + +- task: PublishBuildArtifacts@1 + inputs: + artifactName: 'jar' + pathToPublish: '$(build.artifactStagingDirectory)' From 1f487cc94f426bf35128dd17f3a985f9dbd95296 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Sat, 8 Dec 2018 11:13:34 -0200 Subject: [PATCH 06/24] Create generate-results-with-version.py --- generate-results-with-version.py | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 generate-results-with-version.py diff --git a/generate-results-with-version.py b/generate-results-with-version.py new file mode 100644 index 0000000..230c0b9 --- /dev/null +++ b/generate-results-with-version.py @@ -0,0 +1,35 @@ +from tempfile import NamedTemporaryFile +import shutil +import csv +from xml.etree import ElementTree +import subprocess + + +with open('pom.xml', 'rt') as f: + groups = ElementTree.parse(f) + +root = groups.getroot() +tree = root.findall('.//') +tree = tree[6].findall('.//') +versions = {} +for node in tree: + key = node.tag[node.tag.index("}") + 1:] + versions[key] = node.text + +filename = 'results.csv' +tempfile = NamedTemporaryFile(mode='w', delete=False) + +fields = ['Benchmark', 'Mode', 'Threads', 'Samples', 'Score', 'Score Error (99.9%)', 'Unit'] + +with open(filename, 'r') as csvfile:#, tempfile: + reader = csv.DictReader(csvfile, fieldnames=fields, delimiter=',') + writer = csv.DictWriter(tempfile, fieldnames=fields) + for row in reader: + if row['Benchmark'] != 'Benchmark': + key = "%s.version" % (row['Benchmark'].lower()) + version = versions[key] + row['Benchmark'] = row['Benchmark'] + " " + version + writer.writerow(row) + +shutil.move(tempfile.name, filename) +exit() From 38529ba0edad58e96cd17c5728ca4b11351b1f1a Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Sat, 8 Dec 2018 11:14:32 -0200 Subject: [PATCH 07/24] Update azure-pipelines.yml --- azure-pipelines.yml | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 679bd7f..bebd4a5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,5 +1,5 @@ pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'Ubuntu-16.04' steps: - task: Maven@3 @@ -7,26 +7,35 @@ steps: mavenPomFile: 'pom.xml' mavenOptions: '-Xmx3072m' javaHomeOption: 'JDKVersion' - jdkVersionOption: '1.10' + jdkVersionOption: '1.8' jdkArchitectureOption: 'x64' publishJUnitResults: true - testResultsFiles: '**/TEST-*.xml' + testResultsFiles: '**/surefire-reports/TEST-*.xml' goals: 'package' -# Publish Cobertura or JaCoCo code coverage results from a build -- task: PublishCodeCoverageResults@1 - inputs: - codeCoverageTool: 'JaCoCo' - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/site/jacoco/jacoco.xml' - reportDirectory: '$(System.DefaultWorkingDirectory)/**/site/jacoco' - failIfCoverageEmpty: true - +- script: | + rm results.* + java -jar target/benchmarks.jar -rff results.csv -rf csv + cat results.csv + sed -i -E 's/com\.mitchellbosecke\.benchmark\.(\w+)\.benchmark/\1/g' results.csv + python generate-results-with-version.py + cat results.csv + displayName: 'Exec benchmarks' + +- script: sudo apt-get install -y gnuplot + displayName: 'Install gnuplot' + +- script: gnuplot benchmark.plot + displayName: 'Generate results.png' + - task: CopyFiles@2 inputs: - contents: '**/*.jar' + contents: | + **/*.jar + results.* targetFolder: '$(build.artifactStagingDirectory)' - task: PublishBuildArtifacts@1 inputs: - artifactName: 'jar' + artifactName: 'results' pathToPublish: '$(build.artifactStagingDirectory)' From aa99eeb412fb4ec5ebd32fc0e66f9365e672a471 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Sat, 8 Dec 2018 11:54:44 -0200 Subject: [PATCH 08/24] Update benchmark.plot --- benchmark.plot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark.plot b/benchmark.plot index b5e5243..340a653 100644 --- a/benchmark.plot +++ b/benchmark.plot @@ -26,5 +26,5 @@ set style line 2 lc rgb '#808080' lt 1 set border 3 back ls 2 set tics nomirror -plot 'results.csv' every ::1 using 0:5:xticlabels(stringcolumn(1)[31:36]) with boxes ls 1,\ +plot 'results.csv' every ::1 using 0:5:xticlabels(stringcolumn(1)) with boxes ls 1,\ 'results.csv' every ::1 using 0:($5 + 1500):(sprintf("%d",$5)) with labels From dde1277d53e86aeb662efd931490a0f0f2740436 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Sat, 8 Dec 2018 16:31:20 -0200 Subject: [PATCH 09/24] Update azure-pipelines.yml --- azure-pipelines.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bebd4a5..50ef0e8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,3 +1,5 @@ +timeoutInMinutes: 0 + pool: vmImage: 'Ubuntu-16.04' From c28f0305f518b8428de66d2b4d2a93fdc2d1c89a Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Sat, 8 Dec 2018 16:33:12 -0200 Subject: [PATCH 10/24] Update azure-pipelines.yml --- azure-pipelines.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 50ef0e8..104051c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,5 +1,3 @@ -timeoutInMinutes: 0 - pool: vmImage: 'Ubuntu-16.04' @@ -23,6 +21,7 @@ steps: python generate-results-with-version.py cat results.csv displayName: 'Exec benchmarks' + timeoutInMinutes: 0 - script: sudo apt-get install -y gnuplot displayName: 'Install gnuplot' From 571debed489cc72a96ea81e6f5e3681fe653fd45 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Sat, 8 Dec 2018 17:04:42 -0200 Subject: [PATCH 11/24] Update azure-pipelines.yml --- azure-pipelines.yml | 81 +++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 104051c..292a9c9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,42 +1,45 @@ -pool: - vmImage: 'Ubuntu-16.04' - -steps: -- task: Maven@3 - inputs: - mavenPomFile: 'pom.xml' - mavenOptions: '-Xmx3072m' - javaHomeOption: 'JDKVersion' - jdkVersionOption: '1.8' - jdkArchitectureOption: 'x64' - publishJUnitResults: true - testResultsFiles: '**/surefire-reports/TEST-*.xml' - goals: 'package' - -- script: | - rm results.* - java -jar target/benchmarks.jar -rff results.csv -rf csv - cat results.csv - sed -i -E 's/com\.mitchellbosecke\.benchmark\.(\w+)\.benchmark/\1/g' results.csv - python generate-results-with-version.py - cat results.csv - displayName: 'Exec benchmarks' +jobs: +- job: Linux timeoutInMinutes: 0 + pool: + vmImage: 'Ubuntu-16.04' + + steps: + - task: Maven@3 + inputs: + mavenPomFile: 'pom.xml' + mavenOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + publishJUnitResults: true + testResultsFiles: '**/surefire-reports/TEST-*.xml' + goals: 'package' -- script: sudo apt-get install -y gnuplot - displayName: 'Install gnuplot' - -- script: gnuplot benchmark.plot - displayName: 'Generate results.png' + - script: | + rm results.* + java -jar target/benchmarks.jar -rff results.csv -rf csv + cat results.csv + sed -i -E 's/com\.mitchellbosecke\.benchmark\.(\w+)\.benchmark/\1/g' results.csv + python generate-results-with-version.py + cat results.csv + displayName: 'Exec benchmarks' + + + - script: sudo apt-get install -y gnuplot + displayName: 'Install gnuplot' + + - script: gnuplot benchmark.plot + displayName: 'Generate results.png' + + - task: CopyFiles@2 + inputs: + contents: | + **/*.jar + results.* + targetFolder: '$(build.artifactStagingDirectory)' -- task: CopyFiles@2 - inputs: - contents: | - **/*.jar - results.* - targetFolder: '$(build.artifactStagingDirectory)' - -- task: PublishBuildArtifacts@1 - inputs: - artifactName: 'results' - pathToPublish: '$(build.artifactStagingDirectory)' + - task: PublishBuildArtifacts@1 + inputs: + artifactName: 'results' + pathToPublish: '$(build.artifactStagingDirectory)' From 009749d19dd065cd3da142a7770674ade3252bb2 Mon Sep 17 00:00:00 2001 From: Daniel Menezes Date: Sun, 9 Dec 2018 00:28:14 -0200 Subject: [PATCH 12/24] Update mustache version --- .gitignore | 1 + pom.xml | 6 ++-- .../mitchellbosecke/benchmark/Mustache.java | 35 ++++++++----------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index a90279a..70360f1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ target/ *.war *.ear .project +.idea/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7fc22fa..011b631 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ benchmarks 3.0.6 - 0.9.5 + 1.14 2.3.28 2.0 3.0.11.RELEASE @@ -125,8 +125,8 @@ ${pebble.version}
- com.github.spullara.mustache.java - compiler + com.samskivert + jmustache ${mustache.version} diff --git a/src/main/java/com/mitchellbosecke/benchmark/Mustache.java b/src/main/java/com/mitchellbosecke/benchmark/Mustache.java index 69f8fe9..272a620 100644 --- a/src/main/java/com/mitchellbosecke/benchmark/Mustache.java +++ b/src/main/java/com/mitchellbosecke/benchmark/Mustache.java @@ -1,40 +1,33 @@ package com.mitchellbosecke.benchmark; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; +import java.io.*; import java.util.AbstractCollection; import java.util.Collection; import java.util.Iterator; import java.util.Map; +import com.samskivert.mustache.*; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Setup; -import com.github.mustachejava.DefaultMustacheFactory; -import com.github.mustachejava.MustacheException; -import com.github.mustachejava.MustacheFactory; import com.mitchellbosecke.benchmark.model.Stock; public class Mustache extends BaseBenchmark { - private com.github.mustachejava.Mustache template; + private Template template; @Setup public void setup() { - MustacheFactory mustacheFactory = new DefaultMustacheFactory() { - - @Override - public void encode(String value, Writer writer) { - // Disable HTML escaping - try { - writer.write(value); - } catch (IOException e) { - throw new MustacheException(e); - } - } - }; - template = mustacheFactory.compile("templates/stocks.mustache.html"); + InputStream is = this.getClass().getClassLoader() + .getResourceAsStream("templates/stocks.mustache.html"); + Reader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(is, "UTF8")); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); + } + + template = com.samskivert.mustache.Mustache.compiler().withEscaper(Escapers.NONE).compile(reader); } @SuppressWarnings("unchecked") @@ -45,7 +38,7 @@ public String benchmark() { data.put("items", new StockCollection((Collection) data.get("items"))); Writer writer = new StringWriter(); - template.execute(writer, data); + template.execute(data, writer); return writer.toString(); } From 2720cb96d4f806aa9a773a86441d0b3df037a5e7 Mon Sep 17 00:00:00 2001 From: Daniel Menezes Date: Sun, 9 Dec 2018 09:11:37 -0200 Subject: [PATCH 13/24] Update java version --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 011b631..01cfad9 100644 --- a/pom.xml +++ b/pom.xml @@ -46,8 +46,8 @@ maven-compiler-plugin 2.3.2 - 1.7 - 1.7 + 1.8 + 1.8 From b0f7db4547538cb6dbda94096bc97c9bd24b94e4 Mon Sep 17 00:00:00 2001 From: Daniel Menezes Date: Sun, 9 Dec 2018 09:40:59 -0200 Subject: [PATCH 14/24] Test two Mustache implementations (https://github.com/spullara/mustache.java and https://github.com/samskivert/jmustache (spring boot uses it)) --- pom.xml | 10 +- ...Mustache.java => Mustache_Samskivert.java} | 2 +- .../benchmark/Mustache_Spullara.java | 123 ++++++++++++++++++ .../benchmark/ExpectedOutputTest.java | 11 +- 4 files changed, 141 insertions(+), 5 deletions(-) rename src/main/java/com/mitchellbosecke/benchmark/{Mustache.java => Mustache_Samskivert.java} (98%) create mode 100644 src/main/java/com/mitchellbosecke/benchmark/Mustache_Spullara.java diff --git a/pom.xml b/pom.xml index 01cfad9..1309689 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,8 @@ benchmarks 3.0.6 - 1.14 + 1.14 + 0.9.5 2.3.28 2.0 3.0.11.RELEASE @@ -127,7 +128,12 @@ com.samskivert jmustache - ${mustache.version} + ${mustache_samskivert.version} + + + com.github.spullara.mustache.java + compiler + ${mustache_spullara.version} org.freemarker diff --git a/src/main/java/com/mitchellbosecke/benchmark/Mustache.java b/src/main/java/com/mitchellbosecke/benchmark/Mustache_Samskivert.java similarity index 98% rename from src/main/java/com/mitchellbosecke/benchmark/Mustache.java rename to src/main/java/com/mitchellbosecke/benchmark/Mustache_Samskivert.java index 272a620..2c210f2 100644 --- a/src/main/java/com/mitchellbosecke/benchmark/Mustache.java +++ b/src/main/java/com/mitchellbosecke/benchmark/Mustache_Samskivert.java @@ -12,7 +12,7 @@ import com.mitchellbosecke.benchmark.model.Stock; -public class Mustache extends BaseBenchmark { +public class Mustache_Samskivert extends BaseBenchmark { private Template template; diff --git a/src/main/java/com/mitchellbosecke/benchmark/Mustache_Spullara.java b/src/main/java/com/mitchellbosecke/benchmark/Mustache_Spullara.java new file mode 100644 index 0000000..d3e87d1 --- /dev/null +++ b/src/main/java/com/mitchellbosecke/benchmark/Mustache_Spullara.java @@ -0,0 +1,123 @@ +package com.mitchellbosecke.benchmark; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Setup; + +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.MustacheException; +import com.github.mustachejava.MustacheFactory; +import com.mitchellbosecke.benchmark.model.Stock; + +public class Mustache_Spullara extends BaseBenchmark { + + private com.github.mustachejava.Mustache template; + + @Setup + public void setup() { + MustacheFactory mustacheFactory = new DefaultMustacheFactory() { + + @Override + public void encode(String value, Writer writer) { + // Disable HTML escaping + try { + writer.write(value); + } catch (IOException e) { + throw new MustacheException(e); + } + } + }; + template = mustacheFactory.compile("templates/stocks.mustache.html"); + } + + @SuppressWarnings("unchecked") + @Benchmark + public String benchmark() { + + Map data = getContext(); + data.put("items", new StockCollection((Collection) data.get("items"))); + + Writer writer = new StringWriter(); + template.execute(writer, data); + return writer.toString(); + } + + /** + * This is a modified copy of + * {@link com.github.mustachejava.util.DecoratedCollection} - we need the + * first element at index 1. + * + * @param + */ + private class StockCollection extends AbstractCollection { + + private final Collection c; + + public StockCollection(Collection c) { + this.c = c; + } + + @Override + public Iterator iterator() { + final Iterator iterator = c.iterator(); + return new Iterator() { + + int index = 1; + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public StockView next() { + Stock next = iterator.next(); + int current = index++; + return new StockView(current, current == 1, !iterator.hasNext(), next); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public int size() { + return c.size(); + } + } + + class StockView { + + public final int index; + + public final boolean first; + + public final boolean last; + + public final Stock value; + + public final String negativeClass; + + public final String rowClass; + + public StockView(int index, boolean first, boolean last, Stock value) { + this.index = index; + this.first = first; + this.last = last; + this.value = value; + this.negativeClass = value.getChange() > 0 ? "" : "class=\"minus\""; + this.rowClass = index % 2 == 0 ? "even" : "odd"; + } + } + +} diff --git a/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java b/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java index 8320843..4a8f77d 100644 --- a/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java +++ b/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java @@ -54,8 +54,15 @@ public void testVelocityOutput() throws IOException { } @Test - public void testMustacheOutput() throws IOException { - Mustache mustache = new Mustache(); + public void testMustache_SamskivertOutput() throws IOException { + Mustache_Samskivert mustache = new Mustache_Samskivert(); + mustache.setup(); + assertOutput(mustache.benchmark()); + } + + @Test + public void testMustache_SpullaraOutput() throws IOException { + Mustache_Spullara mustache = new Mustache_Spullara(); mustache.setup(); assertOutput(mustache.benchmark()); } From 492853f220b1d7c2f2031b73b9ff9010395a0970 Mon Sep 17 00:00:00 2001 From: Daniel Menezes Date: Mon, 10 Dec 2018 17:35:52 -0200 Subject: [PATCH 15/24] Add Groovy BenchMark (MarkupTemplateEngine) --- pom.xml | 6 ++ .../com/mitchellbosecke/benchmark/Groovy.java | 58 ++++++++++++++ .../resources/templates/stocks.groovy.tpl | 79 +++++++++++++++++++ .../benchmark/ExpectedOutputTest.java | 7 ++ 4 files changed, 150 insertions(+) create mode 100644 src/main/java/com/mitchellbosecke/benchmark/Groovy.java create mode 100644 src/main/resources/templates/stocks.groovy.tpl diff --git a/pom.xml b/pom.xml index 1309689..90e7bbe 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ 4.11 2.5.0.Final 1.2.0 + 2.5.4 @@ -160,6 +161,11 @@ rocker-runtime ${rocker.version} + + org.codehaus.groovy + groovy-templates + ${groovy.version} + junit diff --git a/src/main/java/com/mitchellbosecke/benchmark/Groovy.java b/src/main/java/com/mitchellbosecke/benchmark/Groovy.java new file mode 100644 index 0000000..e7333aa --- /dev/null +++ b/src/main/java/com/mitchellbosecke/benchmark/Groovy.java @@ -0,0 +1,58 @@ +package com.mitchellbosecke.benchmark; + +import groovy.lang.Writable; +import groovy.text.Template; +import groovy.text.markup.MarkupTemplateEngine; +import groovy.text.markup.TemplateConfiguration; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Setup; + +import java.io.*; +import java.util.Map; + +public class Groovy extends BaseBenchmark { + + private Map context; + + private Template template; + + @Setup + public void setup() { + TemplateConfiguration config = new TemplateConfiguration(); + config.setAutoEscape(false); + config.setUseDoubleQuotes(true); + MarkupTemplateEngine engine = new MarkupTemplateEngine(config); + InputStream is = this.getClass().getClassLoader() + .getResourceAsStream("templates/stocks.groovy.tpl"); + Reader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(is, "UTF8")); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); + } + + try { + template = engine.createTemplate(reader); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } catch (IOException e) { + throw new IllegalStateException(e); + } + + + this.context = getContext(); + } + + @Benchmark + public String benchmark() { + Writer writer = new StringWriter(); + Writable output = template.make(context); + try { + output.writeTo(writer); + } catch (IOException e) { + throw new IllegalStateException(e); + } + return writer.toString(); + } + +} diff --git a/src/main/resources/templates/stocks.groovy.tpl b/src/main/resources/templates/stocks.groovy.tpl new file mode 100644 index 0000000..37ad134 --- /dev/null +++ b/src/main/resources/templates/stocks.groovy.tpl @@ -0,0 +1,79 @@ +yieldUnescaped '' +html { + head { + title('Stock Prices') + meta('http-equiv':"Content-Type", content:"text/html; charset=UTF-8") + meta('http-equiv':"Content-Style-Type", 'content':"text/css") + meta('http-equiv':"Content-Script-Type", 'content':"text/javascript") + link('rel':"shortcut icon", 'href':"/images/favicon.ico") + link('rel':"stylesheet", 'type':"text/css", 'href':"/css/style.css", 'media':"all") +yieldUnescaped ''' +''' + + } + body { + h1('Stock Prices') + + table { + thead { + tr { + th('#') + th('symbol') + th('name') + th('price') + th('change') + th('ratio') + } + } + tbody { + items.eachWithIndex {item, idx -> + + tr (class: idx % 2 ? 'even' : 'odd'){ + td(idx + 1) + td { + a(item.symbol, href: '/stocks/' + item.symbol) + } + td { + a(item.name, href: item.url) + } + td { + strong(item.price) + } + if (item.change < 0) { + td(item.change, class: 'minus') + td(item.ratio, class: 'minus') + } else { + td(item.change) + td(item.ratio) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java b/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java index 4a8f77d..5feb49e 100644 --- a/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java +++ b/src/test/java/com/mitchellbosecke/benchmark/ExpectedOutputTest.java @@ -81,6 +81,13 @@ public void testTrimouOutput() throws IOException { assertOutput(trimou.benchmark()); } + @Test + public void testGroovyOutput() throws IOException { + Groovy groovy = new Groovy(); + groovy.setup(); + assertOutput(groovy.benchmark()); + } + private void assertOutput(String output) throws IOException { assertEquals(readExpectedOutputResource(), output.replaceAll("\\s", "")); } From 684ac27fa63c173ff1d2050013fe81ed8b8c141d Mon Sep 17 00:00:00 2001 From: Daniel Menezes Date: Mon, 10 Dec 2018 17:59:51 -0200 Subject: [PATCH 16/24] Remove unnecessary yieldUnescaped --- .../resources/templates/stocks.groovy.tpl | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/main/resources/templates/stocks.groovy.tpl b/src/main/resources/templates/stocks.groovy.tpl index 37ad134..2484011 100644 --- a/src/main/resources/templates/stocks.groovy.tpl +++ b/src/main/resources/templates/stocks.groovy.tpl @@ -7,34 +7,31 @@ html { meta('http-equiv':"Content-Script-Type", 'content':"text/javascript") link('rel':"shortcut icon", 'href':"/images/favicon.ico") link('rel':"stylesheet", 'type':"text/css", 'href':"/css/style.css", 'media':"all") -yieldUnescaped ''' -''' - +/*]]>*/""") } body { h1('Stock Prices') @@ -50,9 +47,9 @@ thead { th('ratio') } } - tbody { - items.eachWithIndex {item, idx -> + tbody { + items.eachWithIndex {item, idx -> tr (class: idx % 2 ? 'even' : 'odd'){ td(idx + 1) td { @@ -72,8 +69,8 @@ thead { td(item.ratio) } } + } } - } } } } \ No newline at end of file From d0ba7b3f8a7b9c49996b3b7b637297fbdedfc08a Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Mon, 10 Dec 2018 19:25:59 -0200 Subject: [PATCH 17/24] Update azure-pipelines.yml --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 292a9c9..99d99f2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,6 +22,7 @@ jobs: cat results.csv sed -i -E 's/com\.mitchellbosecke\.benchmark\.(\w+)\.benchmark/\1/g' results.csv python generate-results-with-version.py + sed -i -E 's/Mustache_/Mustache /g' results.csv cat results.csv displayName: 'Exec benchmarks' From 91f15c52bbf367c9932e5d899ce8e0d7ada3f512 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Tue, 11 Dec 2018 14:01:32 -0200 Subject: [PATCH 18/24] jmh.version downgrade (1.7.1) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 90e7bbe..c17495b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ UTF-8 - 1.21 + 1.7.1 benchmarks 3.0.6 From fb0451e31faafc15d1ac3c9fe839af282afb64fb Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Tue, 11 Dec 2018 14:08:37 -0200 Subject: [PATCH 19/24] Update results --- results.csv | 18 ++++++++++-------- results.png | Bin 26100 -> 33678 bytes 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/results.csv b/results.csv index 99fd2d2..6568473 100644 --- a/results.csv +++ b/results.csv @@ -1,8 +1,10 @@ -"Benchmark","Mode","Threads","Samples","Score","Score Error (99.9%)","Unit" -"com.mitchellbosecke.benchmark.Freemarker.benchmark","thrpt",1,50.000000,16737.333340,184.040944,"ops/s" -"com.mitchellbosecke.benchmark.Mustache.benchmark","thrpt",1,50.000000,23393.115757,159.003408,"ops/s" -"com.mitchellbosecke.benchmark.Pebble.benchmark","thrpt",1,50.000000,35736.995844,248.860050,"ops/s" -"com.mitchellbosecke.benchmark.Rocker.benchmark","thrpt",1,50.000000,41123.645420,191.949947,"ops/s" -"com.mitchellbosecke.benchmark.Thymeleaf.benchmark","thrpt",1,50.000000,1519.092213,18.156292,"ops/s" -"com.mitchellbosecke.benchmark.Trimou.benchmark","thrpt",1,50.000000,19081.925071,112.440326,"ops/s" -"com.mitchellbosecke.benchmark.Velocity.benchmark","thrpt",1,50.000000,21553.362499,223.035824,"ops/s" +Benchmark,Mode,Threads,Samples,Score,Score Error (99.9%),Unit +Freemarker 2.3.28,thrpt,1,50,14375.008770,67.949534,ops/s +Groovy 2.5.4,thrpt,1,50,9916.720420,310.450084,ops/s +Mustache Samskivert 1.14,thrpt,1,50,9756.638916,201.174622,ops/s +Mustache Spullara 0.9.5,thrpt,1,50,16561.498801,51.512659,ops/s +Pebble 3.0.6,thrpt,1,50,19575.873030,372.340451,ops/s +Rocker 1.2.0,thrpt,1,50,29665.500272,326.030892,ops/s +Thymeleaf 3.0.11.RELEASE,thrpt,1,50,4547.712767,44.024793,ops/s +Trimou 2.5.0.Final,thrpt,1,50,16102.162324,207.259233,ops/s +Velocity 2.0,thrpt,1,50,16435.810422,124.612788,ops/s diff --git a/results.png b/results.png index c5b0329cc129039e12052718dc0c78a47e1250b6..e7a52c5d98efe1a3d574c099c54ba15953b9e42b 100644 GIT binary patch literal 33678 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 literal 26100 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 Date: Tue, 11 Dec 2018 14:13:46 -0200 Subject: [PATCH 20/24] Update java template engines --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9911e36..9b2ae32 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,13 @@ template-benchmark JMH benchmark for popular Java template engines: * [Freemarker](http://freemarker.org/) -* [Mustache](https://github.com/spullara/mustache.java) +* Mustache ([spullara](https://github.com/spullara/mustache.java) and [samskivert](https://github.com/samskivert/jmustachet) implementations) * [Pebble](http://www.mitchellbosecke.com/pebble) * [Rocker](https://github.com/fizzed/rocker) * [Thymeleaf](http://www.thymeleaf.org/) * [Trimou](http://trimou.org/) * [Velocity](http://velocity.apache.org/) +* [Groovy Template](http://groovy-lang.org/) Running the benchmark ====================== From 87b2e6a29c2f484f71a07851336b3f1f38013a8b Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Tue, 11 Dec 2018 14:22:16 -0200 Subject: [PATCH 21/24] jmh.version upgrade (1.21) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c17495b..90e7bbe 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ UTF-8 - 1.7.1 + 1.21 benchmarks 3.0.6 From 6a24de27d30b141674f0919b8454b930828494a5 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Tue, 11 Dec 2018 15:43:59 -0200 Subject: [PATCH 22/24] Show cpu info before beanchmark --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 99d99f2..de9c694 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,6 +17,7 @@ jobs: goals: 'package' - script: | + less /proc/cpuinfo; lscpu rm results.* java -jar target/benchmarks.jar -rff results.csv -rf csv cat results.csv From 75d3a17b845c9448b159291482145d01febd9c32 Mon Sep 17 00:00:00 2001 From: danielmenezesbr Date: Tue, 11 Dec 2018 15:52:42 -0200 Subject: [PATCH 23/24] Show hardware info (memory and cpu) --- azure-pipelines.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index de9c694..75c6b91 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,12 @@ jobs: publishJUnitResults: true testResultsFiles: '**/surefire-reports/TEST-*.xml' goals: 'package' - + + - script: | + cat /proc/cpuinfo; lscpu + cat /proc/meminfo; free -m + displayName: 'Show hardware info' + - script: | less /proc/cpuinfo; lscpu rm results.* From 4ce2e9eed4d35eb886498238d645cf95ab1741f5 Mon Sep 17 00:00:00 2001 From: Daniel Menezes Date: Wed, 12 Dec 2018 16:51:03 -0200 Subject: [PATCH 24/24] settings errorbars --- benchmark.plot | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/benchmark.plot b/benchmark.plot index 340a653..a1cef11 100644 --- a/benchmark.plot +++ b/benchmark.plot @@ -13,7 +13,7 @@ set datafile separator ',' # Output set terminal pngcairo enhanced font "Verdana,9" set output 'results.png' -set grid +set grid lw 0.5 set key off set boxwidth 0.8 relative @@ -27,4 +27,5 @@ set border 3 back ls 2 set tics nomirror plot 'results.csv' every ::1 using 0:5:xticlabels(stringcolumn(1)) with boxes ls 1,\ - 'results.csv' every ::1 using 0:($5 + 1500):(sprintf("%d",$5)) with labels + 'results.csv' every ::1 using 0:($5 + 1500):(sprintf("%d",$5)) with labels,\ + 'results.csv' every ::1 using 0:5:6 with yerrorbars linestyle -1 lc rgb 'black' lw 1