package org.ovirt.engine.core.bll.scheduling.utils;
import static java.util.Objects.requireNonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class CpuPinningHelper {
private static Collection<Integer> parsePCpuPinningNumbers(final String text) {
try {
HashSet<Integer> include = new HashSet<>();
HashSet<Integer> exclude = new HashSet<>();
String[] splitText = text.split(",");
for (String section : splitText) {
if (section.startsWith("^")) {
exclude.add(Integer.parseInt(section.substring(1)));
} else if (section.contains("-")) {
// include range
String[] numbers = section.split("-");
int start = Integer.parseInt(numbers[0]);
int end = Integer.parseInt(numbers[1]);
List<Integer> range = createRange(start, end);
if (range != null) {
include.addAll(range);
} else {
return Arrays.asList();
}
} else {
// include one
include.add(Integer.parseInt(section));
}
}
include.removeAll(exclude);
return include;
} catch (NumberFormatException ex) {
return Arrays.asList();
}
}
/**
* Find out which host cpus are pinned to virtual cpus
* @param cpuPinning cpu pinning rules string
* @return a set of all used host cpus
*/
public static Set<Integer> getAllPinnedPCpus(String cpuPinning) {
// collect all pinned cpus and merge them into one set
final Set<Integer> pinnedCpus = new LinkedHashSet<>();
for (final String rule : cpuPinning.split("_")) {
pinnedCpus.addAll(CpuPinningHelper.parsePCpuPinningNumbers(rule.split("#")[1]));
}
return pinnedCpus;
}
/**
* Parse the provided cpu pinning rules and return the parsed rules
* @param cpuPinning cpu pinning rules string
* @return a list containing virtual cpu to host cpu associations
*/
public static List<PinnedCpu> parseCpuPinning(final String cpuPinning) {
final List<PinnedCpu> rules = new ArrayList<>();
for (final String rule : cpuPinning.split("_")) {
String[] splitRule = rule.split("#");
Collection<Integer> pCpus = parsePCpuPinningNumbers(splitRule[1]);
rules.add(new PinnedCpu(Integer.parseInt(splitRule[0]), pCpus));
}
return rules;
}
private static List<Integer> createRange(int start, int end) {
if (start >= 0 && start < end) {
List<Integer> returnList = new LinkedList<>();
for (int i = start; i <= end; i++) {
returnList.add(i);
}
return returnList;
} else {
return null;
}
}
/**
* Represents the association between a virtual CPU in a VM to the bare metal cpu threads on a host
*/
public static class PinnedCpu {
private Integer vCpu;
private Collection<Integer> pCpus;
protected PinnedCpu(Integer vCpu, Collection<Integer> pCpus) {
this.vCpu = requireNonNull(vCpu);
this.pCpus = requireNonNull(pCpus);
}
/**
* Get the virtual cpu which is associated with the host cpu threads in this class
* @return the virtual cpu
*/
public Integer getvCpu() {
return vCpu;
}
/**
* Get host cpu threads which are associated with the virtual cpu in this class
* @return list of associated host cpu thread
*/
public Collection<Integer> getpCpus() {
return pCpus;
}
}
}