@@ -20,7 +20,6 @@ import (
20
20
"os/signal"
21
21
"path/filepath"
22
22
"regexp"
23
- "strconv"
24
23
"strings"
25
24
"sync"
26
25
"sync/atomic"
@@ -612,10 +611,10 @@ type Config struct {
612
611
kernelPath string
613
612
appendKernelCmdline string
614
613
skipCgroupManagement bool
615
- enableDummyCPUServer bool
616
614
diskCacheSettings string
617
615
memoryProvider vmv1.MemoryProvider
618
616
autoMovableRatio string
617
+ cpuScalingMode string
619
618
}
620
619
621
620
func newConfig (logger * zap.Logger ) * Config {
@@ -625,10 +624,10 @@ func newConfig(logger *zap.Logger) *Config {
625
624
kernelPath : defaultKernelPath ,
626
625
appendKernelCmdline : "" ,
627
626
skipCgroupManagement : false ,
628
- enableDummyCPUServer : false ,
629
627
diskCacheSettings : "cache=none" ,
630
628
memoryProvider : "" , // Require that this is explicitly set. We'll check later.
631
629
autoMovableRatio : "" , // Require that this is explicitly set IFF memoryProvider is VirtioMem. We'll check later.
630
+ cpuScalingMode : "" , // Require that this is explicitly set. We'll check later.
632
631
}
633
632
flag .StringVar (& cfg .vmSpecDump , "vmspec" , cfg .vmSpecDump ,
634
633
"Base64 encoded VirtualMachine json specification" )
@@ -641,14 +640,12 @@ func newConfig(logger *zap.Logger) *Config {
641
640
flag .BoolVar (& cfg .skipCgroupManagement , "skip-cgroup-management" ,
642
641
cfg .skipCgroupManagement ,
643
642
"Don't try to manage CPU" )
644
- flag .BoolVar (& cfg .enableDummyCPUServer , "enable-dummy-cpu-server" ,
645
- cfg .skipCgroupManagement ,
646
- "Use with -skip-cgroup-management. Provide a CPU server but don't actually do anything with it" )
647
643
flag .StringVar (& cfg .diskCacheSettings , "qemu-disk-cache-settings" ,
648
644
cfg .diskCacheSettings , "Cache settings to add to -drive args for VM disks" )
649
645
flag .Func ("memory-provider" , "Set provider for memory hotplug" , cfg .memoryProvider .FlagFunc )
650
646
flag .StringVar (& cfg .autoMovableRatio , "memhp-auto-movable-ratio" ,
651
647
cfg .autoMovableRatio , "Set value of kernel's memory_hotplug.auto_movable_ratio [virtio-mem only]" )
648
+ flag .StringVar (& cfg .cpuScalingMode , "cpu-scaling-mode" , "" , "Set CPU scaling mode" )
652
649
flag .Parse ()
653
650
654
651
if cfg .memoryProvider == "" {
@@ -657,8 +654,8 @@ func newConfig(logger *zap.Logger) *Config {
657
654
if cfg .memoryProvider == vmv1 .MemoryProviderVirtioMem && cfg .autoMovableRatio == "" {
658
655
logger .Fatal ("missing required flag '-memhp-auto-movable-ratio'" )
659
656
}
660
- if cfg .enableDummyCPUServer && ! cfg . skipCgroupManagement {
661
- logger .Fatal ("flag -enable-dummy- cpu-server requires -skip-cgroup-management " )
657
+ if cfg .cpuScalingMode == "" {
658
+ logger .Fatal ("missing required flag '- cpu-scaling-mode' " )
662
659
}
663
660
664
661
return cfg
@@ -894,22 +891,26 @@ func buildQEMUCmd(
894
891
maxCPUs := vmSpec .Guest .CPUs .Max .RoundedUp ()
895
892
minCPUs := vmSpec .Guest .CPUs .Min .RoundedUp ()
896
893
897
- if vmSpec . CpuScalingMode != nil && * vmSpec . CpuScalingMode == vmv1 . CpuScalingModeCpuSysfsState {
898
- // if we use sysfs based scaling we specify start cpus equal to max cpus
894
+ switch cfg . cpuScalingMode {
895
+ case vmv1 . CpuScalingModeSysfs :
899
896
qemuCmd = append (qemuCmd , "-smp" , fmt .Sprintf (
897
+ // if we use sysfs based scaling we specify initial value for cpus qemu arg equal to max cpus
900
898
"cpus=%d,maxcpus=%d,sockets=1,cores=%d,threads=1" ,
901
899
maxCPUs ,
902
900
maxCPUs ,
903
901
maxCPUs ,
904
902
))
905
- } else {
906
- // if we use hotplug we specify start cpus equal to min cpus and scale using udev rules for cpu plug events
903
+ case vmv1 . CpuScalingModeQMP :
904
+ // if we use hotplug we specify initial value for cpus qemu arg equal to min cpus and scale using udev rules for cpu plug events
907
905
qemuCmd = append (qemuCmd , "-smp" , fmt .Sprintf (
908
906
"cpus=%d,maxcpus=%d,sockets=1,cores=%d,threads=1" ,
909
907
minCPUs ,
910
908
maxCPUs ,
911
909
maxCPUs ,
912
910
))
911
+ default :
912
+ // we should never get here because we validate the flag in newConfig
913
+ panic (fmt .Errorf ("unknown CPU scaling mode %s" , cfg .cpuScalingMode ))
913
914
}
914
915
915
916
// memory details
@@ -998,8 +999,8 @@ func makeKernelCmdline(cfg *Config, vmSpec *vmv1.VirtualMachineSpec, vmStatus *v
998
999
if cfg .appendKernelCmdline != "" {
999
1000
cmdlineParts = append (cmdlineParts , cfg .appendKernelCmdline )
1000
1001
}
1001
- if vmSpec . CpuScalingMode != nil && * vmSpec . CpuScalingMode == vmv1 .CpuScalingModeCpuSysfsState {
1002
- // if we use sysfs based scaling we need to specify the start cpus as min CPUs
1002
+ if cfg . cpuScalingMode == vmv1 .CpuScalingModeSysfs {
1003
+ // if we use sysfs based scaling we need to specify the start cpus as min CPUs to mark every CPU except 0 as offline
1003
1004
cmdlineParts = append (cmdlineParts , fmt .Sprintf ("maxcpus=%d" , vmSpec .Guest .CPUs .Min .RoundedUp ()))
1004
1005
}
1005
1006
@@ -1048,44 +1049,28 @@ func runQEMU(
1048
1049
wg := sync.WaitGroup {}
1049
1050
1050
1051
wg .Add (1 )
1051
- useCpuSysfsStateScaling := false
1052
- if vmSpec .CpuScalingMode != nil && * vmSpec .CpuScalingMode == vmv1 .CpuScalingModeCpuSysfsState {
1053
- useCpuSysfsStateScaling = true
1054
- }
1055
1052
go terminateQemuOnSigterm (ctx , logger , & wg )
1056
- if ! cfg .skipCgroupManagement || cfg .enableDummyCPUServer || useCpuSysfsStateScaling {
1053
+ if ! cfg .skipCgroupManagement || cfg .cpuScalingMode == vmv1 . CpuScalingModeSysfs {
1057
1054
var callbacks cpuServerCallbacks
1058
1055
1059
- if cfg .enableDummyCPUServer {
1060
- lastValue := & atomic.Uint32 {}
1061
- lastValue .Store (uint32 (vmSpec .Guest .CPUs .Min ))
1062
-
1063
- callbacks = cpuServerCallbacks {
1064
- get : func (logger * zap.Logger ) (* vmv1.MilliCPU , error ) {
1065
- return lo .ToPtr (vmv1 .MilliCPU (lastValue .Load ())), nil
1066
- },
1067
- set : func (logger * zap.Logger , cpu vmv1.MilliCPU ) error {
1068
- if useCpuSysfsStateScaling {
1069
- err := setNeonvmDaemonCPU (cpu )
1070
- if err != nil {
1071
- logger .Error ("setting CPU through NeonVM Daemon failed" , zap .Any ("cpu" , cpu ), zap .Error (err ))
1072
- return err
1073
- }
1056
+ lastValue := & atomic.Uint32 {}
1057
+ lastValue .Store (uint32 (vmSpec .Guest .CPUs .Min ))
1058
+
1059
+ callbacks = cpuServerCallbacks {
1060
+ get : func (logger * zap.Logger ) (* vmv1.MilliCPU , error ) {
1061
+ return lo .ToPtr (vmv1 .MilliCPU (lastValue .Load ())), nil
1062
+ },
1063
+ set : func (logger * zap.Logger , cpu vmv1.MilliCPU ) error {
1064
+ if cfg .cpuScalingMode == vmv1 .CpuScalingModeSysfs {
1065
+ err := setNeonvmDaemonCPU (cpu )
1066
+ if err != nil {
1067
+ logger .Error ("setting CPU through NeonVM Daemon failed" , zap .Any ("cpu" , cpu ), zap .Error (err ))
1068
+ return err
1074
1069
}
1075
- lastValue .Store (uint32 (cpu ))
1076
- return nil
1077
- },
1078
- }
1079
- } else {
1080
- // Standard implementation -- actually set the cgroup
1081
- callbacks = cpuServerCallbacks {
1082
- get : func (logger * zap.Logger ) (* vmv1.MilliCPU , error ) {
1083
- return getCgroupQuota (cgroupPath )
1084
- },
1085
- set : func (logger * zap.Logger , cpu vmv1.MilliCPU ) error {
1086
- return setCgroupLimit (logger , cpu , cgroupPath )
1087
- },
1088
- }
1070
+ }
1071
+ lastValue .Store (uint32 (cpu ))
1072
+ return nil
1073
+ },
1089
1074
}
1090
1075
1091
1076
wg .Add (1 )
@@ -1493,32 +1478,6 @@ func setCgroupLimit(logger *zap.Logger, r vmv1.MilliCPU, cgroupPath string) erro
1493
1478
return nil
1494
1479
}
1495
1480
1496
- func getCgroupQuota (cgroupPath string ) (* vmv1.MilliCPU , error ) {
1497
- isV2 := cgroups .Mode () == cgroups .Unified
1498
- var path string
1499
- if isV2 {
1500
- path = filepath .Join (cgroupMountPoint , cgroupPath , "cpu.max" )
1501
- } else {
1502
- path = filepath .Join (cgroupMountPoint , "cpu" , cgroupPath , "cpu.cfs_quota_us" )
1503
- }
1504
- data , err := os .ReadFile (path )
1505
- if err != nil {
1506
- return nil , err
1507
- }
1508
-
1509
- arr := strings .Split (strings .Trim (string (data ), "\n " ), " " )
1510
- if len (arr ) == 0 {
1511
- return nil , errors .New ("unexpected cgroup data" )
1512
- }
1513
- quota , err := strconv .ParseUint (arr [0 ], 10 , 64 )
1514
- if err != nil {
1515
- return nil , err
1516
- }
1517
- cpu := vmv1 .MilliCPU (uint32 (quota * 1000 / cgroupPeriod ))
1518
- cpu /= cpuLimitOvercommitFactor
1519
- return & cpu , nil
1520
- }
1521
-
1522
1481
func terminateQemuOnSigterm (ctx context.Context , logger * zap.Logger , wg * sync.WaitGroup ) {
1523
1482
logger = logger .Named ("terminate-qemu-on-sigterm" )
1524
1483
0 commit comments