Skip to content

Commit

Permalink
Added a JMH test for Interval encoding
Browse files Browse the repository at this point in the history
The test compares the previous and the proposed solutions.

It confirms the assumptions about the proposed solution:

- about twice as fast
- removes pressure on GC

# JMH version: 1.19
# VM version: JDK 1.8.0_422, VM 25.422-b05
# VM options: -Xms8g -Xmx8g -Xmn7g
# Warmup: 20 iterations, 1 s each
# Measurement: 10 iterations, 2 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time

Benchmark                                                                         Mode  Cnt      Score     Error   Units
IntervalBenchmarks.encodeWithDurationAndPeriod                                   thrpt   30  46339.530 ± 389.115  ops/ms
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.alloc.rate                    thrpt   30   3393.324 ±  28.481  MB/sec
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.alloc.rate.norm               thrpt   30     96.000 ±   0.001    B/op
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.churn.PS_Eden_Space           thrpt   30   3436.887 ± 778.345  MB/sec
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.churn.PS_Eden_Space.norm      thrpt   30     97.302 ±  22.205    B/op
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.churn.PS_Survivor_Space       thrpt   30      0.005 ±   0.006  MB/sec
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.churn.PS_Survivor_Space.norm  thrpt   30     ≈ 10⁻⁴              B/op
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.count                         thrpt   30     36.000            counts
IntervalBenchmarks.encodeWithDurationAndPeriod:·gc.time                          thrpt   30     30.000                ms
IntervalBenchmarks.encodeWithParts                                               thrpt   30  82322.542 ± 109.306  ops/ms
IntervalBenchmarks.encodeWithParts:·gc.alloc.rate                                thrpt   30     ≈ 10⁻⁴            MB/sec
IntervalBenchmarks.encodeWithParts:·gc.alloc.rate.norm                           thrpt   30     ≈ 10⁻⁶              B/op
IntervalBenchmarks.encodeWithParts:·gc.count                                     thrpt   30        ≈ 0            counts

Signed-off-by: Thomas Segismont <tsegismont@gmail.com>
  • Loading branch information
tsegismont committed Sep 9, 2024
1 parent 383cd28 commit f763432
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
40 changes: 40 additions & 0 deletions vertx-pg-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,44 @@
</plugins>
</build>

<profiles>
<profile>
<id>benchmarks</id>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble-benchmarks</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>org.openjdk.jmh.Main</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/test/assembly/benchmarks.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>

</project>
33 changes: 33 additions & 0 deletions vertx-pg-client/src/test/assembly/benchmarks.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!--
~ Copyright (c) 2011-2022 Contributors to the Eclipse Foundation
~
~ This program and the accompanying materials are made available under the
~ terms of the Eclipse Public License 2.0 which is available at
~ http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
~ which is available at https://www.apache.org/licenses/LICENSE-2.0.
~
~ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-->

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
<id>benchmarks</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.testOutputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<scope>test</scope>
</dependencySet>
</dependencySets>
</assembly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/

package io.vertx.pgclient.benchmarks;

import io.vertx.pgclient.data.Interval;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.io.IOException;
import java.time.Duration;
import java.time.Period;
import java.util.concurrent.TimeUnit;

import static java.time.temporal.ChronoUnit.MICROS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

@Threads(1)
@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Fork(value = 3, jvmArgs = {"-Xms8g", "-Xmx8g", "-Xmn7g"})
public class IntervalBenchmarks {

private Interval interval;

@Setup
public void setup() throws IOException, InterruptedException {
interval = new Interval(-2, 3, 15, -13, 2, -57, -426994);
}

@Benchmark
public void encodeWithDurationAndPeriod(Blackhole blackhole) {
Duration duration = Duration
.ofHours(interval.getHours())
.plusMinutes(interval.getMinutes())
.plusSeconds(interval.getSeconds())
.plus(interval.getMicroseconds(), MICROS);
// days won't be changed
Period monthYear = Period.of(interval.getYears(), interval.getMonths(), interval.getDays()).normalized();

blackhole.consume(NANOSECONDS.toMicros(duration.toNanos()));
blackhole.consume(monthYear.getDays());
blackhole.consume((int) monthYear.toTotalMonths());
}

@Benchmark
public void encodeWithParts(Blackhole blackhole) {
// We decompose the interval in 3 parts: months, seconds and micros
int monthsPart = Math.addExact(Math.multiplyExact(interval.getYears(), 12), interval.getMonths());
// A long is big enough to store the maximum/minimum value of the seconds part
long secondsPart = interval.getDays() * 24 * 3600L
+ interval.getHours() * 3600L
+ interval.getMinutes() * 60L
+ interval.getSeconds()
+ interval.getMicroseconds() / 1000000;
int microsPart = interval.getMicroseconds() % 1000000;

// The actual number of months is the sum of the months part and the number of months present in the seconds part
int months = Math.addExact(monthsPart, Math.toIntExact(secondsPart / 2592000));
// The actual number of days is computed from the remainder of the previous division
// It's necessarily smaller than or equal to 29
int days = (int) secondsPart % 2592000 / 86400;
// The actual number of micros is the sum of the micros part and the remainder of previous divisions
// The remainder of previous divisions is necessarily smaller than or equal to a day less a second
// The microseconds part is smaller than a second
// Therefore, their sum is necessarily smaller than a day
long micros = microsPart + secondsPart % 2592000 % 86400 * 1000000;

blackhole.consume(micros);
blackhole.consume(days);
blackhole.consume(months);
}
}

0 comments on commit f763432

Please sign in to comment.