Skip to content

Commit a28b2a4

Browse files
committed
Version 1.5 - Add support for efficient pause()ing, whileEqual and whileLessThan with limited busy waiting.
1 parent db40be1 commit a28b2a4

10 files changed

Lines changed: 432 additions & 2 deletions

File tree

README

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[ Version History ]
22

3+
Version 1.5 - Add support for efficient pause()ing, whileEqual and whileLessThan with limited busy waiting.
4+
35
Version 1.4.1 - Add an AffinityThreadFactory to support ExecutorService
46

57
Version 1.4 - Support binding of a whole core for hyper-threaded systems. AffinityLock.acquireCore()

pom.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
<groupId>vanilla.java</groupId>
2424
<artifactId>affinity</artifactId>
25-
<version>1.4.1</version>
25+
<version>1.5</version>
2626
<packaging>jar</packaging>
2727

2828
<licenses>
@@ -129,6 +129,7 @@
129129
</plugin>
130130
<plugin>
131131
<artifactId>maven-javadoc-plugin</artifactId>
132+
<version>2.5</version>
132133
<executions>
133134
<execution>
134135
<phase>package</phase>
@@ -154,6 +155,7 @@
154155
<plugin>
155156
<groupId>org.apache.felix</groupId>
156157
<artifactId>maven-bundle-plugin</artifactId>
158+
<version>2.3.6</version>
157159
<extensions>true</extensions>
158160
<configuration>
159161
<instructions>

src/main/c/Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,17 @@ endif
2626

2727
all: $(TARGET)
2828

29-
$(TARGET): vanilla_java_affinity_impl_NativeAffinity.c $(WORKING_DIR)/vanilla_java_affinity_impl_NativeAffinity.h
29+
$(TARGET): vanilla_java_affinity_impl_NativeAffinity.c $(WORKING_DIR)/vanilla_java_affinity_impl_NativeAffinity.h $(WORKING_DIR)/vanilla_java_clock_impl_JNIClock.h $(WORKING_DIR)/vanilla_java_busywaiting_impl_BusyWaiting.h
3030
gcc -O2 -shared -fPIC -L$(JVM_SHARED_LIB) -ljvm -lrt $(INCLUDES) vanilla_java_affinity_impl_NativeAffinity.c -o $(TARGET)
3131

3232
$(WORKING_DIR)/vanilla_java_affinity_impl_NativeAffinity.h: $(TARGET_DIR)/vanilla/java/affinity/impl/NativeAffinity.class
3333
mkdir -p $(TARGET_DIR)/jni
3434
javah -force -classpath $(JAVAH_CLASSPATH) -d $(WORKING_DIR) vanilla.java.affinity.impl.NativeAffinity
3535

36+
$(WORKING_DIR)/vanilla_java_clock_impl_JNIClock.h: $(TARGET_DIR)/vanilla/java/clock/impl/JNIClock.class
37+
mkdir -p $(TARGET_DIR)/jni
38+
javah -force -classpath $(JAVAH_CLASSPATH) -d $(WORKING_DIR) vanilla.java.clock.impl.JNIClock
39+
40+
$(WORKING_DIR)/vanilla_java_busywaiting_impl_BusyWaiting.h: $(TARGET_DIR)/vanilla/java/busywaiting/impl/JNIBusyWaiting.class
41+
mkdir -p $(TARGET_DIR)/jni
42+
javah -force -classpath $(JAVAH_CLASSPATH) -d $(WORKING_DIR) vanilla.java.busywaiting.impl.JNIBusyWaiting

src/main/c/vanilla_java_affinity_impl_NativeAffinity.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <jni.h>
1919
#include <sched.h>
2020
#include "vanilla_java_affinity_impl_NativeAffinity.h"
21+
#include "vanilla_java_busywaiting_impl_JNIBusyWaiting.h"
22+
#include "vanilla_java_clock_impl_JNIClock.h"
2123
/*
2224
* Class: vanilla_java_affinity_impl_NativeAffinity
2325
* Method: getAffinity0
@@ -88,3 +90,56 @@ JNIEXPORT jlong JNICALL Java_vanilla_java_clock_impl_JNIClock_rdtsc0
8890
(JNIEnv *env, jclass c) {
8991
return (jlong) rdtsc();
9092
}
93+
94+
// From http://locklessinc.com/articles/locks/
95+
/* Compile read-write barrier */
96+
#define barrier() asm volatile("": : :"memory")
97+
98+
/* Pause instruction to prevent excess processor bus usage */
99+
#define cpu_relax() asm volatile("pause\n": : :"memory")
100+
101+
/*
102+
* Class: vanilla_java_busywaiting_impl_JNIBusyWaiting
103+
* Method: pause0
104+
* Signature: ()V
105+
*/
106+
JNIEXPORT void JNICALL Java_vanilla_java_busywaiting_impl_JNIBusyWaiting_pause0
107+
(JNIEnv *env, jclass c) {
108+
cpu_relax();
109+
}
110+
111+
/*
112+
* Class: vanilla_java_busywaiting_impl_JNIBusyWaiting
113+
* Method: whileEqual0
114+
* Signature: (JIJ)J
115+
*/
116+
JNIEXPORT jlong JNICALL Java_vanilla_java_busywaiting_impl_JNIBusyWaiting_whileEqual0
117+
(JNIEnv *env, jclass c, jlong address0, jint iterations, jlong value) {
118+
volatile jlong * address = (volatile jlong *) address0;
119+
barrier();
120+
jlong value2 = *address;
121+
while(value2 == value && iterations-- > 0) {
122+
cpu_relax();
123+
barrier();
124+
value2 = *address;
125+
}
126+
return value2;
127+
}
128+
129+
/*
130+
* Class: vanilla_java_busywaiting_impl_JNIBusyWaiting
131+
* Method: whileLessThan0
132+
* Signature: (JIJ)J
133+
*/
134+
JNIEXPORT jlong JNICALL Java_vanilla_java_busywaiting_impl_JNIBusyWaiting_whileLessThan0
135+
(JNIEnv *env, jclass c, jlong address0, jint iterations, jlong value) {
136+
volatile jlong * address = (volatile jlong *) address0;
137+
barrier();
138+
jlong value2 = *address;
139+
while(value2 < value && iterations-- > 0) {
140+
cpu_relax();
141+
barrier();
142+
value2 = *address;
143+
}
144+
return value2;
145+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2011 Peter Lawrey
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package vanilla.java.busywaiting;
18+
19+
import vanilla.java.busywaiting.impl.JNIBusyWaiting;
20+
import vanilla.java.busywaiting.impl.JavaBusyWaiting;
21+
22+
/**
23+
* @author peter.lawrey
24+
*/
25+
public class BusyWaiter {
26+
private static final IBusyWaiter BUSY_WAITER;
27+
28+
static {
29+
if (JNIBusyWaiting.LOADED)
30+
BUSY_WAITER = JNIBusyWaiting.INSTANCE;
31+
else
32+
BUSY_WAITER = JavaBusyWaiting.INSTANCE;
33+
}
34+
35+
/**
36+
* Pause in the most efficient way available.
37+
*/
38+
public static void pause() {
39+
BUSY_WAITER.pause();
40+
}
41+
42+
/**
43+
* poll a long value until it changes (or the iterations have been reached)
44+
*
45+
* @param obj Object to examine or null for raw address space.
46+
* @param address offset in the Object or address pointer
47+
* @param iterations number of times to try before giving up.
48+
* @param value value to test for, return as soon a the value changes.
49+
* @return the value value found.
50+
*/
51+
public static long whileEqual(Object obj, long address, int iterations, long value) {
52+
return BUSY_WAITER.whileEqual(obj, address, iterations, value);
53+
}
54+
55+
/**
56+
* poll a long value while it is less than a value (or the iterations have been reached)
57+
*
58+
* @param obj Object to examine or null for raw address space.
59+
* @param address offset in the Object or address pointer
60+
* @param iterations number of times to try before giving up.
61+
* @param value value to test for, return as soon a the value is equal or more than.
62+
* @return the value value found.
63+
*/
64+
public static long whileLessThan(Object obj, long address, int iterations, long value) {
65+
return BUSY_WAITER.whileLessThan(obj, address, iterations, value);
66+
}
67+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2011 Peter Lawrey
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package vanilla.java.busywaiting;
18+
19+
/**
20+
* @author peter.lawrey
21+
*/
22+
public interface IBusyWaiter {
23+
public void pause();
24+
25+
public long whileEqual(Object obj, long address, int iterations, long value);
26+
27+
public long whileLessThan(Object obj, long address, int iterations, long value);
28+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2011 Peter Lawrey
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package vanilla.java.busywaiting.impl;
18+
19+
import vanilla.java.busywaiting.IBusyWaiter;
20+
21+
/**
22+
* @author peter.lawrey
23+
*/
24+
public enum JNIBusyWaiting implements IBusyWaiter {
25+
INSTANCE;
26+
27+
public static final boolean LOADED;
28+
29+
static {
30+
boolean loaded;
31+
try {
32+
System.loadLibrary("affinity");
33+
loaded = true;
34+
} catch (UnsatisfiedLinkError ule) {
35+
loaded = false;
36+
}
37+
LOADED = loaded;
38+
}
39+
40+
public static native void pause0();
41+
42+
public static native long whileEqual0(long address, int iterations, long value);
43+
44+
public static native long whileLessThan0(long address, int iterations, long value);
45+
46+
@Override
47+
public void pause() {
48+
pause0();
49+
}
50+
51+
@Override
52+
public long whileEqual(Object obj, long address, int iterations, long value) {
53+
if (obj == null)
54+
return whileEqual0(address, iterations, value);
55+
56+
return whileEqual0(obj, address, iterations, value);
57+
}
58+
59+
private static long whileEqual0(Object obj, long address, int iterations, long value) {
60+
long value2 = JavaBusyWaiting.UNSAFE.getLongVolatile(null, address);
61+
while (value2 == value && iterations-- > 0) {
62+
pause0();
63+
value2 = JavaBusyWaiting.UNSAFE.getLongVolatile(obj, address);
64+
}
65+
return value2;
66+
}
67+
68+
@Override
69+
public long whileLessThan(Object obj, long address, int iterations, long value) {
70+
if (obj == null)
71+
return whileLessThan0(address, iterations, value);
72+
73+
return whileLessThan0(obj, address, iterations, value);
74+
}
75+
76+
private static long whileLessThan0(Object obj, long address, int iterations, long value) {
77+
long value2 = JavaBusyWaiting.UNSAFE.getLongVolatile(null, address);
78+
while (value2 < value && iterations-- > 0) {
79+
pause0();
80+
value2 = JavaBusyWaiting.UNSAFE.getLongVolatile(obj, address);
81+
}
82+
return value2;
83+
}
84+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2011 Peter Lawrey
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package vanilla.java.busywaiting.impl;
18+
19+
import sun.misc.Unsafe;
20+
import vanilla.java.busywaiting.IBusyWaiter;
21+
22+
import java.lang.reflect.Field;
23+
24+
/**
25+
* @author peter.lawrey
26+
*/
27+
public enum JavaBusyWaiting implements IBusyWaiter {
28+
INSTANCE;
29+
30+
static final Unsafe UNSAFE;
31+
32+
33+
@Override
34+
public void pause() {
35+
Thread.yield();
36+
}
37+
38+
@Override
39+
public long whileEqual(Object obj, long address, int iterations, long value) {
40+
long value2 = UNSAFE.getLongVolatile(null, address);
41+
while (value2 == value && iterations-- > 0) {
42+
pause();
43+
value2 = UNSAFE.getLongVolatile(obj, address);
44+
}
45+
return value2;
46+
}
47+
48+
@Override
49+
public long whileLessThan(Object obj, long address, int iterations, long value) {
50+
long value2 = UNSAFE.getLongVolatile(null, address);
51+
while (value2 < value && iterations-- > 0) {
52+
pause();
53+
value2 = UNSAFE.getLongVolatile(obj, address);
54+
}
55+
return value2;
56+
}
57+
58+
static {
59+
try {
60+
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
61+
theUnsafe.setAccessible(true);
62+
UNSAFE = (Unsafe) theUnsafe.get(null);
63+
} catch (Exception e) {
64+
throw new AssertionError(e);
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)