Skip to content

Commit 82b9818

Browse files
Marcus SorensenMarcus Sorensen
andauthored
KVM Agent config to reserve dom0 CPUs (#7987)
This PR allows an admin to reserve some hypervisor host CPUs for system use. Another way to think of it is limiting the number of CPUs allocatable to VMs. This can be useful if the admin wants to do other things with the hypervisor's CPU, for example reserve some cores for running hyperconverged storage processes. Co-authored-by: Marcus Sorensen <mls@apple.com>
1 parent 4c59dea commit 82b9818

File tree

5 files changed

+64
-8
lines changed

5 files changed

+64
-8
lines changed

agent/conf/agent.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ hypervisor.type=kvm
279279
# If this parameter is used, property host.overcommit.mem.mb must be set to 0.
280280
#host.reserved.mem.mb=1024
281281

282+
# Number of CPU cores to subtract from advertised available cores.
283+
# These are reserved for system activity, or otherwise share host CPU resources with
284+
# CloudStack VM allocation.
285+
# host.reserved.cpu.count = 0
286+
282287
# The model of Watchdog timer to present to the Guest.
283288
# For all models refer to the libvirt documentation.
284289
#vm.watchdog.model=i6300esb

agent/src/main/java/com/cloud/agent/properties/AgentProperties.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,15 @@ public class AgentProperties{
502502
*/
503503
public static final Property<Integer> HOST_RESERVED_MEM_MB = new Property<>("host.reserved.mem.mb", 1024);
504504

505+
/**
506+
* How many host CPUs to reserve for non-allocation.<br>
507+
* This can be used to set aside CPU cores on the host for other tasks, such as running hyperconverged storage<br>
508+
* processes, etc.
509+
* Data type: Integer.<br>
510+
* Default value: <code>0</code>
511+
*/
512+
public static final Property<Integer> HOST_RESERVED_CPU_CORE_COUNT = new Property<>("host.reserved.cpu.count", 0);
513+
505514
/**
506515
* The model of Watchdog timer to present to the Guest.<br>
507516
* For all models refer to the libvirt documentation.<br>

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
460460

461461
private long dom0OvercommitMem;
462462

463+
private int dom0MinCpuCores;
464+
463465
protected int cmdsTimeout;
464466
protected int stopTimeout;
465467
protected CPUStat cpuStat = new CPUStat();
@@ -1063,6 +1065,8 @@ public boolean configure(final String name, final Map<String, Object> params) th
10631065
// Reserve 1GB unless admin overrides
10641066
dom0MinMem = ByteScaleUtils.mebibytesToBytes(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HOST_RESERVED_MEM_MB));
10651067

1068+
dom0MinCpuCores = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HOST_RESERVED_CPU_CORE_COUNT);
1069+
10661070
// Support overcommit memory for host if host uses ZSWAP, KSM and other memory
10671071
// compressing technologies
10681072
dom0OvercommitMem = ByteScaleUtils.mebibytesToBytes(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HOST_OVERCOMMIT_MEM_MB));
@@ -3540,15 +3544,15 @@ private Map<String, String> getVersionStrings() {
35403544
@Override
35413545
public StartupCommand[] initialize() {
35423546

3543-
final KVMHostInfo info = new KVMHostInfo(dom0MinMem, dom0OvercommitMem, manualCpuSpeed);
3547+
final KVMHostInfo info = new KVMHostInfo(dom0MinMem, dom0OvercommitMem, manualCpuSpeed, dom0MinCpuCores);
35443548

35453549
String capabilities = String.join(",", info.getCapabilities());
35463550
if (dpdkSupport) {
35473551
capabilities += ",dpdk";
35483552
}
35493553

35503554
final StartupRoutingCommand cmd =
3551-
new StartupRoutingCommand(info.getCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, hypervisorType,
3555+
new StartupRoutingCommand(info.getAllocatableCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, hypervisorType,
35523556
RouterPrivateIpStrategy.HostLocal);
35533557
cmd.setCpuSockets(info.getCpuSockets());
35543558
fillNetworkInformation(cmd);

plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public class KVMHostInfo {
4848

4949
private static final Logger LOGGER = Logger.getLogger(KVMHostInfo.class);
5050

51-
private int cpus;
51+
private int totalCpus;
52+
private int allocatableCpus;
5253
private int cpusockets;
5354
private long cpuSpeed;
5455
private long totalMemory;
@@ -58,16 +59,25 @@ public class KVMHostInfo {
5859

5960
private static String cpuInfoFreqFileName = "/sys/devices/system/cpu/cpu0/cpufreq/base_frequency";
6061

61-
public KVMHostInfo(long reservedMemory, long overCommitMemory, long manualSpeed) {
62+
public KVMHostInfo(long reservedMemory, long overCommitMemory, long manualSpeed, int reservedCpus) {
6263
this.cpuSpeed = manualSpeed;
6364
this.reservedMemory = reservedMemory;
6465
this.overCommitMemory = overCommitMemory;
6566
this.getHostInfoFromLibvirt();
6667
this.totalMemory = new MemStat(this.getReservedMemory(), this.getOverCommitMemory()).getTotal();
68+
this.allocatableCpus = totalCpus - reservedCpus;
69+
if (allocatableCpus < 1) {
70+
LOGGER.warn(String.format("Aggressive reserved CPU config leaves no usable CPUs for VMs! Total system CPUs: %d, Reserved: %d, Allocatable: %d", totalCpus, reservedCpus, allocatableCpus));
71+
allocatableCpus = 0;
72+
}
73+
}
74+
75+
public int getTotalCpus() {
76+
return this.totalCpus;
6777
}
6878

69-
public int getCpus() {
70-
return this.cpus;
79+
public int getAllocatableCpus() {
80+
return this.allocatableCpus;
7181
}
7282

7383
public int getCpuSockets() {
@@ -189,7 +199,7 @@ private void getHostInfoFromLibvirt() {
189199
if (hosts.nodes > 0) {
190200
this.cpusockets = hosts.sockets * hosts.nodes;
191201
}
192-
this.cpus = hosts.cpus;
202+
this.totalCpus = hosts.cpus;
193203

194204
final LibvirtCapXMLParser parser = new LibvirtCapXMLParser();
195205
parser.parseCapabilitiesXML(capabilities);

plugins/hypervisors/kvm/src/test/java/org/apache/cloudstack/utils/linux/KVMHostInfoTest.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,36 @@ public void manualCpuSpeedTest() throws Exception {
7373
Mockito.when(conn.close()).thenReturn(0);
7474
int manualSpeed = 500;
7575

76-
KVMHostInfo kvmHostInfo = new KVMHostInfo(10, 10, manualSpeed);
76+
KVMHostInfo kvmHostInfo = new KVMHostInfo(10, 10, manualSpeed, 0);
7777
Assert.assertEquals(kvmHostInfo.getCpuSpeed(), manualSpeed);
7878
}
7979
}
80+
81+
@Test
82+
public void reservedCpuCoresTest() throws Exception {
83+
if (!System.getProperty("os.name").equals("Linux")) {
84+
return;
85+
}
86+
try (MockedStatic<LibvirtConnection> ignored = Mockito.mockStatic(LibvirtConnection.class)) {
87+
Connect conn = Mockito.mock(Connect.class);
88+
NodeInfo nodeInfo = Mockito.mock(NodeInfo.class);
89+
nodeInfo.cpus = 10;
90+
String capabilitiesXml = "<capabilities></capabilities>";
91+
92+
Mockito.when(LibvirtConnection.getConnection()).thenReturn(conn);
93+
Mockito.when(conn.nodeInfo()).thenReturn(nodeInfo);
94+
Mockito.when(conn.getCapabilities()).thenReturn(capabilitiesXml);
95+
Mockito.when(conn.close()).thenReturn(0);
96+
int manualSpeed = 500;
97+
98+
KVMHostInfo kvmHostInfo = new KVMHostInfo(10, 10, 100, 2);
99+
Assert.assertEquals("reserve two CPU cores", 8, kvmHostInfo.getAllocatableCpus());
100+
101+
kvmHostInfo = new KVMHostInfo(10, 10, 100, 0);
102+
Assert.assertEquals("no reserve CPU core setting", 10, kvmHostInfo.getAllocatableCpus());
103+
104+
kvmHostInfo = new KVMHostInfo(10, 10, 100, 12);
105+
Assert.assertEquals("Misconfigured/too large CPU reserve", 0, kvmHostInfo.getAllocatableCpus());
106+
}
107+
}
80108
}

0 commit comments

Comments
 (0)