Skip to content

Commit 368dd31

Browse files
committed
Add test for dumping the lock state
1 parent 25cbc4a commit 368dd31

7 files changed

Lines changed: 344 additions & 72 deletions

File tree

pom.xml

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,53 +12,37 @@
1212
<properties>
1313
<native.source.dir>src/main/c</native.source.dir>
1414
</properties>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>junit</groupId>
19+
<artifactId>junit</artifactId>
20+
<version>4.8.2</version>
21+
<scope>test</scope>
22+
</dependency>
23+
</dependencies>
24+
1525
<build>
1626
<plugins>
1727
<plugin>
1828
<groupId>org.codehaus.mojo</groupId>
19-
<artifactId>native-maven-plugin</artifactId>
20-
<version>1.0-alpha-7</version>
21-
<extensions>true</extensions>
22-
23-
<configuration>
24-
<javahClassNames>
25-
<javahClassName>vanilla.java.affinity.AffinitySupport</javahClassName>
26-
</javahClassNames>
27-
<javahSearchJNIFromDependencies>true</javahSearchJNIFromDependencies>
28-
<compilerStartOptions>
29-
<compilerStartOption>${commonCompilerOptions}</compilerStartOption>
30-
</compilerStartOptions>
31-
32-
<sources>
33-
<source>
34-
<directory>${native.source.dir}</directory>
35-
<fileNames>
36-
<fileName>affinitysupport.c</fileName>
37-
</fileNames>
38-
</source>
39-
<source>
40-
<directory>${native.source.dir}/include</directory>
41-
</source>
42-
<source>
43-
<directory>target/native/javah</directory>
44-
</source>
45-
<source>
46-
<directory>/opt/java/openjdk/include/</directory>
47-
</source>
48-
<source>
49-
<directory>/opt/java/openjdk/include/linux/</directory>
50-
</source>
51-
</sources>
52-
53-
<linkerStartOptions>
54-
<linkerStartOption>-shared</linkerStartOption>
55-
</linkerStartOptions>
56-
57-
</configuration>
58-
29+
<artifactId>exec-maven-plugin</artifactId>
30+
<version>1.2.1</version>
31+
<executions>
32+
<execution>
33+
<!-- this execution happens just after compiling the java classes, and builds the native code. -->
34+
<id>build-native</id>
35+
<phase>process-classes</phase>
36+
<goals>
37+
<goal>exec</goal>
38+
</goals>
39+
<configuration>
40+
<executable>src/main/c/Makefile</executable>
41+
<workingDirectory>src/main/c</workingDirectory>
42+
</configuration>
43+
</execution>
44+
</executions>
5945
</plugin>
60-
6146
</plugins>
62-
6347
</build>
6448
</project>

src/main/c/Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/make -f
2+
#
3+
# Makefile for C code
4+
#
5+
6+
# C sources to compile
7+
8+
TARGET_DIR := ../../../target/classes
9+
TARGET := $(TARGET_DIR)/libaffinity.so
10+
11+
WORKING_DIR := $(TARGET_DIR)/../jni
12+
13+
JAVA_BUILD_DIR := $(TARGET_DIR)
14+
15+
JAVA_HOME ?= /usr/java/default
16+
JVM_SHARED_LIB := $(JAVA_HOME)/jre/lib/amd64/server
17+
18+
INCLUDES := -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(WORKING_DIR)
19+
20+
# classpath for javah
21+
ifdef CLASSPATH
22+
JAVAH_CLASSPATH = $(JAVA_BUILD_DIR):$(CLASSPATH)
23+
else
24+
JAVAH_CLASSPATH = $(JAVA_BUILD_DIR)
25+
endif
26+
27+
all: $(TARGET)
28+
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)
31+
32+
$(WORKING_DIR)/vanilla_java_affinity_AffinitySupport.h: $(TARGET_DIR)/vanilla/java/affinity/AffinitySupport.class
33+
mkdir -p $(TARGET_DIR)/jni
34+
javah -force -classpath $(JAVAH_CLASSPATH) -d $(WORKING_DIR) vanilla.java.affinity.AffinitySupport
35+

src/main/c/affinitysupport.c

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#define _GNU_SOURCE
2+
#include <jni.h>
3+
#include <sched.h>
4+
#include "vanilla_java_affinity_AffinitySupport.h"
5+
/*
6+
* Class: vanilla_java_affinity_AffinitySupport
7+
* Method: getAffinity
8+
* Signature: ()J
9+
*/
10+
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_AffinitySupport_getAffinity
11+
(JNIEnv *env, jclass c) {
12+
cpu_set_t mask;
13+
int ret = sched_getaffinity(0, sizeof(mask), &mask);
14+
if (ret < 0) return ~0LL;
15+
long long mask2 = 0, i;
16+
for(i=0;i<sizeof(mask2)*8;i++)
17+
if (CPU_ISSET(i, &mask))
18+
mask2 |= 1L << i;
19+
return (jlong) mask2;
20+
}
21+
22+
/*
23+
* Class: vanilla_java_affinity_AffinitySupport
24+
* Method: setAffinity
25+
* Signature: (J)V
26+
*/
27+
JNIEXPORT void JNICALL Java_vanilla_java_affinity_AffinitySupport_setAffinity
28+
(JNIEnv *env, jclass c, jlong affinity) {
29+
int i;
30+
cpu_set_t mask;
31+
CPU_ZERO(&mask);
32+
for(i=0;i<sizeof(affinity)*8;i++)
33+
if ((affinity >> i) & 1)
34+
CPU_SET(i, &mask);
35+
sched_setaffinity(0, sizeof(mask), &mask);
36+
}
37+
38+
#if defined(__i386__)
39+
static __inline__ unsigned long long rdtsc(void) {
40+
unsigned long long int x;
41+
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
42+
return x;
43+
}
44+
45+
#elif defined(__x86_64__)
46+
static __inline__ unsigned long long rdtsc(void) {
47+
unsigned hi, lo;
48+
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
49+
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
50+
}
51+
52+
#elif defined(__MIPS_32__)
53+
#define rdtsc(dest) \
54+
_ _asm_ _ _ _volatile_ _("mfc0 %0,$9; nop" : "=r" (dest))
55+
56+
#elif defined(__MIPS_SGI__)
57+
#include <time.h>
58+
59+
static __inline__ unsigned long long rdtsc (void) {
60+
struct timespec tp;
61+
clock_gettime (CLOCK_SGI_CYCLE, &tp);
62+
return (unsigned long long)(tp.tv_sec * (unsigned long long)1000000000) + (unsigned long long)tp.tv_nsec;
63+
}
64+
#endif
65+
66+
/*
67+
* Class: vanilla_java_affinity_AffinitySupport
68+
* Method: rdtsc
69+
* Signature: ()J
70+
*/
71+
JNIEXPORT jlong JNICALL Java_vanilla_java_affinity_AffinitySupport_rdtsc
72+
(JNIEnv *env, jclass c) {
73+
return (jlong) rdtsc();
74+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package vanilla.java.affinity;
2+
3+
/**
4+
* @author peter.lawrey
5+
*/
6+
public class AffinityLock {
7+
public static final int PROCESSORS = Runtime.getRuntime().availableProcessors();
8+
public static final long BASE_AFFINITY = AffinitySupport.LOADED ? AffinitySupport.getAffinity() : -1L;
9+
public static final long RESERVED_AFFINITY = getReservedAffinity0();
10+
private static final AffinityLock[] LOCKS = new AffinityLock[PROCESSORS];
11+
private static final AffinityLock NONE = new AffinityLock(-1, false, false);
12+
13+
private final int id;
14+
private final boolean base;
15+
private final boolean reserved;
16+
Thread assignedThread;
17+
18+
AffinityLock(int id, boolean base, boolean reserved) {
19+
this.id = id;
20+
this.base = base;
21+
this.reserved = reserved;
22+
}
23+
24+
static {
25+
for (int i = 0; i < PROCESSORS; i++)
26+
LOCKS[i] = new AffinityLock(i, ((BASE_AFFINITY >> i) & 1) != 0, ((RESERVED_AFFINITY >> i) & 1) != 0);
27+
}
28+
29+
private static long getReservedAffinity0() {
30+
String reservedAffinity = System.getProperty("affinity.reserved");
31+
if (reservedAffinity == null)
32+
return ((1 << PROCESSORS) - 1) ^ BASE_AFFINITY;
33+
return Long.parseLong(reservedAffinity, 16);
34+
}
35+
36+
public static AffinityLock acquireLock() {
37+
Thread t = Thread.currentThread();
38+
synchronized (AffinityLock.class) {
39+
for (int i = PROCESSORS - 1; i > 0; i++) {
40+
AffinityLock al = LOCKS[i];
41+
if (!al.reserved) continue;
42+
if (al.assignedThread != null) {
43+
if (al.assignedThread.isAlive()) continue;
44+
System.err.println("Lock assigned to " + al.assignedThread + " but this thread is dead.");
45+
}
46+
al.assignedThread = t;
47+
System.out.println("Assigning cpu " + al.id + " to " + al.assignedThread);
48+
return al;
49+
}
50+
}
51+
System.out.println("No reservable CPU for " + t);
52+
return AffinityLock.NONE;
53+
}
54+
55+
public void release() {
56+
if (this == NONE) return;
57+
58+
Thread t = Thread.currentThread();
59+
synchronized (AffinityLock.class) {
60+
if (assignedThread != t)
61+
throw new IllegalStateException("Cannot release lock " + id + " assigned to " + assignedThread);
62+
System.out.println("Releasing cpu " + id + " from " + t);
63+
assignedThread = null;
64+
}
65+
}
66+
67+
public static String dumpLocks() {
68+
return dumpLocks0(LOCKS);
69+
}
70+
71+
static String dumpLocks0(AffinityLock[] locks) {
72+
StringBuilder sb = new StringBuilder();
73+
for (int i = 0; i < locks.length; i++) {
74+
AffinityLock al = locks[i];
75+
sb.append(i).append(": ");
76+
if (al.assignedThread != null)
77+
sb.append(al.assignedThread).append(" alive=").append(al.assignedThread.isAlive());
78+
else if (al.reserved)
79+
sb.append("Reserved for this application");
80+
else if (al.base)
81+
sb.append("General use CPU");
82+
else
83+
sb.append("CPU not available");
84+
sb.append('\n');
85+
}
86+
return sb.toString();
87+
}
88+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,54 @@
11
package vanilla.java.affinity;
22

33
public class AffinitySupport {
4+
public static final boolean LOADED;
5+
private static final int FACTOR_BITS = 10;
6+
private static long RDTSC_FACTOR = 1 << FACTOR_BITS;
7+
private static long CPU_FREQUENCY = 1000;
8+
private static final long START;
9+
10+
static {
11+
boolean loaded;
12+
long start;
13+
try {
14+
System.loadLibrary("affinity");
15+
estimateFrequency(50);
16+
estimateFrequency(200);
17+
System.out.println("Estimated clock frequency was " + CPU_FREQUENCY + " MHz");
18+
start = rdtsc();
19+
loaded = true;
20+
} catch (UnsatisfiedLinkError ule) {
21+
System.err.println("Unable to find libaffinity in " + System.getProperty("java.library.path"));
22+
start = 0;
23+
loaded = false;
24+
}
25+
LOADED = loaded;
26+
START = start;
27+
}
28+
29+
private static void estimateFrequency(int factor) {
30+
long now, start = System.nanoTime();
31+
while ((now = System.nanoTime()) == start) ;
32+
long start0 = rdtsc();
33+
long end = start + factor * 1000000;
34+
while ((now = System.nanoTime()) < end) ;
35+
long end0 = rdtsc();
36+
end = now;
37+
RDTSC_FACTOR = (end - start) << FACTOR_BITS / (end0 - start0);
38+
CPU_FREQUENCY = (end0 - start0) * 1000 / (end - start) + 1;
39+
}
40+
441
public native static long getAffinity();
542

643
public native static void setAffinity(long affinity);
744

845
public native static long rdtsc();
46+
47+
public long nanoTime() {
48+
return LOADED ? tscToNano(rdtsc() - START) : System.nanoTime();
49+
}
50+
51+
public long tscToNano(long tsc) {
52+
return tsc * RDTSC_FACTOR >> 10;
53+
}
954
}

0 commit comments

Comments
 (0)