Skip to content

Instantly share code, notes, and snippets.

@gdela
Last active May 30, 2019 09:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gdela/48c235ccdd083944ae0e258547a81c1c to your computer and use it in GitHub Desktop.
Save gdela/48c235ccdd083944ae0e258547a81c1c to your computer and use it in GitHub Desktop.
Benchmark used for improving performance of TransactionLog class in Hazelcast: https://github.com/hazelcast/hazelcast/pull/15111
/*
* Copyright (c) 2008-2019, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.transaction.impl;
import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.TransactionalMap;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.DataSerializable;
import com.hazelcast.transaction.TransactionContext;
import com.hazelcast.transaction.TransactionOptions;
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.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import static com.hazelcast.transaction.TransactionOptions.TransactionType.TWO_PHASE;
import static com.hazelcast.transaction.impl.MyTransactionBenchmark.ChangeOrder.*;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.commons.lang3.RandomUtils.nextInt;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Fork(value = 1, warmups = 0)
@Warmup(iterations = 3, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 6, time = 1, timeUnit = SECONDS)
public class MyTransactionBenchmark {
private HazelcastInstance instance;
public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder().include(MyTransactionBenchmark.class.getSimpleName()).build();
new Runner(options).run();
}
@Setup
public void setup() throws InterruptedException {
Config config = new Config();
instance = Hazelcast.newHazelcastInstance(config);
instance.getMap("map");
}
@TearDown
public void tearDown() {
Hazelcast.shutdownAll();
}
private TransactionOptions options() {
return new TransactionOptions()
.setTransactionType(TWO_PHASE)
.setDurability(2)
.setTimeout(1, MINUTES);
}
public enum ChangeOrder { FORWARD, BACKWARD, RANDOM, NONE }
private void performTransaction(int numOfEntries, ChangeOrder order) {
TransactionContext context = instance.newTransactionContext(options());
context.beginTransaction();
TransactionalMap<Integer, Pojo> txMap = context.getMap("map");
// baseline - just putting new entries into transaction
for (int id = 0; id < numOfEntries; id++) {
txMap.put(id, new Pojo(id));
}
// in some other place in code - work on the same entries that are already in transaction
IntStream ids = null;
switch (order) {
case FORWARD: ids = IntStream.iterate(0, id -> id+1).limit(numOfEntries); break;
case BACKWARD: ids = IntStream.iterate(numOfEntries-1, id -> id-1).limit(numOfEntries); break;
case RANDOM: ids = IntStream.generate(() -> nextInt(0, numOfEntries)).limit(numOfEntries); break;
case NONE: ids = IntStream.empty(); break;
}
ids.forEach(id -> {
Pojo pojo = txMap.get(id);
pojo.doSomething();
txMap.put(id, pojo);
});
context.commitTransaction();
}
@Benchmark
public void _10_baseline() {
performTransaction(10, NONE);
}
@Benchmark
public void _10_forward() {
performTransaction(10, FORWARD);
}
@Benchmark
public void _10_backward() {
performTransaction(10, BACKWARD);
}
@Benchmark
public void _10_random() {
performTransaction(10, RANDOM);
}
@Benchmark
public void _100_baseline() {
performTransaction(100, NONE);
}
@Benchmark
public void _100_forward() {
performTransaction(100, FORWARD);
}
@Benchmark
public void _100_backward() {
performTransaction(100, BACKWARD);
}
@Benchmark
public void _100_random() {
performTransaction(100, RANDOM);
}
@Benchmark
public void _1000_baseline() {
performTransaction(1000, NONE);
}
@Benchmark
public void _1000_forward() {
performTransaction(1000, FORWARD);
}
@Benchmark
public void _1000_backward() {
performTransaction(1000, BACKWARD);
}
@Benchmark
public void _1000_random() {
performTransaction(1000, RANDOM);
}
@Benchmark
public void _10000_baseline() {
performTransaction(10000, NONE);
}
@Benchmark
public void _10000_forward() {
performTransaction(10000, FORWARD);
}
@Benchmark
public void _10000_backward() {
performTransaction(10000, BACKWARD);
}
@Benchmark
public void _10000_random() {
performTransaction(10000, RANDOM);
}
// todo: benchmark also rollbacks?
public static class Pojo implements DataSerializable {
public int f1;
public int f3;
public int f2;
public int f4;
public String f5;
public Pojo() { }
public Pojo(int f1, int f2, int f3, int f4) {
this.f1 = f1;
this.f2 = f2;
this.f3 = f3;
this.f4 = f4;
this.f5 = "somewhat longer value";
}
public Pojo(int value) {
this(value, value, value, value);
}
public void doSomething() {
this.f1 *= 2;
this.f2 *= 2;
this.f3 *= 2;
this.f4 *= 2;
this.f5 += "- times two";
}
@Override
public void writeData(ObjectDataOutput out) throws IOException {
out.writeInt(f1);
out.writeInt(f2);
out.writeInt(f3);
out.writeInt(f4);
out.writeUTF(f5);
}
@Override
public void readData(ObjectDataInput in) throws IOException {
f1 = in.readInt();
f2 = in.readInt();
f3 = in.readInt();
f4 = in.readInt();
f5 = in.readUTF();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment