2323
2424import java .io .File ;
2525import java .io .IOException ;
26- import java .util .NavigableMap ;
27- import java .util .TreeMap ;
2826import java .util .logging .Level ;
2927import 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