Last active
May 30, 2019 09:30
-
-
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
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
/* | |
* 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