Skip to content

Commit 35ba9fa

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 37314c3 + da19214 commit 35ba9fa

File tree

3 files changed

+123
-38
lines changed

3 files changed

+123
-38
lines changed

README.md

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,56 @@
11
Thread Affinity
22
=============
33

4-
Lets you bind a thread to a given core, this can improve performance ( this libary works best on linux )
4+
Lets you bind a thread to a given core, this can improve performance (this library works best on linux).
55

66

77
OpenHFT Java Thread Affinity library
88

9-
See the affinity/src/test/java for working examples of how to use this library.
9+
See [affinity/src/test/java](https://github.com/OpenHFT/Java-Thread-Affinity/tree/master/affinity/src/test/java)
10+
for working examples of how to use this library.
1011

1112
[Thread Affinity usage Heatmap](http://jrvis.com/red-dwarf/?user=openhft&repo=Java-Thread-Affinity)
1213

13-
## Versions
14+
## Changes
1415

15-
V2.2 - Latest build.
16-
V2.0.1 - Added getThreadId for the process if of the thread.
16+
- V3.1.1 - Upgraded JNA dependency to 4.4.0
17+
- V2.0.1 - Added getThreadId for the process if of the thread.
18+
19+
## Dependencies
20+
21+
Java-Thread-Affinity will try to use [JNA](https://github.com/java-native-access/jna)
22+
to provide access to native thread-handling functions. JNA should be installed on
23+
your system to get the most from this library.
24+
25+
### JNA version
26+
27+
Java-Thread-Affinity currently depends on JNA version 4.4.0, which in turn
28+
depends on a version of GLIBC >= 2.14. If your operating system is an old one,
29+
with a version of GLIBC released before 2011, this library will not be able to
30+
invoke native functions.
31+
32+
To work around this problem, fork the repository, and override the `<version>` tag
33+
for the artifacts `jna` and `jna-platform` in the project's `pom` file.
1734

1835
### Installing JNA on Ubuntu
1936

20-
----
21-
sudo apt-get install libjna-java
22-
----
2337

24-
### Installing JAN on Centos
38+
sudo apt-get install libjna-java
39+
40+
41+
### Installing JNA on CentOS
42+
43+
sudo yum install jna
2544

26-
----
27-
sudo yum install jna
28-
----
2945

30-
## How does allocation work?
31-
The library will read your /proc/cpuinfo if you have one or provide one and it will determine your CPU layout. If you don't have one it will assume every CPU is on one Socket.
46+
## How CPU does allocation work?
47+
The library will read your `/proc/cpuinfo` if you have one or provide one and it will determine your CPU layout. If you don't have one it will assume every CPU is on one CPU socket.
3248

3349
The library looks for isolated CPUs determined by looking at the CPUs you are not running on by default.
3450
i.e. if you have 16 CPUs but 8 of them are not available for general use (as determined by the affinity of the process on startup) it will start assigning to those CPUs.
3551

3652
Note: if you have more than one process using this library you need to specify which CPUs the process can use otherwise it will assign the same CPUs to both processes.
37-
To control which CPUs a process can use, add -Daffinity.reserved={cpu-mark-in-hex} to the command line of the process
53+
To control which CPUs a process can use, add -Daffinity.reserved={cpu-mask-in-hex} to the command line of the process.
3854

3955
Note: the CPU 0 is reserved for the Operating System, it has to run somewhere.
4056

@@ -89,7 +105,7 @@ You can get the current thread id using
89105

90106
int threadId = AffinitySupport.getThreadId();
91107

92-
## determining which CPU you are running on.
108+
## Determining which CPU you are running on.
93109
You can get the current CPU being used by
94110

95111
int cpuId = AffinitySupport.getCpu();

affinity/src/main/java/net/openhft/affinity/BootClassPath.java

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,97 @@
1919

2020
import org.slf4j.Logger;
2121
import org.slf4j.LoggerFactory;
22-
import sun.misc.URLClassPath;
2322

24-
import java.io.File;
25-
import java.net.MalformedURLException;
26-
import java.net.URL;
23+
import java.io.IOException;
24+
import java.nio.file.FileVisitResult;
25+
import java.nio.file.Files;
26+
import java.nio.file.Path;
27+
import java.nio.file.Paths;
28+
import java.nio.file.SimpleFileVisitor;
29+
import java.nio.file.attribute.BasicFileAttributes;
30+
import java.util.Collections;
31+
import java.util.Enumeration;
32+
import java.util.HashSet;
33+
import java.util.Set;
34+
import java.util.jar.JarEntry;
35+
import java.util.jar.JarFile;
2736

2837
enum BootClassPath {
2938
INSTANCE;
3039

31-
private final URLClassPath bootClassPath = new URLClassPath(getBootClassPathURLs());
40+
private final Set<String> bootClassPathResources = Collections.unmodifiableSet(getResourcesOnBootClasspath());
3241

3342
public final boolean has(String binaryClassName) {
34-
String resourceClassName = binaryClassName.replace('.', '/').concat(".class");
35-
return bootClassPath.getResource(resourceClassName, false) != null;
43+
final String resourceClassName = binaryClassName.replace('.', '/').concat(".class");
44+
return bootClassPathResources.contains(resourceClassName);
3645
}
3746

38-
private URL[] getBootClassPathURLs() {
39-
Logger LOGGER = LoggerFactory.getLogger(BootClassPath.class);
40-
try {
41-
String bootClassPath = System.getProperty("sun.boot.class.path");
42-
LOGGER.trace("Boot class-path is: {}", bootClassPath);
47+
private static Set<String> getResourcesOnBootClasspath() {
48+
final Logger logger = LoggerFactory.getLogger(BootClassPath.class);
49+
final Set<String> resources = new HashSet<>();
50+
final String bootClassPath = System.getProperty("sun.boot.class.path");
51+
logger.trace("Boot class-path is: {}", bootClassPath);
52+
53+
final String pathSeparator = System.getProperty("path.separator");
54+
logger.trace("Path separator is: '{}'", pathSeparator);
55+
56+
final String[] pathElements = bootClassPath.split(pathSeparator);
57+
58+
for (final String pathElement : pathElements) {
59+
resources.addAll(findResources(Paths.get(pathElement), logger));
60+
}
61+
62+
return resources;
63+
}
64+
65+
private static Set<String> findResources(final Path path, final Logger logger) {
66+
if (!Files.exists(path)) {
67+
return Collections.emptySet();
68+
}
69+
70+
if (Files.isDirectory(path)) {
71+
return findResourcesInDirectory(path, logger);
72+
}
4373

44-
String pathSeparator = System.getProperty("path.separator");
45-
LOGGER.trace("Path separator is: '{}'", pathSeparator);
74+
return findResourcesInJar(path, logger);
75+
}
4676

47-
String[] pathElements = bootClassPath.split(pathSeparator);
48-
URL[] pathURLs = new URL[pathElements.length];
49-
for (int i = 0; i < pathElements.length; i++) {
50-
pathURLs[i] = new File(pathElements[i]).toURI().toURL();
77+
private static Set<String> findResourcesInJar(final Path path, final Logger logger) {
78+
final Set<String> jarResources = new HashSet<>();
79+
try {
80+
final JarFile jarFile = new JarFile(path.toFile());
81+
final Enumeration<JarEntry> entries = jarFile.entries();
82+
while (entries.hasMoreElements()) {
83+
final JarEntry jarEntry = entries.nextElement();
84+
if (jarEntry.getName().endsWith(".class")) {
85+
jarResources.add(jarEntry.getName());
86+
}
5187
}
5288

53-
return pathURLs;
54-
} catch (MalformedURLException e) {
55-
LOGGER.warn("Parsing the boot class-path failed! Reason: {}", e.getMessage());
56-
return new URL[0];
89+
90+
} catch (IOException e) {
91+
logger.warn("Not a jar file: {}", path);
92+
}
93+
94+
return jarResources;
95+
}
96+
97+
private static Set<String> findResourcesInDirectory(final Path path, final Logger logger) {
98+
final Set<String> dirResources = new HashSet<>();
99+
try {
100+
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
101+
@Override
102+
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
103+
if (file.getFileName().toString().endsWith(".class")) {
104+
dirResources.add(path.relativize(file).toString());
105+
}
106+
return super.visitFile(file, attrs);
107+
}
108+
});
109+
} catch (IOException e) {
110+
logger.warn("Error walking dir: " + path, e);
57111
}
112+
113+
return dirResources;
58114
}
59115
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.openhft.affinity;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.assertTrue;
6+
7+
public class BootClassPathTest {
8+
@Test
9+
public void shouldDetectClassesOnClassPath() throws Exception {
10+
assertTrue(BootClassPath.INSTANCE.has("java.lang.Thread"));
11+
assertTrue(BootClassPath.INSTANCE.has("java.lang.Runtime"));
12+
}
13+
}

0 commit comments

Comments
 (0)