Skip to content

Commit 9622eaa

Browse files
committed
Rename AffinitySupport => Native Affinity
1 parent ff0b2c0 commit 9622eaa

8 files changed

Lines changed: 244 additions & 28 deletions

File tree

pom.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>vanilla.java</groupId>
88
<artifactId>affinity</artifactId>
9-
<version>1.0</version>
9+
<version>1.1</version>
1010
<packaging>jar</packaging>
1111

1212
<properties>
@@ -20,6 +20,13 @@
2020
<version>4.8.2</version>
2121
<scope>test</scope>
2222
</dependency>
23+
<dependency>
24+
<groupId>com.sun.jna</groupId>
25+
<artifactId>jna</artifactId>
26+
<version>3.2.7</version>
27+
<scope>system</scope>
28+
<systemPath>/usr/share/java/jna.jar</systemPath>
29+
</dependency>
2330
</dependencies>
2431

2532
<build>

src/main/c/Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ endif
2626

2727
all: $(TARGET)
2828

29-
$(TARGET): vanilla_java_affinity_AffinitySupport.c $(WORKING_DIR)/vanilla_java_affinity_AffinitySupport.h
30-
gcc -O2 -shared -fPIC -L$(JVM_SHARED_LIB) -ljvm -lrt $(INCLUDES) vanilla_java_affinity_AffinitySupport.c -o $(TARGET)
29+
$(TARGET): vanilla_java_affinity_NativeAffinity.c $(WORKING_DIR)/vanilla_java_affinity_NativeAffinity.h
30+
gcc -O2 -shared -fPIC -L$(JVM_SHARED_LIB) -ljvm -lrt $(INCLUDES) vanilla_java_affinity_NativeAffinity.c -o $(TARGET)
3131

32-
$(WORKING_DIR)/vanilla_java_affinity_AffinitySupport.h: $(TARGET_DIR)/vanilla/java/affinity/AffinitySupport.class
32+
$(WORKING_DIR)/vanilla_java_affinity_NativeAffinity.h: $(TARGET_DIR)/vanilla/java/affinity/NativeAffinity.class
3333
mkdir -p $(TARGET_DIR)/jni
34-
javah -force -classpath $(JAVAH_CLASSPATH) -d $(WORKING_DIR) vanilla.java.affinity.AffinitySupport
34+
javah -force -classpath $(JAVAH_CLASSPATH) -d $(WORKING_DIR) vanilla.java.affinity.NativeAffinity
3535

src/main/c/vanilla_java_affinity_AffinitySupport.c renamed to src/main/c/vanilla_java_affinity_NativeAffinity.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#define _GNU_SOURCE
22
#include <jni.h>
33
#include <sched.h>
4-
#include "vanilla_java_affinity_AffinitySupport.h"
4+
#include "vanilla_java_affinity_NativeAffinity.h"
55
/*
6-
* Class: vanilla_java_affinity_AffinitySupport
6+
* Class: vanilla_java_affinity_NativeAffinity
77
* Method: getAffinity
88
* Signature: ()J
99
*/
10-
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_AffinitySupport_getAffinity
10+
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_getAffinity
1111
(JNIEnv *env, jclass c) {
1212
cpu_set_t mask;
1313
int ret = sched_getaffinity(0, sizeof(mask), &mask);
@@ -20,11 +20,11 @@ JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_AffinitySupport_getAffinity
2020
}
2121

2222
/*
23-
* Class: vanilla_java_affinity_AffinitySupport
23+
* Class: vanilla_java_affinity_NativeAffinity
2424
* Method: setAffinity
2525
* Signature: (J)V
2626
*/
27-
JNIEXPORT void JNICALL Java_vanilla_java_affinity_AffinitySupport_setAffinity
27+
JNIEXPORT void JNICALL Java_vanilla_java_affinity_NativeAffinity_setAffinity
2828
(JNIEnv *env, jclass c, jlong affinity) {
2929
int i;
3030
cpu_set_t mask;
@@ -64,11 +64,11 @@ static __inline__ unsigned long long rdtsc (void) {
6464
#endif
6565

6666
/*
67-
* Class: vanilla_java_affinity_AffinitySupport
67+
* Class: vanilla_java_affinity_NativeAffinity
6868
* Method: rdtsc
6969
* Signature: ()J
7070
*/
71-
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_AffinitySupport_rdtsc
71+
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_NativeAffinity_rdtsc
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 = AffinitySupport.LOADED ? AffinitySupport.getAffinity() : -1L;
8+
public static final long BASE_AFFINITY = NativeAffinity.LOADED ? NativeAffinity.getAffinity() : -1L;
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);

src/main/java/vanilla/java/affinity/AffinitySupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package vanilla.java.affinity;
22

3-
public class AffinitySupport {
3+
public class NativeAffinity {
44
public static final boolean LOADED;
55
private static final int FACTOR_BITS = 17;
66
private static long RDTSC_FACTOR = 1 << FACTOR_BITS;
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package test.threads;
2+
3+
import com.sun.jna.*;
4+
import com.sun.jna.ptr.LongByReference;
5+
6+
import java.text.ParseException;
7+
import java.util.StringTokenizer;
8+
9+
/**
10+
* For attaching threads to cores
11+
*
12+
* @author cheremin
13+
* @since 25.10.11, 14:18
14+
*/
15+
public class ThreadAffinity {
16+
17+
private static final Core[] cores;
18+
19+
static {
20+
final int coresCount = Runtime.getRuntime().availableProcessors();
21+
cores = new Core[coresCount];
22+
23+
for (int i = 0; i < cores.length; i++) {
24+
cores[i] = new Core(i);
25+
}
26+
}
27+
28+
29+
public static final class Core {
30+
private final int sequence;
31+
32+
public Core(final int sequence) {
33+
this.sequence = sequence;
34+
if (sequence > Integer.SIZE) {
35+
throw new IllegalStateException("Too many cores (" + sequence + ") for integer mask");
36+
}
37+
}
38+
39+
public int sequence() {
40+
return sequence;
41+
}
42+
43+
public void attachTo() throws Exception {
44+
45+
final long mask = mask();
46+
47+
setCurrentThreadAffinityMask(mask);
48+
}
49+
50+
public void attach(final Thread thread) throws Exception {
51+
52+
final long mask = mask();
53+
54+
setThreadAffinityMask(thread.getId(), mask);
55+
}
56+
57+
private int mask() {
58+
return 1 << sequence;
59+
}
60+
61+
62+
@Override
63+
public String toString() {
64+
return String.format("Core[#%d]", sequence());
65+
}
66+
67+
}
68+
69+
public static void setCurrentThreadAffinityMask(final long mask) throws Exception {
70+
final CLibrary lib = CLibrary.INSTANCE;
71+
final int cpuMaskSize = Long.SIZE / 8;
72+
try {
73+
final int ret = lib.sched_setaffinity(0, cpuMaskSize, new LongByReference(mask));
74+
if (ret < 0) {
75+
final int errNo = getErrorNo();
76+
throw new Exception("sched_setaffinity( 0, (" + cpuMaskSize + ") , &(" + mask + ") ) return " + ret + ", errno() = " + errNo);
77+
}
78+
} catch (Throwable e) {
79+
throw new Exception(e);
80+
}
81+
}
82+
83+
public static void setThreadAffinityMask(final long threadID,
84+
final long mask) throws Exception {
85+
final CLibrary lib = CLibrary.INSTANCE;
86+
final int cpuMaskSize = Long.SIZE / 8;
87+
try {
88+
final int ret = lib.sched_setaffinity((int) threadID, cpuMaskSize, new LongByReference(mask));
89+
if (ret < 0) {
90+
final int errNo = getErrorNo();
91+
throw new Exception("sched_setaffinity( " + threadID + ", (" + cpuMaskSize + ") , &(" + mask + ") ) return " + ret + ", errno() = " + errNo);
92+
}
93+
} catch (Throwable e) {
94+
throw new Exception(e);
95+
}
96+
}
97+
98+
99+
private static int getErrorNo() {
100+
final NativeLibrary nativeLib = NativeLibrary.getInstance("c");
101+
final Pointer pErrNo = nativeLib.getFunction("errno");
102+
return pErrNo.getInt(0);
103+
}
104+
105+
106+
public static Core[] cores() {
107+
return cores.clone();
108+
}
109+
110+
public static Core currentCore() {
111+
final int cpuSequence = CLibrary.INSTANCE.sched_getcpu();
112+
return cores[cpuSequence];
113+
}
114+
115+
public static void nice(final int increment) throws Exception {
116+
final CLibrary lib = CLibrary.INSTANCE;
117+
try {
118+
final int ret = lib.nice(increment);
119+
if (ret < 0) {
120+
final int errNo = getErrorNo();
121+
throw new Exception("nice( " + increment + " ) return " + ret + ", errno() = " + errNo);
122+
}
123+
} catch (Throwable e) {
124+
throw new Exception(e);
125+
}
126+
}
127+
128+
private interface CLibrary extends Library {
129+
public static final CLibrary INSTANCE = (CLibrary)
130+
Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
131+
132+
public void printf(final String format,
133+
final Object... args);
134+
135+
public int nice(final int increment);
136+
137+
public int sched_setaffinity(final int pid,
138+
final int cpusetsize,
139+
final PointerType cpuset);
140+
141+
public int sched_getcpu();
142+
}
143+
144+
public static void main(final String[] args) throws Exception {
145+
146+
final Core currentCore = currentCore();
147+
// System.out.printf( "currentCore() -> %s\n", currentCore );
148+
149+
// final int niceRet = lib.nice( -20 );
150+
// System.out.printf( "nice -> %d\n", niceRet );
151+
152+
153+
for (final Core core : cores()) {
154+
new Thread() {
155+
@Override
156+
public void run() {
157+
try {
158+
core.attachTo();
159+
System.out.printf("currentCore() -> %s\n", currentCore());
160+
for (int i = 0; i < Integer.MAX_VALUE; i++) {
161+
i--;
162+
}
163+
} catch (Exception e) {
164+
e.printStackTrace();
165+
}
166+
}
167+
}.start();
168+
169+
170+
}
171+
172+
}
173+
174+
public static int[] parseCoresIndexes(final String str,
175+
final int[] defaults) throws ParseException {
176+
final StringTokenizer stok = new StringTokenizer(str, ",");
177+
final int size = stok.countTokens();
178+
if (size == 0) {
179+
return defaults;
180+
}
181+
182+
final int maxIndex = Runtime.getRuntime().availableProcessors() - 1;
183+
final int[] indexes = new int[size];
184+
for (int i = 0; stok.hasMoreTokens(); i++) {
185+
final String token = stok.nextToken();
186+
final int index;
187+
try {
188+
index = Integer.parseInt(token);
189+
} catch (NumberFormatException e) {
190+
throw new ParseException("Can't parse [" + i + "]='" + token + "' as Integer", i);
191+
}
192+
if (index > maxIndex || index < 0) {
193+
throw new ParseException("Index[" + i + "]=" + index + " is out of bounds [0," + maxIndex + "]", i);
194+
}
195+
indexes[i] = index;
196+
}
197+
return indexes;
198+
}
199+
200+
public static Core[] parseCores(final String str,
201+
final int[] defaults) throws ParseException {
202+
final int[] indexes = parseCoresIndexes(str, defaults);
203+
final Core[] cores = new Core[indexes.length];
204+
for (int i = 0; i < cores.length; i++) {
205+
cores[i] = cores()[indexes[i]];
206+
}
207+
return cores;
208+
}
209+
}

src/test/java/vanilla/java/affinity/AffinitySupportMain.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/**
44
* @author peter.lawrey
55
*/
6-
public class AffinitySupportMain {
6+
public class NativeAffinityMain {
77
public static void main(String... args) {
88
AffinityLock al = AffinityLock.acquireLock();
99
try {

src/test/java/vanilla/java/affinity/AffinitySupportTest.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@
77
/**
88
* @author peter.lawrey
99
*/
10-
public class AffinitySupportTest {
10+
public class NativeAffinityTest {
1111
@Test
1212
public void testGetAffinity() throws Exception {
13-
long a = AffinitySupport.getAffinity();
13+
long a = NativeAffinity.getAffinity();
1414
assertFalse(a == 0);
1515
assertFalse(a == -1);
1616
}
1717

1818
@Test
1919
public void testSetAffinity() throws Exception {
20-
AffinitySupport.setAffinity(0x1);
21-
assertEquals(0x1, AffinitySupport.getAffinity());
20+
NativeAffinity.setAffinity(0x1);
21+
assertEquals(0x1, NativeAffinity.getAffinity());
2222

23-
AffinitySupport.setAffinity(0x2);
24-
assertEquals(0x2, AffinitySupport.getAffinity());
23+
NativeAffinity.setAffinity(0x2);
24+
assertEquals(0x2, NativeAffinity.getAffinity());
2525
}
2626

2727
@Test
2828
public void testRdtsc() throws Exception {
29-
long l1 = AffinitySupport.rdtsc();
30-
long l2 = AffinitySupport.rdtsc();
29+
long l1 = NativeAffinity.rdtsc();
30+
long l2 = NativeAffinity.rdtsc();
3131
assertTrue(l2 > l1);
3232
assertTrue(l2 < l1 + 1000000);
3333
}
@@ -77,14 +77,14 @@ public void run() {
7777
@Test
7878
public void testRdtscPerf() {
7979
final int runs = 10 * 1000 * 1000;
80-
AffinitySupport.rdtsc();
80+
NativeAffinity.rdtsc();
8181
long start = System.nanoTime();
82-
long start0 = AffinitySupport.rdtsc();
82+
long start0 = NativeAffinity.rdtsc();
8383
for (int i = 0; i < runs; i++)
84-
AffinitySupport.rdtsc();
84+
NativeAffinity.rdtsc();
8585
long time = System.nanoTime() - start;
86-
final long time0 = AffinitySupport.rdtsc() - start0;
87-
long time2 = AffinitySupport.tscToNano(time0);
86+
final long time0 = NativeAffinity.rdtsc() - start0;
87+
long time2 = NativeAffinity.tscToNano(time0);
8888
System.out.printf("Each call took %.1f ns and the ratio was %.5f%n", (double) time / runs, (double) time2 / time);
8989
}
9090
}

0 commit comments

Comments
 (0)