-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[core] optimize template rendering (#1479)
- Loading branch information
1 parent
16b969d
commit a9fb04b
Showing
9 changed files
with
570 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
## How to run | ||
Build | ||
``` | ||
./mvnw clean install -DskipTests | ||
./mvnw clean verify -pl 'thirdeye-benchmarks' | ||
``` | ||
|
||
Run benchmark | ||
``` | ||
java -jar thirdeye-benchmarks/target/benchmarks.jar | ||
# or with a regex filter on ClassName.methodName | ||
java -jar thirdeye-benchmarks/target/benchmarks.jar applyContext | ||
``` | ||
|
||
## Speed-Optimizations | ||
### 1 - StringTemplateUtils - Template properties | ||
Problem: StringTemplateUtils#applyContext - the method to apply properties to template - was extremely slow. | ||
An ObjectMapper was instantiated at each call, so the ser/deserializer obtained by reflection (slow) were re-computed each time. | ||
Optimization: re-use the ObjectMapper. It's a bit tricky because we use custom ser/deser to inject values. Values change at each call. | ||
So we mutate the custom ser/deserializer of the re-used ObjectMapper at each call. This is not thread safe so we introduce a pool of re-usable ObjectMappers. | ||
|
||
Before: | ||
``` | ||
Benchmark Mode Cnt Score Error Units | ||
StringTemplateUtilsBenchmark.applyContext avgt 7 1480.610 ± 56.571 us/op | ||
``` | ||
|
||
``` | ||
Benchmark Mode Cnt Score Error Units | ||
StringTemplateUtilsBenchmark.applyContext avgt 7 55.539 ± 0.272 us/op | ||
``` | ||
|
||
For an alert with 1000 enumeration items: | ||
- before: applying properties takes ~ 1000 *1480us ~= 1.5 seconds --> slow in the UI | ||
- after: applying properties takes ~ 1000 *55us ~= 50 milliseconds | ||
|
||
Please make sure this does not get slower. | ||
I think there is still a 10x speed improvement opportunity here but this should be fast enough for the moment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
Copyright 2024 StarTree Inc | ||
Licensed under the StarTree Community License (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.startree.ai/legal/startree-community-license | ||
Unless required by applicable law or agreed to in writing, software distributed under the | ||
License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OF ANY KIND, | ||
either express or implied. | ||
See the License for the specific language governing permissions and limitations under | ||
the License. | ||
--> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>ai.startree.thirdeye</groupId> | ||
<artifactId>thirdeye</artifactId> | ||
<version>1.303.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>thirdeye-benchmarks</artifactId> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<jmh.version>1.37</jmh.version> | ||
<javac.target>17</javac.target> | ||
<uberjar.name>benchmarks</uberjar.name> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>ai.startree.thirdeye</groupId> | ||
<artifactId>thirdeye-spi</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>ai.startree.thirdeye</groupId> | ||
<artifactId>thirdeye-core</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.openjdk.jmh</groupId> | ||
<artifactId>jmh-core</artifactId> | ||
<version>${jmh.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.openjdk.jmh</groupId> | ||
<artifactId>jmh-generator-annprocess</artifactId> | ||
<version>${jmh.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.8.0</version> | ||
<configuration> | ||
<compilerVersion>${javac.target}</compilerVersion> | ||
<source>${javac.target}</source> | ||
<target>${javac.target}</target> | ||
<annotationProcessorPaths> | ||
<path> | ||
<groupId>org.openjdk.jmh</groupId> | ||
<artifactId>jmh-generator-annprocess</artifactId> | ||
<version>1.37</version> | ||
</path> | ||
</annotationProcessorPaths> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-shade-plugin</artifactId> | ||
<version>3.2.1</version> | ||
<executions> | ||
<execution> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>shade</goal> | ||
</goals> | ||
<configuration> | ||
<finalName>${uberjar.name}</finalName> | ||
<transformers> | ||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | ||
<mainClass>org.openjdk.jmh.Main</mainClass> | ||
</transformer> | ||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> | ||
</transformers> | ||
<filters> | ||
<filter> | ||
<!-- | ||
Shading signed JARs will fail without this. | ||
http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar | ||
--> | ||
<artifact>*:*</artifact> | ||
<excludes> | ||
<exclude>META-INF/*.SF</exclude> | ||
<exclude>META-INF/*.DSA</exclude> | ||
<exclude>META-INF/*.RSA</exclude> | ||
</excludes> | ||
</filter> | ||
</filters> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
<pluginManagement> | ||
<plugins> | ||
<plugin> | ||
<artifactId>maven-clean-plugin</artifactId> | ||
<version>2.5</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-deploy-plugin</artifactId> | ||
<version>2.8.1</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-install-plugin</artifactId> | ||
<version>2.5.1</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-jar-plugin</artifactId> | ||
<version>2.4</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-javadoc-plugin</artifactId> | ||
<version>2.9.1</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-resources-plugin</artifactId> | ||
<version>2.6</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-site-plugin</artifactId> | ||
<version>3.3</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-source-plugin</artifactId> | ||
<version>2.2.1</version> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<version>2.17</version> | ||
</plugin> | ||
</plugins> | ||
</pluginManagement> | ||
</build> | ||
|
||
</project> |
82 changes: 82 additions & 0 deletions
82
thirdeye-benchmarks/src/main/java/org/sample/StringTemplateUtilsBenchmark.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/* | ||
* Copyright 2024 StarTree Inc | ||
* | ||
* Licensed under the StarTree Community License (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.startree.ai/legal/startree-community-license | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the | ||
* License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OF ANY KIND, | ||
* either express or implied. | ||
* See the License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package org.sample; | ||
|
||
import ai.startree.thirdeye.spi.Constants; | ||
import ai.startree.thirdeye.spi.datalayer.dto.AlertTemplateDTO; | ||
import ai.startree.thirdeye.util.StringTemplateUtils; | ||
import com.google.common.collect.ImmutableMap; | ||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.TimeUnit; | ||
import org.apache.commons.io.IOUtils; | ||
import org.openjdk.jmh.annotations.Benchmark; | ||
import org.openjdk.jmh.annotations.BenchmarkMode; | ||
import org.openjdk.jmh.annotations.Fork; | ||
import org.openjdk.jmh.annotations.Measurement; | ||
import org.openjdk.jmh.annotations.Mode; | ||
import org.openjdk.jmh.annotations.OutputTimeUnit; | ||
import org.openjdk.jmh.annotations.Scope; | ||
import org.openjdk.jmh.annotations.Setup; | ||
import org.openjdk.jmh.annotations.State; | ||
import org.openjdk.jmh.annotations.Threads; | ||
import org.openjdk.jmh.annotations.Warmup; | ||
import org.openjdk.jmh.infra.Blackhole; | ||
|
||
@Fork(value = 1, jvmArgsPrepend = "-Xmx128m") | ||
@Measurement(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS) | ||
@Warmup(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS) | ||
@State(Scope.Thread) | ||
@Threads(1) | ||
@BenchmarkMode(Mode.AverageTime) | ||
@OutputTimeUnit(TimeUnit.MICROSECONDS) | ||
public class StringTemplateUtilsBenchmark { | ||
|
||
AlertTemplateDTO template; | ||
Map<String, Object> valuesMap; | ||
|
||
@Setup | ||
public void setup() throws IOException { | ||
String alertTemplateDtoString = IOUtils.resourceToString("/alertTemplateDto.json", | ||
StandardCharsets.UTF_8); | ||
template = Constants.TEMPLATABLE_OBJECT_MAPPER.readValue(alertTemplateDtoString, | ||
AlertTemplateDTO.class); | ||
valuesMap = ImmutableMap.<String, Object>builder() | ||
.put("aggregationColumn", "views") | ||
.put("completenessDelay", "P0D") | ||
.put("monitoringGranularity", "P1D") | ||
.put("max", "${max}") | ||
.put("timezone", "UTC") | ||
.put("queryFilters", "") | ||
.put("aggregationFunction", "sum") | ||
.put("rcaExcludedDimensions", List.of()) | ||
.put("timeColumnFormat", "1,DAYS,SIMPLE_DATE_FORMAT,yyyyMMdd") | ||
.put("timeColumn", "date") | ||
.put("min", "${min}") | ||
.put("rcaAggregationFunction", "") | ||
.put("queryLimit", "100000000") | ||
.put("startTime", 1) | ||
.put("endTime", 2) | ||
.put("dataSource", "pinotQuickStartLocal") | ||
.put("dataset", "pageviews") | ||
.build(); | ||
} | ||
|
||
@Benchmark | ||
public void applyContext(Blackhole blackhole) throws IOException { | ||
blackhole.consume(StringTemplateUtils.applyContext(template, valuesMap)); | ||
} | ||
} |
Oops, something went wrong.