Commit 02398f9c authored by Ivo Anjo's avatar Ivo Anjo

Introduce new doTransactionally API, and port existing examples to use it

parent 008657a4
......@@ -405,47 +405,24 @@ JNIEXPORT void JNICALL Java_javartm_Transaction_abort__J(JNIEnv *env, jclass cls
}
}
/*
JNIEXPORT jobject JNICALL Java_javartm_Transaction_doTransactionally(JNIEnv *env, jclass cls, jobject atomicBlock, jobject fallbackBlock) {
static jmethodID callMethodId = NULL;
if (callMethodId == NULL) {
jclass atomicBlockClass = (*env)->FindClass(env, "java/util/concurrent/Callable");
callMethodId = (*env)->GetMethodID(env, atomicBlockClass, "call", "()Ljava/lang/Object;");
if (!callMethodId) return NULL;
}
printf("Preparing execution...\n");
int res = _xbegin();
if (_xtest()) {
jobject retValue = (*env)->CallObjectMethod(env, atomicBlock, callMethodId);
_xend();
printf("Successful commit\n");
return retValue;
}
printf("Abort or failed to start tx res = %d\n", res);
return (*env)->CallObjectMethod(env, fallbackBlock, callMethodId);
}
*/
// How many times failed transactions inside doTransactionally are retried
// 10 was enough to hit at least 99.999% with most tests
#define RETRIES 10
JNIEXPORT jboolean JNICALL Java_javartm_Transaction_doTransactionally(JNIEnv *env, jclass cls, jobject runnable, jboolean warmup) {
JNIEXPORT jobject JNICALL Java_javartm_Transaction_doTransactionally(JNIEnv *env, jclass cls, jobject runnable, jboolean warmup) {
static jmethodID runMethodId = NULL;
if (runMethodId == NULL) {
jclass atomicBlockClass = (*env)->FindClass(env, "java/lang/Runnable");
runMethodId = (*env)->GetMethodID(env, atomicBlockClass, "run", "()V");
if (!runMethodId) return 0;
jclass atomicBlockClass = (*env)->FindClass(env, "javartm/AtomicRunnable");
runMethodId = (*env)->GetMethodID(env, atomicBlockClass, "run", "()Ljava/lang/Object;");
if (!runMethodId) return NULL;
}
for (int i = 0; i < RETRIES; i++) {
if (warmup || (begin() == _XBEGIN_STARTED)) {
(*env)->CallVoidMethod(env, runnable, runMethodId);
jobject retValue = (*env)->CallObjectMethod(env, runnable, runMethodId);
if (!warmup) _xend();
return 1;
return retValue;
}
}
return 0;
return NULL;
}
/*
* javartm: a Java library for Restricted Transactional Memory
* Copyright (C) 2013 Ivo Anjo <ivo.anjo@ist.utl.pt>
*
* This file is part of javartm.
*
* javartm is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* javartm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with javartm. If not, see <http://www.gnu.org/licenses/>.
*/
package javartm;
/**
* An AtomicRunnable contains a block of code which will be executed transactionally, and methods that
* are before/after the warmup process.
*/
public abstract class AtomicRunnable<V> {
protected void beforeWarmup() { }
protected void afterWarmup() { }
public abstract V run();
}
......@@ -24,11 +24,13 @@ public final class Test3 {
public static int x, y;
public static void main(String[] args) throws Throwable {
final Runnable transaction = new Runnable() {
public void run() {
if (!Transaction.inTransaction()) return;
final AtomicRunnable<Void> transaction = new AtomicRunnable<Void>() {
@Override
public Void run() {
if (!Transaction.inTransaction()) return null;
x++;
y++;
return null;
}
};
......
......@@ -28,8 +28,9 @@ public final class Test6 {
public static void main(String[] args) throws Throwable {
final int ITERS = 5000000;
final Runnable transaction = new Runnable() {
public void run() {
final AtomicRunnable<Void> transaction = new AtomicRunnable<Void>() {
@Override
public Void run() {
// The simpler warmup just returns with this test, but then the dummy method
// call will never work
//if (!Transaction.inTransaction()) return;
......@@ -37,13 +38,17 @@ public final class Test6 {
y++;
z++;
dummy();
return null;
}
@Override
public void afterWarmup() {
x = 0; y = 0; z = 0;
}
};
Warmup.doWarmup(transaction);
x = 0; y = 0; z = 0;
Thread[] threads = new Thread[Runtime.getRuntime().availableProcessors()];
synchronized (Test6.class) {
......
......@@ -99,7 +99,8 @@ public final class Transaction {
// -XX:+PrintCompilation may be used to verify which methods are being recompiled.
Log.trace("Warming up methods");
final Runnable dummyRunnable = new Runnable() { public void run() { } };
final AtomicRunnable<Void> dummyRunnable =
new AtomicRunnable<Void>() { @Override public Void run() { return null; } };
Warmup.doWarmup(new Runnable() { public void run() {
inTransaction();
......@@ -135,13 +136,11 @@ public final class Transaction {
**/
public native static void abort(long reason);
//public native static <V> V doTransactionally(Callable<V> atomicBlock, Callable<V> fallbackBlock);
public static boolean doTransactionally(Runnable r) {
public static <V> V doTransactionally(AtomicRunnable<V> r) {
return doTransactionally(r, false);
}
public native static boolean doTransactionally(Runnable r, boolean warmup);
public native static <V> V doTransactionally(AtomicRunnable<V> r, boolean warmup);
public static short getAbortReason(int txStatus) {
return (short) (txStatus >>> 24);
......
......@@ -33,7 +33,7 @@ public class Warmup {
// In some cases, the value above is not enough, so let's arbitrarily do a bit more
private static final int ITERATIONS = HOTSPOT_JIT_THRESHOLD * 3;
/** Warmups up the received runnable by calling it repeatedly until the VM JIT kicks in **/
/** Warms up the received runnable by calling it repeatedly until the VM JIT kicks in **/
public static void doWarmup(Runnable r) {
for (int i = 0; i < ITERATIONS; i++) r.run();
try {
......@@ -41,4 +41,15 @@ public class Warmup {
} catch (InterruptedException e) { throw new RuntimeException(e); }
Log.info("Warmup for " + r.getClass().getName() + " complete");
}
/** Warms up the received runnable by calling it repeatedly until the VM JIT kicks in **/
public static void doWarmup(AtomicRunnable<?> r) {
r.beforeWarmup();
for (int i = 0; i < ITERATIONS; i++) r.run();
r.afterWarmup();
try {
Thread.sleep(10);
} catch (InterruptedException e) { throw new RuntimeException(e); }
Log.info("Warmup for " + r.getClass().getName() + " complete");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment