Skip to content

Commit

Permalink
Add micro benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
komamitsu committed May 22, 2024
1 parent d6e9e37 commit 3b2be71
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
5 changes: 5 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
id 'net.ltgt.errorprone' version "${errorpronePluginVersion}"
id 'maven-publish'
id 'signing'
id 'application'
}

sourceSets {
Expand Down Expand Up @@ -287,3 +288,7 @@ signing {
required { project.gradle.taskGraph.hasTask("publish") }
sign publishing.publications.mavenJava
}

application {
mainClassName = "com.scalar.db.transaction.consensuscommit.CoordinatorGroupCommitter"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@
import com.scalar.db.util.groupcommit.GroupCommitConfig;
import com.scalar.db.util.groupcommit.GroupCommitter;
import com.scalar.db.util.groupcommit.KeyManipulator;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

public class CoordinatorGroupCommitter
extends GroupCommitter<String, String, String, String, Snapshot> {
Expand Down Expand Up @@ -63,6 +74,7 @@ static class CoordinatorGroupCommitKeyManipulator

// Use Random instead of ThreadLocalRandom in favor of global randomness.
private final Random random = new Random();
private final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

@Override
public String generateParentKey() {
Expand All @@ -73,6 +85,14 @@ public String generateParentKey() {
return new String(chars);
}

public String generateParentKeyWithThreadLocalRandom() {
char[] chars = new char[PRIMARY_KEY_SIZE];
for (int i = 0; i < PRIMARY_KEY_SIZE; i++) {
chars[i] = CHARS_FOR_PRIMARY_KEY[threadLocalRandom.nextInt(CHARS_FOR_PRIMARY_KEY_SIZE)];
}
return new String(chars);
}

@Override
public String fullKey(String parentKey, String childKey) {
if (parentKey.length() != PRIMARY_KEY_SIZE) {
Expand Down Expand Up @@ -121,5 +141,109 @@ public String emitKeyFromParentKey(String s) {
// Return the string as is since the value is already String.
return s;
}

private static final int[] FAST_MASKS = {
554189328, // 10000
277094664, // 01000
138547332, // 00100
69273666, // 00010
34636833, // 00001
346368330, // 01010
727373493, // 10101
588826161, // 10001
935194491, // 11011
658099827, // 10011
};

public String generateParentKeyFaster() {
char[] chars = new char[PRIMARY_KEY_SIZE];
int num_rounds = chars.length / FAST_MASKS.length;

int i = 0;
for (int ctr = 0; ctr < num_rounds; ctr++) {
int rand = random.nextInt(10000);
for (int mask : FAST_MASKS) {
chars[i++] = CHARS_FOR_PRIMARY_KEY[(rand | mask) % CHARS_FOR_PRIMARY_KEY_SIZE];
}
}
// Use the old way for the remaining characters
// I am doing this because I am too lazy to think of something more clever
for (; i < chars.length; i++) {
chars[i] = CHARS_FOR_PRIMARY_KEY[random.nextInt(CHARS_FOR_PRIMARY_KEY_SIZE)];
}
return new String(chars);
}

public String generateParentKeyFasterWithThreadLocalRandom() {
char[] chars = new char[PRIMARY_KEY_SIZE];
int num_rounds = chars.length / FAST_MASKS.length;

int i = 0;
for (int ctr = 0; ctr < num_rounds; ctr++) {
int rand = threadLocalRandom.nextInt(10000);
for (int mask : FAST_MASKS) {
chars[i++] = CHARS_FOR_PRIMARY_KEY[(rand | mask) % CHARS_FOR_PRIMARY_KEY_SIZE];
}
}
// Use the old way for the remaining characters
// I am doing this because I am too lazy to think of something more clever
for (; i < chars.length; i++) {
chars[i] = CHARS_FOR_PRIMARY_KEY[threadLocalRandom.nextInt(CHARS_FOR_PRIMARY_KEY_SIZE)];
}
return new String(chars);
}
}

public static void main(String[] args) throws Throwable {
int threadNum = Integer.parseInt(args[0]);
int opsPerThread = Integer.parseInt(args[1]);
String methodName = args[2];
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);

CoordinatorGroupCommitKeyManipulator keyManipulator =
new CoordinatorGroupCommitKeyManipulator();
int warmup = 20000;
Lookup publicLookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class);
MethodHandle mh =
publicLookup.findVirtual(
CoordinatorGroupCommitKeyManipulator.class, methodName, methodType);

List<Double> durationsPerOp = new ArrayList<>();
List<Future<?>> futures = new ArrayList<>();
for (int threadIndex = 0; threadIndex < threadNum; threadIndex++) {
futures.add(
executorService.submit(
() -> {
try {
for (int i = 0; i < warmup; i++) {
mh.invoke(keyManipulator);
}
TimeUnit.SECONDS.sleep(5);
long start = System.currentTimeMillis();
for (int i = 0; i < opsPerThread; i++) {
mh.invoke(keyManipulator);
}
long duration = System.currentTimeMillis() - start;
double durationPerOp = ((double) duration * 1000) / opsPerThread;
System.out.println("Total duration(ms): " + duration);
System.out.println("Duration(us) per operation: " + durationPerOp);
durationsPerOp.add(durationPerOp);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}));
}
executorService.shutdown();

for (Future<?> future : futures) {
future.get();
}

double tmpSum = 0;
for (double durationPerOp : durationsPerOp) {
tmpSum = tmpSum + durationPerOp;
}
System.out.println("Average duration(us) per operation: " + (tmpSum / threadNum));
}
}

0 comments on commit 3b2be71

Please sign in to comment.