Skip to content

Commit b59b477

Browse files
committed
Add support for JNA
1 parent bf54c8b commit b59b477

13 files changed

Lines changed: 282 additions & 118 deletions

README

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Check update
1+
Verison 1.0 -

src/main/c/vanilla_java_affinity_NativeAffinity.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
#include "vanilla_java_affinity_NativeAffinity.h"
55
/*
66
* Class: vanilla_java_affinity_NativeAffinity
7-
* Method: getAffinity
7+
* Method: getAffinity0
88
* Signature: ()J
99
*/
10-
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_getAffinity
10+
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_getAffinity0
1111
(JNIEnv *env, jclass c) {
1212
cpu_set_t mask;
1313
int ret = sched_getaffinity(0, sizeof(mask), &mask);
@@ -21,10 +21,10 @@ JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_getAffinity
2121

2222
/*
2323
* Class: vanilla_java_affinity_NativeAffinity
24-
* Method: setAffinity
24+
* Method: setAffinity0
2525
* Signature: (J)V
2626
*/
27-
JNIEXPORT void JNICALL Java_vanilla_java_affinity_NativeAffinity_setAffinity
27+
JNIEXPORT void JNICALL Java_vanilla_java_affinity_NativeAffinity_setAffinity0
2828
(JNIEnv *env, jclass c, jlong affinity) {
2929
int i;
3030
cpu_set_t mask;
@@ -65,10 +65,10 @@ static __inline__ unsigned long long rdtsc (void) {
6565

6666
/*
6767
* Class: vanilla_java_affinity_NativeAffinity
68-
* Method: rdtsc
68+
* Method: rdtsc0
6969
* Signature: ()J
7070
*/
71-
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_rdtsc
71+
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_rdtsc0
7272
(JNIEnv *env, jclass c) {
7373
return (jlong) rdtsc();
7474
}

src/main/java/vanilla/java/affinity/AffinityLock.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
public class AffinityLock {
77
public static final int PROCESSORS = Runtime.getRuntime().availableProcessors();
8-
public static final long BASE_AFFINITY = NativeAffinity.LOADED ? NativeAffinity.getAffinity() : -1L;
8+
public static final long BASE_AFFINITY = AffinitySupport.getAffinity();
99
public static final long RESERVED_AFFINITY = getReservedAffinity0();
1010
private static final AffinityLock[] LOCKS = new AffinityLock[PROCESSORS];
1111
private static final AffinityLock NONE = new AffinityLock(-1, false, false);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package vanilla.java.affinity;
2+
3+
public enum AffinitySupport {
4+
;
5+
6+
interface IAffinity {
7+
public long getAffinity();
8+
9+
public void setAffinity(long affinity);
10+
11+
public long nanoTime();
12+
}
13+
14+
private static final IAffinity affinityImpl;
15+
16+
static {
17+
if (NativeAffinity.LOADED)
18+
affinityImpl = NativeAffinity.INSTANCE;
19+
else if (JNAAffinity.LOADED)
20+
affinityImpl = JNAAffinity.INSTANCE;
21+
else
22+
affinityImpl = NullAffinity.INSTANCE;
23+
}
24+
25+
public static long getAffinity() {
26+
return affinityImpl.getAffinity();
27+
}
28+
29+
public static void setAffinity(long affinity) {
30+
affinityImpl.setAffinity(affinity);
31+
}
32+
33+
public static long nanoTime() {
34+
return affinityImpl.nanoTime();
35+
}
36+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package vanilla.java.affinity;
2+
3+
import com.sun.jna.*;
4+
import com.sun.jna.ptr.LongByReference;
5+
6+
public enum JNAAffinity implements AffinitySupport.IAffinity {
7+
INSTANCE;
8+
public static final Boolean LOADED;
9+
public static final String LIBRARY_NAME = Platform.isWindows() ? "msvcrt" : "c";
10+
11+
private interface CLibrary extends Library {
12+
public static final CLibrary INSTANCE = (CLibrary)
13+
Native.loadLibrary(LIBRARY_NAME, CLibrary.class);
14+
15+
public int sched_setaffinity(final int pid, final int cpusetsize, final PointerType cpuset);
16+
17+
public int sched_getaffinity(final int pid, final int cpusetsize, final PointerType cpuset);
18+
19+
// public int sched_getcpu();
20+
}
21+
22+
static {
23+
boolean loaded = false;
24+
try {
25+
INSTANCE.getAffinity();
26+
loaded = true;
27+
} catch (Exception e) {
28+
System.out.println("Unable to load jna library " + e);
29+
}
30+
LOADED = loaded;
31+
}
32+
33+
@Override
34+
public long getAffinity() {
35+
final CLibrary lib = CLibrary.INSTANCE;
36+
final LongByReference cpuset = new LongByReference(0L);
37+
final int ret = lib.sched_getaffinity(0, Long.SIZE / 8, cpuset);
38+
if (ret < 0) {
39+
final int errNo = getErrorNo();
40+
throw new IllegalStateException("sched_getaffinity((" + Long.SIZE / 8 + ") , &(" + cpuset + ") ) return " + ret + ", errno() = " + errNo);
41+
}
42+
return cpuset.getValue();
43+
}
44+
45+
@Override
46+
public void setAffinity(long affinity) {
47+
final CLibrary lib = CLibrary.INSTANCE;
48+
final int ret = lib.sched_setaffinity(0, Long.SIZE / 8, new LongByReference(affinity));
49+
if (ret < 0) {
50+
final int errNo = getErrorNo();
51+
throw new IllegalStateException("sched_setaffinity((" + Long.SIZE / 8 + ") , &(" + affinity + ") ) return " + ret + ", errno() = " + errNo);
52+
}
53+
}
54+
55+
private static int getErrorNo() {
56+
final NativeLibrary nativeLib = NativeLibrary.getInstance(LIBRARY_NAME);
57+
final Pointer pErrNo = nativeLib.getFunction("errno");
58+
return pErrNo.getInt(0);
59+
}
60+
61+
@Override
62+
public long nanoTime() {
63+
return System.nanoTime();
64+
}
65+
}

src/main/java/vanilla/java/affinity/NativeAffinity.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package vanilla.java.affinity;
22

3-
public class NativeAffinity {
3+
public enum NativeAffinity implements AffinitySupport.IAffinity {
4+
INSTANCE;
5+
46
public static final boolean LOADED;
57
private static final int FACTOR_BITS = 17;
68
private static long RDTSC_FACTOR = 1 << FACTOR_BITS;
@@ -15,10 +17,10 @@ public class NativeAffinity {
1517
estimateFrequency(50);
1618
estimateFrequency(200);
1719
System.out.println("Estimated clock frequency was " + CPU_FREQUENCY + " MHz");
18-
start = rdtsc();
20+
start = rdtsc0();
1921
loaded = true;
2022
} catch (UnsatisfiedLinkError ule) {
21-
System.err.println("Unable to find libaffinity in " + System.getProperty("java.library.path"));
23+
System.out.println("Unable to find libaffinity in " + System.getProperty("java.library.path") + " " + ule);
2224
start = 0;
2325
loaded = false;
2426
}
@@ -29,23 +31,34 @@ public class NativeAffinity {
2931
private static void estimateFrequency(int factor) {
3032
long now, start = System.nanoTime();
3133
while ((now = System.nanoTime()) == start) ;
32-
long start0 = rdtsc();
34+
long start0 = rdtsc0();
3335
long end = start + factor * 1000000;
3436
while ((now = System.nanoTime()) < end) ;
35-
long end0 = rdtsc();
37+
long end0 = rdtsc0();
3638
end = now;
3739
RDTSC_FACTOR = ((end - start) << FACTOR_BITS) / (end0 - start0) - 1;
3840
CPU_FREQUENCY = (end0 - start0 + 1) * 1000 / (end - start);
3941
}
4042

41-
public native static long getAffinity();
43+
private native static long getAffinity0();
44+
45+
private native static void setAffinity0(long affinity);
46+
47+
native static long rdtsc0();
4248

43-
public native static void setAffinity(long affinity);
4449

45-
public native static long rdtsc();
50+
@Override
51+
public long getAffinity() {
52+
return getAffinity0();
53+
}
54+
55+
@Override
56+
public void setAffinity(long affinity) {
57+
setAffinity0(affinity);
58+
}
4659

47-
public static long nanoTime() {
48-
return LOADED ? tscToNano(rdtsc() - START) : System.nanoTime();
60+
public long nanoTime() {
61+
return tscToNano(rdtsc0() - START);
4962
}
5063

5164
public static long tscToNano(long tsc) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package vanilla.java.affinity;
2+
3+
public enum NullAffinity implements AffinitySupport.IAffinity {
4+
INSTANCE;
5+
6+
@Override
7+
public long getAffinity() {
8+
return -1;
9+
}
10+
11+
@Override
12+
public void setAffinity(long affinity) {
13+
14+
}
15+
16+
@Override
17+
public long nanoTime() {
18+
return System.nanoTime();
19+
}
20+
}

src/test/java/vanilla/java/affinity/AffinitySupportMain.java renamed to src/test/java/vanilla/java/affinity/AffinityLockMain.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@
33
/**
44
* @author peter.lawrey
55
*/
6-
public class NativeAffinityMain {
7-
public static void main(String... args) {
8-
AffinityLock al = AffinityLock.acquireLock();
9-
try {
10-
new Thread(new SleepRunnable(), "reader").start();
11-
new Thread(new SleepRunnable(), "writer").start();
12-
new Thread(new SleepRunnable(), "engine").start();
13-
} finally {
14-
al.release();
15-
}
6+
public class AffinityLockMain {
7+
public static void main(String... args) throws InterruptedException {
8+
new Thread(new SleepRunnable(), "engine").start();
9+
new Thread(new SleepRunnable(), "reader").start();
10+
new Thread(new SleepRunnable(), "writer").start();
11+
Thread.sleep(100);
12+
System.out.println(AffinityLock.dumpLocks());
1613
}
1714

1815
private static class SleepRunnable implements Runnable {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package vanilla.java.affinity;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.assertEquals;
6+
7+
/**
8+
* @author peter.lawrey
9+
*/
10+
public class AffinityLockTest {
11+
@Test
12+
public void dumpLocks() {
13+
AffinityLock[] locks = {
14+
new AffinityLock(0, true, false),
15+
new AffinityLock(1, false, false),
16+
new AffinityLock(2, false, true),
17+
new AffinityLock(3, false, true),
18+
new AffinityLock(4, true, false),
19+
new AffinityLock(5, false, false),
20+
new AffinityLock(6, false, true),
21+
new AffinityLock(7, false, true),
22+
};
23+
locks[2].assignedThread = new Thread(new InterrupedThread(), "logger");
24+
locks[2].assignedThread.start();
25+
locks[3].assignedThread = new Thread(new InterrupedThread(), "engine");
26+
locks[3].assignedThread.start();
27+
locks[6].assignedThread = new Thread(new InterrupedThread(), "main");
28+
locks[7].assignedThread = new Thread(new InterrupedThread(), "tcp");
29+
locks[7].assignedThread.start();
30+
final String actual = AffinityLock.dumpLocks0(locks);
31+
assertEquals("0: General use CPU\n" +
32+
"1: CPU not available\n" +
33+
"2: Thread[logger,5,main] alive=true\n" +
34+
"3: Thread[engine,5,main] alive=true\n" +
35+
"4: General use CPU\n" +
36+
"5: CPU not available\n" +
37+
"6: Thread[main,5,main] alive=false\n" +
38+
"7: Thread[tcp,5,main] alive=true\n", actual);
39+
System.out.println(actual);
40+
41+
locks[2].assignedThread.interrupt();
42+
locks[3].assignedThread.interrupt();
43+
locks[7].assignedThread.interrupt();
44+
}
45+
46+
}

0 commit comments

Comments
 (0)