jte: JTE is slower than regular String.replace approach

Hello, first of all, thanks for the great library.

I made a simple benchmark in order to test JTE performance and seems JTE is much slower than regular String.replace() at least for simple use cases.

Benchmark:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Fork(1)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
public class JTETest {

    String primaryColor = "#ffffff";
    String templateTxt;
    CodeResolver codeResolver = new DirectoryCodeResolver(Path.of("xxx/templates"));
    TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Plain);


    @Setup
    public void setup() {
        templateTxt = "<!DOCTYPE html>\n"
                + "<html>\n"
                + "<head>\n"
                + "${primaryColor}\n"
                + "</head>\n"
                + "</html>";

    }

    @Benchmark
    public String concat() {
        return "<!DOCTYPE html>\n"
                + "<html>\n"
                + "<head>\n"
                + primaryColor
                + "\n"
                + "</head>\n"
                + "</html>";
    }

    @Benchmark
    public String replace() {
        return templateTxt.replace("${primaryColor}", primaryColor);
    }

    @Benchmark
    public String templateEngine() {
        TemplateOutput output = new StringOutput();
        templateEngine.render("replace_test.jte", primaryColor, output);
        return output.toString();
    }

}

replace_test.jte:

@param String primaryColor

<!DOCTYPE html>
<html>
<head>
${primaryColor}
</head>
</html>

Result:

Benchmark               Mode  Cnt     Score     Error  Units
JTETest.concat          avgt    5    25.720 ±   2.108  ns/op
JTETest.replace         avgt    5    75.095 ±   8.815  ns/op
JTETest.templateEngine  avgt    5  2867.906 ± 183.810  ns/op

For the large template 1kb and many replacements, JTE is still slower ~30%. Is that expected?

In theory, if the template doesn’t have any control flow, it could be compiled to String concat pattern:

“<head>” + primaryColor + “</head>”, where OptimizeStringConcat kicks in. That should make it even faster than regular String.replace pattern. WDYT?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (8 by maintainers)

Commits related to this issue

Most upvoted comments

@doom369 will do that then! And I think it’s a good choice if simple String.replace is all that is needed to not add an additional dependency.

Thanks for posting the benchmark and all the insights on String performance 😃

@casid for Java 8 and below it was -XX:+OptimizeStringConcat. Since Java 9 it’s StringConcatFactory. Checkout this JEP - http://openjdk.java.net/jeps/280 it has a lot of interesting info.

I’m wondering if the JIT would be able to inline the virtual methods of the interface.

Inlining is possible, however, the resulting concatenation won’t be optimized, because it should be chaining calls pattern .append("tag").append(param) otherwise JIT doesn’t optimize it. In the case of StringOutput the result will be:

sb.append();
sb.append();

those code patterns are not optimized.