/*
* Copyright 2011 Peter Lawrey
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vanilla.java.affinity.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.jna.LastErrorException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
/**
* Implementation of IAffinity based on JNA call of
* sched_setaffinity(3)/sched_getaffinity(3) from 'c' library. Applicable for most
* linux/unix platforms
* <p/>
* TODO Support assignment to core 64 and above
*
* @author peter.lawrey
* @author BegemoT
*/
public enum PosixJNAAffinity {
INSTANCE;
private static final Logger LOGGER = Logger.getLogger(PosixJNAAffinity.class.getName());
public static final boolean LOADED;
private static final String LIBRARY_NAME = Platform.isWindows() ? "msvcrt" : "c";
/**
* @author BegemoT
*/
private interface CLibrary extends Library {
public static final CLibrary INSTANCE = (CLibrary)
Native.loadLibrary(LIBRARY_NAME, CLibrary.class);
public int sched_setaffinity(final int pid,
final int cpusetsize,
final long[] cpuset) throws LastErrorException;
public int sched_getaffinity(final int pid,
final int cpusetsize,
final long[] cpuset) throws LastErrorException;
}
static {
boolean loaded = false;
try {
INSTANCE.getAffinity();
loaded = true;
} catch (UnsatisfiedLinkError e) {
LOGGER.log(Level.WARNING, "Unable to load jna library " + e);
}
LOADED = loaded;
}
public long getAffinity() {
final CLibrary lib = CLibrary.INSTANCE;
// TODO where are systems with 64+ cores...
final long cpuset[] = new long[16];
try {
final int ret = lib.sched_getaffinity(0, 16 * (Long.SIZE / 8), cpuset);
if (ret < 0)
throw new IllegalStateException("sched_getaffinity((" + Long.SIZE / 8 + ") , &(" + cpuset + ") ) return " + ret);
return cpuset[0];
} catch (LastErrorException e) {
throw new IllegalStateException("sched_getaffinity((" + Long.SIZE / 8 + ") , &(" + cpuset + ") ) errorNo=" + e.getErrorCode(), e);
}
}
public void setAffinity(final String affinityString) {
Set<Integer> cores = new HashSet<Integer>();
for (String affinity : affinityString.split(":")) {
String affinityRange[] = affinity.split("-");
if (affinityRange.length == 1) {
cores.add(Integer.valueOf(affinityRange[0]));
} else {
/*
* For hyper threading, skip every other thread. God help you
* if you have more than two threads per core
*/
boolean skipEveryOther = false;
if (affinityRange[0].startsWith("!")) {
affinityRange[0] = affinityRange[0].substring(1, affinityRange[0].length());
skipEveryOther = true;
}
int rangeStart = Integer.valueOf(affinityRange[0]);
int rangeEnd = Integer.valueOf(affinityRange[1]);
if (rangeEnd < rangeStart) {
throw new IllegalArgumentException();
}
for (int ii = rangeStart; ii <= rangeEnd; ii++) {
if (skipEveryOther) {
/*
* If the start of the range is even, skip the odd values
*/
if (rangeStart % 2 == 0 && ii % 2 == 1) {
continue;
}
/*
* If the start was odd, skip the even values
*/
if (rangeStart % 2 == 1 && ii % 2 == 0) {
continue;
}
}
cores.add(ii);
}
}
}
long mask = 0;
for (Integer core : cores) {
mask |= 1L << core;
}
System.out.println("Thread (" + Thread.currentThread().getName() + ") setting affinity to " + cores);
setAffinity(mask);
}
public void setAffinity(final long affinity) {
final CLibrary lib = CLibrary.INSTANCE;
try {
//fixme: where are systems with more then 64 cores...
long affinityMask[] = new long[16];
affinityMask[0] = affinity;
final int ret = lib.sched_setaffinity(0, 16 * (Long.SIZE / 8), affinityMask);
if (ret < 0) {
throw new IllegalStateException("sched_setaffinity((" + Long.SIZE / 8 + ") , &(" + affinity + ") ) return " + ret);
}
} catch (LastErrorException e) {
throw new IllegalStateException("sched_getaffinity((" + Long.SIZE / 8 + ") , &(" + affinity + ") ) errorNo=" + e.getErrorCode(), e);
}
}
}