Skip to content

Commit 729907e

Browse files
AFFINITY-6 Factoring out static stuff from AffinityLock into a more reusable form
1 parent 1585ae6 commit 729907e

3 files changed

Lines changed: 228 additions & 171 deletions

File tree

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

Lines changed: 45 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
import java.io.File;
2525
import java.io.IOException;
26-
import java.util.NavigableMap;
27-
import java.util.TreeMap;
2826
import java.util.logging.Level;
2927
import java.util.logging.Logger;
3028

@@ -46,29 +44,12 @@ public class AffinityLock {
4644
public static final long BASE_AFFINITY = AffinitySupport.getAffinity();
4745
public static final long RESERVED_AFFINITY = getReservedAffinity0();
4846

49-
private static AffinityLock[] LOCKS;
50-
private static NavigableMap<Integer, AffinityLock[]> CORES; // set by cpuLayout()
51-
private static final AffinityLock NONE = new AffinityLock(-1, false, false);
52-
@NotNull
53-
private static CpuLayout cpuLayout = new NoCpuLayout(PROCESSORS);
47+
static final LockInventory LOCK_INVENTORY = new LockInventory(new NoCpuLayout(PROCESSORS));
5448

5549
static {
5650
try {
5751
if (new File("/proc/cpuinfo").exists()) {
5852
cpuLayout(VanillaCpuLayout.fromCpuInfo());
59-
} else {
60-
LOCKS = new AffinityLock[PROCESSORS];
61-
CORES = new TreeMap<Integer, AffinityLock[]>();
62-
for (int i = 0; i < PROCESSORS; i++) {
63-
AffinityLock al = LOCKS[i] = new AffinityLock(i, ((BASE_AFFINITY >> i) & 1) != 0, ((RESERVED_AFFINITY >> i) & 1) != 0);
64-
65-
final int layoutId = al.cpuId;
66-
int logicalCpuId = coreForId(layoutId);
67-
AffinityLock[] als = CORES.get(logicalCpuId);
68-
if (als == null)
69-
CORES.put(logicalCpuId, als = new AffinityLock[1]);
70-
als[cpuLayout.threadId(layoutId)] = al;
71-
}
7253
}
7354
} catch (IOException e) {
7455
LOGGER.log(Level.WARNING, "Unable to load /proc/cpuinfo", e);
@@ -84,49 +65,15 @@ public class AffinityLock {
8465
* @param cpuLayout for this application to use for this machine.
8566
*/
8667
public static void cpuLayout(@NotNull CpuLayout cpuLayout) {
87-
synchronized (AffinityLock.class) {
88-
if (cpuLayout.equals(AffinityLock.cpuLayout))
89-
return;
90-
AffinityLock.cpuLayout = cpuLayout;
91-
// System.out.println("Locks= " + cpuLayout.cpus());
92-
LOCKS = new AffinityLock[cpuLayout.cpus()];
93-
int threads = cpuLayout.threadsPerCore();
94-
CORES = new TreeMap<Integer, AffinityLock[]>();
95-
for (int i = 0; i < cpuLayout.cpus(); i++) {
96-
boolean base1 = ((BASE_AFFINITY >> i) & 1) != 0;
97-
boolean reservable1 = ((RESERVED_AFFINITY >> i) & 1) != 0;
98-
if (LOGGER.isLoggable(Level.FINE))
99-
LOGGER.fine("cpu " + i + " base= " + base1 + " reservable= " + reservable1);
100-
AffinityLock al = LOCKS[i] = new AffinityLock(i, base1, reservable1);
101-
final int layoutId = al.cpuId;
102-
int logicalCpuId = coreForId(layoutId);
103-
AffinityLock[] als = CORES.get(logicalCpuId);
104-
if (als == null)
105-
CORES.put(logicalCpuId, als = new AffinityLock[threads]);
106-
als[cpuLayout.threadId(layoutId)] = al;
107-
}
108-
}
109-
}
110-
111-
/**
112-
* Translate a layout id into a logical cpu id.
113-
* <p></p>
114-
* This translation is perform so that regardless of how
115-
*
116-
* @param id
117-
* @return
118-
*/
119-
120-
private static int coreForId(int id) {
121-
return cpuLayout.socketId(id) * cpuLayout.coresPerSocket() + cpuLayout.coreId(id);
68+
LOCK_INVENTORY.set(cpuLayout);
12269
}
12370

12471
/**
12572
* @return The current CpuLayout for the application.
12673
*/
12774
@NotNull
12875
public static CpuLayout cpuLayout() {
129-
return cpuLayout;
76+
return LOCK_INVENTORY.getCpuLayout();
13077
}
13178

13279
private static long getReservedAffinity0() {
@@ -187,42 +134,11 @@ public static AffinityLock acquireCore(boolean bind) {
187134
}
188135

189136
private static AffinityLock acquireLock(boolean bind, int cpuId, @NotNull AffinityStrategy... strategies) {
190-
synchronized (AffinityLock.class) {
191-
for (AffinityStrategy strategy : strategies) {
192-
// consider all processors except cpu 0 which is usually used by the OS.
193-
// if you have only one core, this library is not appropriate in any case.
194-
for (int i = LOCKS.length - 1; i > 0; i--) {
195-
AffinityLock al = LOCKS[i];
196-
if (al.canReserve() && (cpuId < 0 || strategy.matches(cpuId, al.cpuId))) {
197-
al.assignCurrentThread(bind, false);
198-
return al;
199-
}
200-
}
201-
}
202-
}
203-
if (LOGGER.isLoggable(Level.WARNING))
204-
LOGGER.warning("No reservable CPU for " + Thread.currentThread());
205-
return AffinityLock.NONE;
137+
return LOCK_INVENTORY.acquireLock(bind, cpuId, strategies);
206138
}
207139

208140
private static AffinityLock acquireCore(boolean bind, int cpuId, @NotNull AffinityStrategy... strategies) {
209-
synchronized (AffinityLock.class) {
210-
for (AffinityStrategy strategy : strategies) {
211-
LOOP:
212-
for (AffinityLock[] als : CORES.descendingMap().values()) {
213-
for (AffinityLock al : als)
214-
if (!al.canReserve() || !strategy.matches(cpuId, al.cpuId))
215-
continue LOOP;
216-
217-
final AffinityLock al = als[0];
218-
al.assignCurrentThread(bind, true);
219-
return al;
220-
}
221-
}
222-
}
223-
if (LOGGER.isLoggable(Level.WARNING))
224-
LOGGER.warning("No reservable Core for " + Thread.currentThread());
225-
return acquireLock(bind, cpuId, strategies);
141+
return LOCK_INVENTORY.acquireCore(bind, cpuId, strategies);
226142
}
227143

228144

@@ -231,37 +147,37 @@ private static AffinityLock acquireCore(boolean bind, int cpuId, @NotNull Affini
231147
*/
232148
@NotNull
233149
public static String dumpLocks() {
234-
return dumpLocks0(LOCKS);
235-
}
236-
237-
@NotNull
238-
static String dumpLocks0(@NotNull AffinityLock[] locks) {
239-
StringBuilder sb = new StringBuilder();
240-
for (int i = 0; i < locks.length; i++) {
241-
AffinityLock al = locks[i];
242-
sb.append(i).append(": ");
243-
if (al.assignedThread != null)
244-
sb.append(al.assignedThread).append(" alive=").append(al.assignedThread.isAlive());
245-
else if (al.reservable)
246-
sb.append("Reserved for this application");
247-
else if (al.base)
248-
sb.append("General use CPU");
249-
else
250-
sb.append("CPU not available");
251-
sb.append('\n');
252-
}
253-
return sb.toString();
150+
return LOCK_INVENTORY.dumpLocks();
254151
}
255152

256-
//// Non static fields and methods.
153+
/**
154+
* Logical ID of the CPU to which this lock belongs to.
155+
*/
257156
private final int cpuId;
157+
158+
/**
159+
* CPU to which this lock belongs to is of general use.
160+
*/
258161
private final boolean base;
162+
163+
/**
164+
* CPU to which this lock belongs to is reservable.
165+
*/
259166
private final boolean reservable;
167+
168+
/**
169+
* An inventory build from the CPU layout which keeps track of the various locks
170+
* belonging to each CPU.
171+
*/
172+
private final LockInventory lockInventory;
173+
260174
boolean bound = false;
175+
261176
@Nullable
262177
Thread assignedThread;
263178

264-
AffinityLock(int cpuId, boolean base, boolean reservable) {
179+
AffinityLock(int cpuId, boolean base, boolean reservable, LockInventory lockInventory) {
180+
this.lockInventory = lockInventory;
265181
this.cpuId = cpuId;
266182
this.base = base;
267183
this.reservable = reservable;
@@ -273,7 +189,7 @@ else if (al.base)
273189
* @param bind whether to bind the thread as well
274190
* @param wholeCore whether to reserve all the thread in the same core.
275191
*/
276-
private void assignCurrentThread(boolean bind, boolean wholeCore) {
192+
final void assignCurrentThread(boolean bind, boolean wholeCore) {
277193
assignedThread = Thread.currentThread();
278194
if (bind)
279195
bind(wholeCore);
@@ -296,25 +212,7 @@ public void bind(boolean wholeCore) {
296212
throw new IllegalStateException("cpu " + cpuId + " already bound to " + assignedThread);
297213

298214
if (wholeCore) {
299-
int core = coreForId(cpuId);
300-
for (AffinityLock al : CORES.get(core)) {
301-
if (bound && al.assignedThread != null && al.assignedThread.isAlive()) {
302-
LOGGER.severe("cpu " + al.cpuId + " already bound to " + al.assignedThread);
303-
} else {
304-
al.bound = true;
305-
al.assignedThread = Thread.currentThread();
306-
}
307-
}
308-
if (LOGGER.isLoggable(Level.INFO)) {
309-
StringBuilder sb = new StringBuilder().append("Assigning core ").append(core);
310-
String sep = ": cpus ";
311-
for (AffinityLock al : CORES.get(core)) {
312-
sb.append(sep).append(al.cpuId);
313-
sep = ", ";
314-
}
315-
sb.append(" to ").append(assignedThread);
316-
LOGGER.info(sb.toString());
317-
}
215+
lockInventory.bindWhileCore(cpuId);
318216
} else if (cpuId >= 0) {
319217
bound = true;
320218
assignedThread = Thread.currentThread();
@@ -325,7 +223,7 @@ public void bind(boolean wholeCore) {
325223
AffinitySupport.setAffinity(1L << cpuId);
326224
}
327225

328-
private boolean canReserve() {
226+
final boolean canReserve() {
329227
if (!reservable) return false;
330228
if (assignedThread != null) {
331229
if (assignedThread.isAlive()) return false;
@@ -351,23 +249,7 @@ public AffinityLock acquireLock(AffinityStrategy... strategies) {
351249
* Release the current AffinityLock which can be discarded.
352250
*/
353251
public void release() {
354-
Thread t = Thread.currentThread();
355-
synchronized (AffinityLock.class) {
356-
for (AffinityLock al : LOCKS) {
357-
Thread at = al.assignedThread;
358-
if (at == t) {
359-
if (LOGGER.isLoggable(Level.INFO))
360-
LOGGER.info("Releasing cpu " + al.cpuId + " from " + t);
361-
al.assignedThread = null;
362-
al.bound = false;
363-
} else if (at != null && !at.isAlive()) {
364-
LOGGER.warning("Releasing cpu " + al.cpuId + " from " + t + " as it is not alive.");
365-
al.assignedThread = null;
366-
al.bound = false;
367-
}
368-
}
369-
}
370-
AffinitySupport.setAffinity(BASE_AFFINITY);
252+
lockInventory.release();
371253
}
372254

373255
@Override
@@ -399,4 +281,18 @@ public boolean isAllocated() {
399281
public boolean isBound() {
400282
return bound;
401283
}
284+
285+
@Override
286+
public String toString() {
287+
StringBuilder sb = new StringBuilder();
288+
if (assignedThread != null)
289+
sb.append(assignedThread).append(" alive=").append(assignedThread.isAlive());
290+
else if (reservable)
291+
sb.append("Reserved for this application");
292+
else if (base)
293+
sb.append("General use CPU");
294+
else
295+
sb.append("CPU not available");
296+
return sb.toString();
297+
}
402298
}

0 commit comments

Comments
 (0)