Skip to content

Commit

Permalink
nlm: add throughput test for lock manager
Browse files Browse the repository at this point in the history
Motivation:

 - performance benchmarking
 - getting in touch with JMH

Modification:
Add throughput test for lock manager. Introduce a dedicated profile to
run benchmark tests.

```
$ mvn clean verify -Pbenchmark

....

Result "org.dcache.nfs.benchmarks.ConcurrentLockManagerBenchmark.benchmarkConcurrentLocking":
  1574556.068 ±(99.9%) 98632.233 ops/s [Average]
  (min, avg, max) = (1078256.296, 1574556.068, 1735655.142), stdev = 131671.209
  CI (99.9%): [1475923.835, 1673188.301] (assumes normal distribution)

$
```

Result:
automated performance monitoring can be integrated into CI.

Acked-by: Albert Rossi
Target: master
  • Loading branch information
kofemann committed Mar 8, 2019
1 parent 7c7714d commit 0a43629
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 1 deletion.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Building from sources

To build nfs4j from source code Java8 and Maven3 are required.

To run benchmarks:
```
mvn verify -Pbenchmark
```

Implementing own NFS server
---------------------------

Expand Down
70 changes: 70 additions & 0 deletions benchmarks/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<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>org.dcache</groupId>
<artifactId>nfs4j</artifactId>
<version>0.19.0-SNAPSHOT</version>
</parent>

<groupId>org.dcache</groupId>
<artifactId>benchmarks</artifactId>
<packaging>jar</packaging>

<profiles>
<profile>
<id>benchmark</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>integration-test</phase>
</execution>
</executions>
<configuration>
<executable>java</executable>
<classpathScope>test</classpathScope>
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>org.dcache.nfs.benchmarks.BenchmarkRunner</argument>
<argument>.*</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<!--
EXTERNAL DEPENDENCIES
-->
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
</dependency>
<dependency>
<groupId>org.dcache</groupId>
<artifactId>nfs4j-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.dcache.nfs.benchmarks;

import org.openjdk.jmh.results.format.ResultFormatType;
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;


/**
*
*/
public class BenchmarkRunner {

public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(ConcurrentLockManagerBenchmark.class.getSimpleName())
.resultFormat(ResultFormatType.JSON)
.build();

new Runner(opt).run();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.dcache.nfs.benchmarks;

import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import org.dcache.nfs.v4.StateOwner;
import org.dcache.nfs.v4.nlm.LockException;
import org.dcache.nfs.v4.nlm.LockManager;
import org.dcache.nfs.v4.nlm.NlmLock;
import org.dcache.nfs.v4.nlm.SimpleLm;
import org.dcache.nfs.v4.xdr.clientid4;
import org.dcache.nfs.v4.xdr.nfs_lock_type4;
import org.dcache.nfs.v4.xdr.state_owner4;
import org.openjdk.jmh.annotations.*;

@BenchmarkMode(Mode.Throughput)
public class ConcurrentLockManagerBenchmark {

/*
* Lock manage object. One instance per benchmark.
*/
@State(Scope.Benchmark)
public static class LockManagerHolder {

private LockManager lm;

@Setup
public void setUp() {
lm = new SimpleLm();
}

public LockManager getLockManager() {
return lm;
}
}

/*
* File id object. One per thread. Created in advance to reduce allocation overhead.
*/
@State(Scope.Thread)
public static class FileHolder {

private final Random random = ThreadLocalRandom.current();
private final byte[] file1 = new byte[16];

public FileHolder() {
random.nextBytes(file1);
}

public byte[] getFile() {
return file1;
}

}

@Benchmark
@Threads(16)
@Warmup(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
public NlmLock benchmarkConcurrentLocking(LockManagerHolder lmh, FileHolder fh) throws LockException {

NlmLock lock = new LockBuilder()
.withOwner("owner1")
.from(0)
.length(1)
.forWrite()
.build();

lmh.getLockManager().lock(fh.getFile(), lock);
return lock;
}

public static class LockBuilder {

private long offset;
private long length;
private StateOwner owner;
private int lockType;

LockBuilder withOwner(String owner) {
state_owner4 so = new state_owner4();

so.owner = owner.getBytes(StandardCharsets.UTF_8);
so.clientid = new clientid4(1);
this.owner = new StateOwner(so, 1);
return this;
}

LockBuilder from(long offset) {
this.offset = offset;
return this;
}

LockBuilder length(long length) {
this.length = length;
return this;
}

LockBuilder forRead() {
this.lockType = nfs_lock_type4.READ_LT;
return this;
}

LockBuilder forWrite() {
this.lockType = nfs_lock_type4.WRITE_LT;
return this;
}

NlmLock build() {
return new NlmLock(owner, lockType, offset, length);
}
}

}
10 changes: 10 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
10 changes: 9 additions & 1 deletion core/src/main/java/org/dcache/nfs/v4/nlm/SimpleLm.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@ public class SimpleLm extends AbstractLockManager {
*
* FIXME: get number of threads from RPC service.
*/
private final Striped<Lock> objLock = Striped.lock(Runtime.getRuntime().availableProcessors() * 4);
private final Striped<Lock> objLock;

public SimpleLm() {
this(Runtime.getRuntime().availableProcessors()*4);
}

public SimpleLm(int concurrency) {
objLock = Striped.lock(concurrency);
}

/**
* Exclusive lock on objects locks.
Expand Down
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<module>basic-client</module>
<module>spring</module>
<module>dlm</module>
<module>benchmarks</module>
</modules>

<build>
Expand Down Expand Up @@ -189,6 +190,16 @@
<artifactId>je</artifactId>
<version>7.3.7</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.21</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.21</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down

0 comments on commit 0a43629

Please sign in to comment.