Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 48 additions & 49 deletions src/main/java/ca/spottedleaf/concurrentutil/numa/LinuxNuma.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,76 +32,75 @@ public final class LinuxNuma extends OSNuma.PreCalculatedNuma {
}
public static final LinuxNuma INSTANCE;
static {
if (!LIBRARIES_AVAILABLE) {
INSTANCE = null;
} else {
LinuxNuma instance = null;
if (LIBRARIES_AVAILABLE) {
final int totalNumaNodes = LibNuma.numa_max_node() + 1;

final Pointer cpuMask = LibNuma.numa_allocate_cpumask();
try {
if (cpuMask == null) {
INSTANCE = null;
LOGGER.debug("Failed to create Linux NUMA CPU mapping: Failed to allocate cpu mask for libnuma");
} else {
if (cpuMask != null) {
final int totalCpus = LibNuma.numa_num_possible_cpus();
if (totalCpus > 0) {
final int[] coreToNuma = new int[totalCpus];
Arrays.fill(coreToNuma, -1);

boolean ok = true;
for (int node = 0; node < totalNumaNodes; ++node) {
LibNuma.numa_bitmask_clearall(cpuMask);
final int res = LibNuma.numa_node_to_cpus(node, cpuMask);
if (res != 0) {
ok = false;
break;
}

int[] coreToNuma = new int[totalCpus];
Arrays.fill(coreToNuma, -1);
core_to_numa_setup:
for (int node = 0; node < totalNumaNodes; ++node) {
LibNuma.numa_bitmask_clearall(cpuMask);
final int res = LibNuma.numa_node_to_cpus(node, cpuMask);
if (res != 0) {
// failed
LOGGER.debug("Failed to create Linux NUMA CPU mapping: Failed libnuma numa_node_to_cpus(" + node + ", ...): " + res);
coreToNuma = null;
break;
}

for (int cpu = 0; cpu < totalCpus; ++cpu) {
final int bit = LibNuma.numa_bitmask_isbitset(cpuMask, cpu);
if (bit == 0) {
// not set
continue;
for (int cpu = 0; cpu < totalCpus; ++cpu) {
final int bit = LibNuma.numa_bitmask_isbitset(cpuMask, cpu);
if (bit == 0) {
continue;
}
if (coreToNuma[cpu] != -1) {
ok = false;
break;
}
if (coreToNuma.length <= cpu) {
coreToNuma = Arrays.copyOf(coreToNuma, cpu + 1);
}
coreToNuma[cpu] = node;
}
if (coreToNuma[cpu] != -1) {
LOGGER.debug("Failed to create Linux NUMA CPU mapping: Duplicate node mapping for core " + cpu + ": " + coreToNuma[cpu] + " and " + node);
coreToNuma = null;
break core_to_numa_setup;
if (!ok) {
break;
}
// it is set, so mark it in the core mapping
coreToNuma[cpu] = node;
}
}
if (coreToNuma != null) {
for (int cpu = 0; cpu < coreToNuma.length; ++cpu) {
final int node = coreToNuma[cpu];
if (node == -1) {
LOGGER.debug("Failed to create Linux NUMA CPU mapping: No node mapping for core " + cpu);
coreToNuma = null;
break;

if (ok) {
for (int cpu = 0; cpu < coreToNuma.length; ++cpu) {
if (coreToNuma[cpu] == -1) {
ok = false;
break;
}
}
}
}

final int[][] costArray = new int[totalNumaNodes][totalNumaNodes];
for (int i = 0; i < totalNumaNodes; ++i) {
for (int j = 0; j < totalNumaNodes; ++j) {
final int dist = LibNuma.numa_distance(i, j);
// distance is 0 when it cannot be determined
// distances 1-9 are reserved and have no meaning
costArray[i][j] = dist < 10 ? OSNuma.NUMA_DISTANCE_CANNOT_DETERMINE : dist;
if (ok) {
final int[][] costArray = new int[totalNumaNodes][totalNumaNodes];
for (int i = 0; i < totalNumaNodes; ++i) {
for (int j = 0; j < totalNumaNodes; ++j) {
final int dist = LibNuma.numa_distance(i, j);
costArray[i][j] = dist <= 0 ? 255 : dist;
}
}

instance = new LinuxNuma(coreToNuma, costArray);
}
}

INSTANCE = coreToNuma == null ? null : new LinuxNuma(coreToNuma, costArray);
}
} finally {
if (cpuMask != null) {
LibNuma.numa_bitmask_free(cpuMask);
}
}
}
INSTANCE = instance;
}

private LinuxNuma(final int[] coreToNuma, final int[][] costArray) {
Expand Down
22 changes: 18 additions & 4 deletions src/main/java/ca/spottedleaf/concurrentutil/numa/OSNuma.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ public default void setCurrentNumaAffinity(final long[] to) {
public default void setCurrentNumaAffinity(final int[] numaNodes) {
final IntArrayList cores = new IntArrayList();
for (final int node : numaNodes) {
cores.addAll(IntArrayList.wrap(this.getCores(node)));
final int[] nodeCores = this.getCores(node);
if (nodeCores == null) {
throw new IllegalArgumentException("Unknown NUMA node: " + node);
}
cores.addAll(IntArrayList.wrap(nodeCores));
}

this.setCurrentThreadAffinity(FlatBitsetUtil.intsToBitset(cores.toIntArray()));
Expand All @@ -153,7 +157,12 @@ public PreCalculatedNuma(final int[] coreToNuma, final int[][] costArray) {
}

for (int core = 0; core < coreToNuma.length; ++core) {
numaToCore[coreToNuma[core]].add(core);
final int node = coreToNuma[core];
if (node < 0 || node >= numaToCore.length) {
// unknown mapping, ignore
continue;
}
numaToCore[node].add(core);
}

this.numaToCore = new int[this.costArray.length][];
Expand Down Expand Up @@ -197,7 +206,12 @@ public int getNumaNode(final int coreId) {
// cannot determine
return -1;
}
return this.coreToNuma[coreId];
final int node = this.coreToNuma[coreId];
if (node < 0 || node >= this.costArray.length) {
// cannot determine
return -1;
}
return node;
}

@Override
Expand All @@ -216,7 +230,7 @@ public int[] getCores(final int numaId) {

@Override
public int getCurrentNumaNode() {
return this.coreToNuma[this.getCurrentCore()];
return this.getNumaNode(this.getCurrentCore());
}
}

Expand Down