Skip to content

Commit ad46a29

Browse files
committed
AFFINITY-26 Add a faster JNI timer and performance tune a number of key benchmarks.
1 parent 6560e9e commit ad46a29

14 files changed

Lines changed: 271 additions & 212 deletions

File tree

affinity/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<groupId>net.openhft</groupId>
4646
<artifactId>third-party-bom</artifactId>
4747
<type>pom</type>
48-
<version>3.4.18</version>
48+
<version>3.4.20</version>
4949
<scope>import</scope>
5050
</dependency>
5151
</dependencies>
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright (C) 2015 higherfrequencytrading.com
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU Lesser General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU Lesser General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
17+
package net.openhft.affinity;
18+
19+
import net.openhft.affinity.impl.*;
20+
import org.jetbrains.annotations.NotNull;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
24+
import java.io.PrintWriter;
25+
import java.io.StringWriter;
26+
import java.util.BitSet;
27+
28+
/**
29+
* Library to wrap low level JNI or JNA calls. Can be called without needing to know the actual implementation used.
30+
*
31+
* @author peter.lawrey
32+
*/
33+
public enum Affinity {
34+
;
35+
@NotNull
36+
private static final IAffinity AFFINITY_IMPL;
37+
static final Logger LOGGER = LoggerFactory.getLogger(Affinity.class);
38+
private static Boolean JNAAvailable;
39+
40+
static {
41+
String osName = System.getProperty("os.name");
42+
if (osName.contains("Win") && isWindowsJNAAffinityUsable()) {
43+
LOGGER.trace("Using Windows JNA-based affinity control implementation");
44+
AFFINITY_IMPL = WindowsJNAAffinity.INSTANCE;
45+
46+
} else if (osName.contains("x")) {
47+
/*if (osName.startsWith("Linux") && NativeAffinity.LOADED) {
48+
LOGGER.trace("Using Linux JNI-based affinity control implementation");
49+
AFFINITY_IMPL = NativeAffinity.INSTANCE;
50+
} else*/
51+
if (osName.startsWith("Linux") && isLinuxJNAAffinityUsable()) {
52+
LOGGER.trace("Using Linux JNA-based affinity control implementation");
53+
AFFINITY_IMPL = LinuxJNAAffinity.INSTANCE;
54+
55+
} else if (isPosixJNAAffinityUsable()) {
56+
LOGGER.trace("Using Posix JNA-based affinity control implementation");
57+
AFFINITY_IMPL = PosixJNAAffinity.INSTANCE;
58+
59+
} else {
60+
LOGGER.info("Using dummy affinity control implementation");
61+
AFFINITY_IMPL = NullAffinity.INSTANCE;
62+
}
63+
} else if (osName.contains("Mac") && isMacJNAAffinityUsable()) {
64+
LOGGER.trace("Using MAC OSX JNA-based thread id implementation");
65+
AFFINITY_IMPL = OSXJNAAffinity.INSTANCE;
66+
67+
} else if (osName.contains("SunOS") && isSolarisJNAAffinityUsable()) {
68+
LOGGER.trace("Using Solaris JNA-based thread id implementation");
69+
AFFINITY_IMPL = SolarisJNAAffinity.INSTANCE;
70+
71+
} else {
72+
LOGGER.info("Using dummy affinity control implementation");
73+
AFFINITY_IMPL = NullAffinity.INSTANCE;
74+
}
75+
}
76+
77+
public static IAffinity getAffinityImpl() {
78+
return AFFINITY_IMPL;
79+
}
80+
81+
private static boolean isWindowsJNAAffinityUsable() {
82+
if (isJNAAvailable()) {
83+
try {
84+
return WindowsJNAAffinity.LOADED;
85+
} catch (Throwable t) {
86+
logThrowable(t, "Windows JNA-based affinity not usable because it failed to load!");
87+
return false;
88+
}
89+
} else {
90+
LOGGER.warn("Windows JNA-based affinity not usable due to JNA not being available!");
91+
return false;
92+
}
93+
}
94+
95+
private static boolean isPosixJNAAffinityUsable() {
96+
if (isJNAAvailable()) {
97+
try {
98+
return PosixJNAAffinity.LOADED;
99+
} catch (Throwable t) {
100+
logThrowable(t, "Posix JNA-based affinity not usable because it failed to load!");
101+
return false;
102+
}
103+
} else {
104+
LOGGER.warn("Posix JNA-based affinity not usable due to JNA not being available!");
105+
return false;
106+
}
107+
}
108+
109+
private static boolean isLinuxJNAAffinityUsable() {
110+
if (isJNAAvailable()) {
111+
try {
112+
return LinuxJNAAffinity.LOADED;
113+
} catch (Throwable t) {
114+
logThrowable(t, "Linux JNA-based affinity not usable because it failed to load!");
115+
return false;
116+
}
117+
} else {
118+
LOGGER.warn("Linux JNA-based affinity not usable due to JNA not being available!");
119+
return false;
120+
}
121+
}
122+
123+
private static boolean isMacJNAAffinityUsable() {
124+
if (isJNAAvailable()) {
125+
return true;
126+
127+
} else {
128+
LOGGER.warn("MAX OSX JNA-based affinity not usable due to JNA not being available!");
129+
return false;
130+
}
131+
}
132+
133+
private static boolean isSolarisJNAAffinityUsable() {
134+
if (isJNAAvailable()) {
135+
return true;
136+
137+
} else {
138+
LOGGER.warn("Solaris JNA-based affinity not usable due to JNA not being available!");
139+
return false;
140+
}
141+
}
142+
143+
private static void logThrowable(Throwable t, String description) {
144+
StringWriter sw = new StringWriter();
145+
sw.append(description);
146+
sw.append(" Reason: ");
147+
t.printStackTrace(new PrintWriter(sw));
148+
LOGGER.warn(sw.toString());
149+
}
150+
151+
public static BitSet getAffinity() {
152+
return AFFINITY_IMPL.getAffinity();
153+
}
154+
155+
public static void setAffinity(final BitSet affinity) {
156+
AFFINITY_IMPL.setAffinity(affinity);
157+
}
158+
159+
public static void setAffinity(int cpu) {
160+
BitSet affinity = new BitSet(Runtime.getRuntime().availableProcessors());
161+
affinity.set(cpu);
162+
setAffinity(affinity);
163+
}
164+
165+
public static int getCpu() {
166+
return AFFINITY_IMPL.getCpu();
167+
}
168+
169+
public static int getThreadId() {
170+
return AFFINITY_IMPL.getThreadId();
171+
}
172+
173+
public static boolean isJNAAvailable() {
174+
if (JNAAvailable == null)
175+
try {
176+
Class.forName("com.sun.jna.Platform");
177+
JNAAvailable = true;
178+
} catch (ClassNotFoundException ignored) {
179+
JNAAvailable = false;
180+
}
181+
return JNAAvailable;
182+
}
183+
184+
public static AffinityLock acquireLock() {
185+
return isNonForkingAffinityAvailable() ? NonForkingAffinityLock.acquireLock() : AffinityLock.acquireLock();
186+
}
187+
188+
public static AffinityLock acquireCore() {
189+
return isNonForkingAffinityAvailable() ? NonForkingAffinityLock.acquireCore() : AffinityLock.acquireCore();
190+
}
191+
192+
public static AffinityLock acquireLock(boolean bind) {
193+
return isNonForkingAffinityAvailable() ? NonForkingAffinityLock.acquireLock(bind) : AffinityLock.acquireLock(bind);
194+
}
195+
196+
public static AffinityLock acquireCore(boolean bind) {
197+
return isNonForkingAffinityAvailable() ? NonForkingAffinityLock.acquireCore(bind) : AffinityLock.acquireCore(bind);
198+
}
199+
200+
private static boolean isNonForkingAffinityAvailable() {
201+
BootClassPath bootClassPath = BootClassPath.INSTANCE;
202+
return bootClassPath.has("java.lang.ThreadTrackingGroup") && bootClassPath.has("java.lang.ThreadLifecycleListener");
203+
}
204+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class AffinityLock implements Closeable {
4242
// TODO It seems like on virtualized platforms .availableProcessors() value can change at
4343
// TODO runtime. We should think about how to adopt to such change
4444
public static final int PROCESSORS = Runtime.getRuntime().availableProcessors();
45-
public static final BitSet BASE_AFFINITY = AffinitySupport.getAffinity();
45+
public static final BitSet BASE_AFFINITY = Affinity.getAffinity();
4646
public static final BitSet RESERVED_AFFINITY = getReservedAffinity0();
4747
private static final LockInventory LOCK_INVENTORY = new LockInventory(new NoCpuLayout(PROCESSORS));
4848

@@ -228,7 +228,7 @@ public void bind(boolean wholeCore) {
228228
{
229229
BitSet affinity = new BitSet();
230230
affinity.set(cpuId, true);
231-
AffinitySupport.setAffinity(affinity);
231+
Affinity.setAffinity(affinity);
232232
}
233233
}
234234

0 commit comments

Comments
 (0)