Skip to content

Commit

Permalink
feat: implement micro-benchmark module for performance testing
Browse files Browse the repository at this point in the history
For instance, Statement create/close loop leads to OutOfMemory in OpenJDK/OracleJDK (finalizer queue fills up)
-Xmx128m, OracleJDK 1.8u40, MacOS, 2.6Ghz Core i7
# Warmup Iteration   1: 1147,070 ns/op
# Warmup Iteration   2: 12101,537 ns/op
# Warmup Iteration   3: 90825,971 ns/op
# Warmup Iteration   4: <failure>
java.lang.OutOfMemoryError: GC overhead limit exceeded

closes #289
  • Loading branch information
vlsi committed Jun 3, 2015
1 parent c9214d3 commit 48b79a3
Show file tree
Hide file tree
Showing 5 changed files with 404 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ nbproject
*.iml
build.local.properties
*-dist.zip

ubenchmark/target
162 changes: 162 additions & 0 deletions ubenchmark/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<!--
Copyright (c) 1997-2011, PostgreSQL Global Development Group
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the PostgreSQL Global Development Group nor the names
of its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-->

<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>

<groupId>org.postgresql</groupId>
<artifactId>pgjdbc-benchmark</artifactId>
<version>1.0</version>
<packaging>jar</packaging>

<name>JDBC driver performance benchmarks</name>

<prerequisites>
<maven>3.0</maven>
</prerequisites>

<dependencies>
<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>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
<scope>provided</scope>
</dependency>
</dependencies>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jmh.version>1.9.3</jmh.version>
<javac.target>1.6</javac.target>
<uberjar.name>benchmarks</uberjar.name>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerVersion>${javac.target}</compilerVersion>
<source>${javac.target}</source>
<target>${javac.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</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>
</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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.postgresql.benchmark.connection;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.postgresql.util.ConnectionUtil;

import java.sql.*;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
* Tests the time and memory required to create a connection.
* Note: due to TCP socket's turning into TIME_WAIT state on close, it is
* rather hard to test lots of connection creations, so only 50 iterations are performed.
*
* <p>To run this and other benchmarks (you can run the class from within IDE):
*
* <blockquote>
* <code>mvn package &amp;&amp;
* java -classpath postgresql-driver.jar:target/benchmarks.jar -Duser=postgres -Dpassword=postgres -Dport=5433 -wi 10 -i 10 -f 1</code>
* </blockquote>
*
* <p>To run with profiling:
*
* <blockquote>
* <code>java -classpath postgresql-driver.jar:target/benchmarks.jar
* -prof gc -f 1 -wi 10 -i 10</code>
* </blockquote>
*/
@Fork(1)
@Measurement(iterations = 50)
@Warmup(iterations = 10)
@State(Scope.Thread)
@Threads(1)
@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class FinalizeConnection
{
private Properties connectionProperties;
private String connectionUrl;
private Driver driver;

@Setup(Level.Trial)
public void setUp() throws SQLException
{
Properties props = ConnectionUtil.getProperties();

connectionProperties = props;
connectionUrl = ConnectionUtil.getURL();
driver = DriverManager.getDriver(connectionUrl);
}

@Benchmark
public void baseline() throws SQLException
{
}

@Benchmark
public Connection createAndClose() throws SQLException
{
Connection connection = driver.connect(connectionUrl, connectionProperties);
connection.close();
return connection;
}

public static void main(String[] args) throws RunnerException
{
Options opt = new OptionsBuilder()
.include(FinalizeConnection.class.getSimpleName())
.addProfiler(GCProfiler.class)
.detectJvmArgs()
.build();

new Runner(opt).run();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.postgresql.benchmark.statement;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.postgresql.util.ConnectionUtil;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
* Here we measure the time it takes to create and close a dummy statement.
*
* <p>To run this and other benchmarks (you can run the class from within IDE):
*
* <blockquote>
* <code>mvn package &amp;&amp;
* java -classpath postgresql-driver.jar:target/benchmarks.jar -Duser=postgres -Dpassword=postgres -Dport=5433 -wi 10 -i 10 -f 1</code>
* </blockquote>
*
* <p>To run with profiling:
*
* <blockquote>
* <code>java -classpath postgresql-driver.jar:target/benchmarks.jar
* -prof gc -f 1 -wi 10 -i 10</code>
* </blockquote>
*/
@Fork(value = 1, jvmArgsPrepend = "-Xmx128m")
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class FinalizeStatement
{
@Param({"0", "1", "10", "100"})
private int leakPct;

private float leakPctFloat;

private Connection connection;

@Setup(Level.Trial)
public void setUp() throws SQLException
{
Properties props = ConnectionUtil.getProperties();

connection = DriverManager.getConnection(ConnectionUtil.getURL(), props);
leakPctFloat = 0.01f * leakPct;
}

@TearDown(Level.Trial)
public void tearDown() throws SQLException
{
connection.close();
}

@Benchmark
public Statement createAndLeak() throws SQLException
{
Statement statement = connection.createStatement();
if (ThreadLocalRandom.current().nextFloat() >= leakPctFloat)
statement.close();
return statement;
}

public static void main(String[] args) throws RunnerException
{
Options opt = new OptionsBuilder()
.include(FinalizeStatement.class.getSimpleName())
.addProfiler(GCProfiler.class)
.detectJvmArgs()
.build();

new Runner(opt).run();
}
}
Loading

0 comments on commit 48b79a3

Please sign in to comment.