mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-30 18:23:35 +08:00
feat(region,host,scheduler): scheduler support allocate cpu numa pin (#20932)
This commit is contained in:
@@ -326,6 +326,8 @@ const (
|
||||
VM_METADATA_START_VCPU_COUNT = "start_vcpu_count"
|
||||
|
||||
VM_METADATA_RELEASED_DEVICES = "released_devices"
|
||||
|
||||
VM_METADATA_CPU_NUMA_PIN = "__cpu_numa_pin"
|
||||
)
|
||||
|
||||
// windows allow a maximal length of 15
|
||||
|
||||
@@ -721,6 +721,7 @@ type ServerMigrateForecastInput struct {
|
||||
SkipKernelCheck bool `json:"skip_kernel_check"`
|
||||
ConvertToKvm bool `json:"convert_to_kvm"`
|
||||
IsRescueMode bool `json:"is_rescue_mode"`
|
||||
ResetCpuNumaPin bool `json:"reset_cpu_numa_pin"`
|
||||
}
|
||||
|
||||
type ServerResizeDiskInput struct {
|
||||
@@ -876,6 +877,8 @@ type GuestJsonDesc struct {
|
||||
|
||||
IsolatedDevices []*IsolatedDeviceJsonDesc `json:"isolated_devices"`
|
||||
|
||||
CpuNumaPin []SCpuNumaPin `json:"cpu_numa_pin"`
|
||||
|
||||
Domain string `json:"domain"`
|
||||
|
||||
Nics []*GuestnetworkJsonDesc `json:"nics"`
|
||||
@@ -935,6 +938,18 @@ type GuestJsonDesc struct {
|
||||
Containers []*host.ContainerDesc `json:"containers"`
|
||||
}
|
||||
|
||||
type SVCpuPin struct {
|
||||
Vcpu int
|
||||
Pcpu int
|
||||
}
|
||||
|
||||
type SCpuNumaPin struct {
|
||||
SizeMB *int `json:"size_mb"`
|
||||
NodeId int `json:"node_id"`
|
||||
|
||||
VcpuPin []SVCpuPin `json:"vcpu_pin"`
|
||||
}
|
||||
|
||||
type ServerSetBootIndexInput struct {
|
||||
// key index, value boot_index
|
||||
Disks map[string]int8 `json:"disks"`
|
||||
|
||||
@@ -24,6 +24,11 @@ type ServerCloneDiskFromStorageResponse struct {
|
||||
TargetFormat string `json:"target_format"`
|
||||
}
|
||||
|
||||
type HostNodeHugepageNr struct {
|
||||
NodeId int `json:"node_id"`
|
||||
HugepageNr int `json:"hugepage_nr"`
|
||||
}
|
||||
|
||||
type HostTopology struct {
|
||||
*topology.Info
|
||||
}
|
||||
|
||||
+86
-12
@@ -78,13 +78,17 @@ type ScheduleInput struct {
|
||||
ServerConfig
|
||||
|
||||
// HostId used by migrate
|
||||
HostId string `json:"host_id"`
|
||||
LiveMigrate bool `json:"live_migrate"`
|
||||
SkipCpuCheck *bool `json:"skip_cpu_check"`
|
||||
CpuDesc string `json:"cpu_desc"`
|
||||
CpuMicrocode string `json:"cpu_microcode"`
|
||||
CpuMode string `json:"cpu_mode"`
|
||||
OsArch string `json:"os_arch"`
|
||||
HostId string `json:"host_id"`
|
||||
LiveMigrate bool `json:"live_migrate"`
|
||||
SkipCpuCheck *bool `json:"skip_cpu_check"`
|
||||
CpuDesc string `json:"cpu_desc"`
|
||||
CpuMicrocode string `json:"cpu_microcode"`
|
||||
CpuMode string `json:"cpu_mode"`
|
||||
OsArch string `json:"os_arch"`
|
||||
ResetCpuNumaPin bool `json:"reset_cpu_numa_pin"`
|
||||
|
||||
// For Migrate
|
||||
CpuNumaPin []SCpuNumaPin `json:"cpu_numa_pin"`
|
||||
|
||||
HostMemPageSizeKB int `json:"host_mem_page_size"`
|
||||
SkipKernelCheck *bool `json:"skip_kernel_check"`
|
||||
@@ -130,12 +134,82 @@ type CandidateNet struct {
|
||||
NetworkIds []string `json:"network_ids"`
|
||||
}
|
||||
|
||||
type SFreeNumaCpuMem struct {
|
||||
FreeCpuCount int
|
||||
MemSize int
|
||||
EnableNumaAllocate bool
|
||||
|
||||
CpuCount int
|
||||
NodeId int
|
||||
}
|
||||
|
||||
type SortedFreeNumaCpuMam []*SFreeNumaCpuMem
|
||||
|
||||
func (pq SortedFreeNumaCpuMam) Len() int { return len(pq) }
|
||||
|
||||
func (pq SortedFreeNumaCpuMam) Less(i, j int) bool {
|
||||
if pq[i].EnableNumaAllocate {
|
||||
return pq[i].MemSize > pq[j].MemSize
|
||||
} else {
|
||||
return pq[i].FreeCpuCount > pq[j].FreeCpuCount
|
||||
}
|
||||
}
|
||||
|
||||
func (pq SortedFreeNumaCpuMam) Swap(i, j int) {
|
||||
pq[i], pq[j] = pq[j], pq[i]
|
||||
}
|
||||
|
||||
func NodesFreeMemSizeEnough(nodeCount, memSize int, cpuNumaFree []*SFreeNumaCpuMem) bool {
|
||||
if !cpuNumaFree[0].EnableNumaAllocate {
|
||||
return true
|
||||
}
|
||||
|
||||
var freeMem = 0
|
||||
var leastFree = memSize / nodeCount
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
if cpuNumaFree[i].MemSize < leastFree {
|
||||
return false
|
||||
}
|
||||
freeMem += cpuNumaFree[i].MemSize
|
||||
}
|
||||
return freeMem >= memSize
|
||||
}
|
||||
|
||||
func NodesFreeCpuEnough(nodeCount, vcpuCount int, cpuNumaFree []*SFreeNumaCpuMem) bool {
|
||||
var freeCpu = 0
|
||||
var leaseCpu = vcpuCount / nodeCount
|
||||
|
||||
//if vcpuCount > nodeCount*cpuNumaFree[0].CpuCount {
|
||||
// return false
|
||||
//}
|
||||
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
if cpuNumaFree[i].FreeCpuCount < leaseCpu {
|
||||
return false
|
||||
}
|
||||
freeCpu += cpuNumaFree[i].FreeCpuCount
|
||||
}
|
||||
return freeCpu >= vcpuCount
|
||||
}
|
||||
|
||||
type SCpuPin struct {
|
||||
Vcpu int
|
||||
Pcpu int
|
||||
}
|
||||
|
||||
type SCpuNumaPin struct {
|
||||
CpuPin []int
|
||||
NodeId int
|
||||
MemSizeMB *int
|
||||
}
|
||||
|
||||
type CandidateResource struct {
|
||||
SessionId string `json:"session_id"`
|
||||
HostId string `json:"host_id"`
|
||||
Name string `json:"name"`
|
||||
Disks []*CandidateDisk `json:"disks"`
|
||||
Nets []*CandidateNet `json:"nets"`
|
||||
SessionId string `json:"session_id"`
|
||||
HostId string `json:"host_id"`
|
||||
Name string `json:"name"`
|
||||
CpuNumaPin []SCpuNumaPin `json:"cpu_numa_pin"`
|
||||
Disks []*CandidateDisk `json:"disks"`
|
||||
Nets []*CandidateNet `json:"nets"`
|
||||
|
||||
// used by backup schedule
|
||||
BackupCandidate *CandidateResource `json:"backup_candidate"`
|
||||
|
||||
@@ -74,6 +74,8 @@ const (
|
||||
ACT_MIGRATE = "migrate"
|
||||
ACT_MIGRATE_FAIL = "migrate_fail"
|
||||
|
||||
ACT_RESET_CPU_NUMA_PIN = "reset_cpu_numa_pin"
|
||||
|
||||
ACT_VM_CONVERT = "vm_convert"
|
||||
ACT_VM_CONVERTING = "vm_converting"
|
||||
ACT_VM_CONVERT_FAIL = "vm_convert_fail"
|
||||
|
||||
@@ -447,7 +447,8 @@ func (self *SKVMGuestDriver) RequestAssociateEip(ctx context.Context, userCred m
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, cpuSockets, vmemSize int64) error {
|
||||
if jsonutils.QueryBoolean(task.GetParams(), "guest_online", false) {
|
||||
taskParams := task.GetParams()
|
||||
if jsonutils.QueryBoolean(taskParams, "guest_online", false) {
|
||||
addCpu := vcpuCount - int64(guest.VcpuCount)
|
||||
addMem := vmemSize - int64(guest.VmemSize)
|
||||
if addCpu < 0 || addMem < 0 {
|
||||
@@ -461,6 +462,10 @@ func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *m
|
||||
if vmemSize > int64(guest.VmemSize) {
|
||||
body.Set("add_mem", jsonutils.NewInt(addMem))
|
||||
}
|
||||
if taskParams.Contains("cpu_numa_pin") {
|
||||
cpuNumaPin, _ := taskParams.Get("cpu_numa_pin")
|
||||
body.Set("cpu_numa_pin", cpuNumaPin)
|
||||
}
|
||||
host, _ := guest.GetHost()
|
||||
url := fmt.Sprintf("%s/servers/%s/hotplug-cpu-mem", host.ManagerUri, guest.Id)
|
||||
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
|
||||
|
||||
@@ -527,6 +527,8 @@ func (self *SGuest) GetSchedMigrateParams(
|
||||
if input.PreferHostId != "" {
|
||||
schedDesc.ServerConfig.PreferHost = input.PreferHostId
|
||||
}
|
||||
|
||||
schedDesc.ResetCpuNumaPin = input.ResetCpuNumaPin
|
||||
if input.LiveMigrate {
|
||||
schedDesc.LiveMigrate = input.LiveMigrate
|
||||
if self.GetMetadata(context.Background(), "__cpu_mode", userCred) != api.CPU_MODE_QEMU {
|
||||
@@ -544,6 +546,11 @@ func (self *SGuest) GetSchedMigrateParams(
|
||||
schedDesc.SkipKernelCheck = &input.SkipKernelCheck
|
||||
schedDesc.HostMemPageSizeKB = host.PageSizeKB
|
||||
}
|
||||
if self.CpuNumaPin != nil {
|
||||
cpuNumaPin := make([]schedapi.SCpuNumaPin, 0)
|
||||
self.CpuNumaPin.Unmarshal(&cpuNumaPin)
|
||||
schedDesc.CpuNumaPin = cpuNumaPin
|
||||
}
|
||||
}
|
||||
schedDesc.ReuseNetwork = true
|
||||
return schedDesc
|
||||
@@ -562,7 +569,8 @@ func (self *SGuest) StartMigrateTask(
|
||||
ctx context.Context, userCred mcclient.TokenCredential,
|
||||
isRescueMode, autoStart bool, guestStatus, preferHostId, parentTaskId string,
|
||||
) error {
|
||||
self.SetStatus(ctx, userCred, api.VM_START_MIGRATE, "")
|
||||
vmStatus := api.VM_START_MIGRATE
|
||||
|
||||
data := jsonutils.NewDict()
|
||||
if isRescueMode {
|
||||
data.Set("is_rescue_mode", jsonutils.JSONTrue)
|
||||
@@ -573,11 +581,17 @@ func (self *SGuest) StartMigrateTask(
|
||||
if autoStart {
|
||||
data.Set("auto_start", jsonutils.JSONTrue)
|
||||
}
|
||||
if self.HostId == preferHostId {
|
||||
vmStatus = api.VM_STARTING
|
||||
data.Set("reset_cpu_numa_pin", jsonutils.JSONTrue)
|
||||
}
|
||||
|
||||
data.Set("guest_status", jsonutils.NewString(guestStatus))
|
||||
dedicateMigrateTask := "GuestMigrateTask"
|
||||
if self.GetHypervisor() != api.HYPERVISOR_KVM {
|
||||
dedicateMigrateTask = "ManagedGuestMigrateTask" //托管私有云
|
||||
}
|
||||
self.SetStatus(ctx, userCred, vmStatus, "")
|
||||
if task, err := taskman.TaskManager.NewTask(ctx, dedicateMigrateTask, self, userCred, data, parentTaskId, "", nil); err != nil {
|
||||
log.Errorln(err)
|
||||
return err
|
||||
@@ -1543,7 +1557,12 @@ func (self *SGuest) StartGueststartTask(
|
||||
ctx context.Context, userCred mcclient.TokenCredential,
|
||||
data *jsonutils.JSONDict, parentTaskId string,
|
||||
) error {
|
||||
if self.Hypervisor == api.HYPERVISOR_KVM && self.guestDisksStorageTypeIsShared() {
|
||||
schedStart := self.Hypervisor == api.HYPERVISOR_KVM && self.guestDisksStorageTypeIsShared()
|
||||
if options.Options.IgnoreNonrunningGuests && self.CpuNumaPin != nil {
|
||||
schedStart = true
|
||||
}
|
||||
|
||||
if schedStart {
|
||||
return self.GuestSchedStartTask(ctx, userCred, data, parentTaskId)
|
||||
} else {
|
||||
return self.GuestNonSchedStartTask(ctx, userCred, data, parentTaskId)
|
||||
|
||||
@@ -127,6 +127,8 @@ type SGuest struct {
|
||||
VcpuCount int `nullable:"false" default:"1" list:"user" create:"optional"`
|
||||
// 内存大小, 单位MB
|
||||
VmemSize int `nullable:"false" list:"user" create:"required"`
|
||||
// CPU 内存绑定信息
|
||||
CpuNumaPin jsonutils.JSONObject `nullable:"true" get:"user" update:"user" create:"optional"`
|
||||
|
||||
// 启动顺序
|
||||
BootOrder string `width:"8" charset:"ascii" nullable:"true" default:"cdn" list:"user" update:"user" create:"optional"`
|
||||
@@ -1271,6 +1273,94 @@ func (guest *SGuest) SetHostIdWithBackup(userCred mcclient.TokenCredential, mast
|
||||
return err
|
||||
}
|
||||
|
||||
func (guest *SGuest) UpdateCpuNumaPin(
|
||||
ctx context.Context, userCred mcclient.TokenCredential,
|
||||
schedCpuNumaPin []schedapi.SCpuNumaPin, cpuNumaPinTarget []api.SCpuNumaPin,
|
||||
) error {
|
||||
srcSchedCpuNumaPin := make([]schedapi.SCpuNumaPin, 0)
|
||||
err := guest.CpuNumaPin.Unmarshal(&srcSchedCpuNumaPin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcSchedCpuNumaPin = append(srcSchedCpuNumaPin, schedCpuNumaPin...)
|
||||
|
||||
srcCpuNumaPin := make([]api.SCpuNumaPin, 0)
|
||||
cpuNumaPinStr := guest.GetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, nil)
|
||||
cpuNumaPinJson, err := jsonutils.ParseString(cpuNumaPinStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cpuNumaPinJson.Unmarshal(&srcCpuNumaPin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcCpuNumaPin = append(srcCpuNumaPin, cpuNumaPinTarget...)
|
||||
|
||||
diff, err := db.Update(guest, func() error {
|
||||
guest.CpuNumaPin = jsonutils.Marshal(srcSchedCpuNumaPin)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var jcpuNumaPin = jsonutils.Marshal(srcCpuNumaPin)
|
||||
err = guest.SetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, jcpuNumaPin, userCred)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(guest, db.ACT_UPDATE, diff, userCred)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (guest *SGuest) SetCpuNumaPin(
|
||||
ctx context.Context, userCred mcclient.TokenCredential,
|
||||
schedCpuNumaPin []schedapi.SCpuNumaPin, cpuNumaPin []api.SCpuNumaPin,
|
||||
) error {
|
||||
if cpuNumaPin == nil && schedCpuNumaPin != nil {
|
||||
cpuNumaPin = make([]api.SCpuNumaPin, len(schedCpuNumaPin))
|
||||
|
||||
vcpuId := 0
|
||||
for i := range schedCpuNumaPin {
|
||||
cpuNumaPin[i] = api.SCpuNumaPin{
|
||||
SizeMB: schedCpuNumaPin[i].MemSizeMB,
|
||||
NodeId: schedCpuNumaPin[i].NodeId,
|
||||
}
|
||||
cpuNumaPin[i].VcpuPin = make([]api.SVCpuPin, len(schedCpuNumaPin[i].CpuPin))
|
||||
for j := range schedCpuNumaPin[i].CpuPin {
|
||||
cpuNumaPin[i].VcpuPin[j].Pcpu = schedCpuNumaPin[i].CpuPin[j]
|
||||
cpuNumaPin[i].VcpuPin[j].Vcpu = vcpuId
|
||||
vcpuId += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var schedCpuNumaPinJ jsonutils.JSONObject
|
||||
if schedCpuNumaPin != nil {
|
||||
schedCpuNumaPinJ = jsonutils.Marshal(schedCpuNumaPin)
|
||||
}
|
||||
diff, err := db.Update(guest, func() error {
|
||||
guest.CpuNumaPin = schedCpuNumaPinJ
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var jcpuNumaPin interface{} = ""
|
||||
if cpuNumaPin != nil {
|
||||
jcpuNumaPin = jsonutils.Marshal(cpuNumaPin)
|
||||
}
|
||||
err = guest.SetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, jcpuNumaPin, userCred)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(guest, db.ACT_UPDATE, diff, userCred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (guest *SGuest) ValidateResizeDisk(disk *SDisk, storage *SStorage) error {
|
||||
drv, err := guest.GetDriver()
|
||||
if err != nil {
|
||||
@@ -5105,6 +5195,18 @@ func (self *SGuest) GetJsonDescAtHypervisor(ctx context.Context, host *SHost) *a
|
||||
desc.IsolatedDevices = append(desc.IsolatedDevices, dev.getDesc())
|
||||
}
|
||||
|
||||
if self.CpuNumaPin != nil {
|
||||
cpuNumaPin := make([]api.SCpuNumaPin, 0)
|
||||
cpuNumaPinStr := self.GetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, nil)
|
||||
cpuNumaPinJson, err := jsonutils.ParseString(cpuNumaPinStr)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse cpu numa pin %s: %s", cpuNumaPinStr, err)
|
||||
} else {
|
||||
cpuNumaPinJson.Unmarshal(&cpuNumaPin)
|
||||
desc.CpuNumaPin = cpuNumaPin
|
||||
}
|
||||
}
|
||||
|
||||
// nics, domain
|
||||
desc.Domain = options.Options.DNSDomain
|
||||
nics, _ := self.GetNetworks("")
|
||||
|
||||
@@ -4250,7 +4250,7 @@ func (hh *SHost) ValidateUpdateData(ctx context.Context, userCred mcclient.Token
|
||||
func (hh *SHost) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
hh.SEnabledStatusInfrasResourceBase.PostUpdate(ctx, userCred, query, data)
|
||||
|
||||
if data.Contains("cpu_cmtbound") || data.Contains("mem_cmtbound") {
|
||||
if data.Contains("cpu_cmtbound") || data.Contains("mem_cmtbound") || data.Contains("enable_numa_allocate") {
|
||||
hh.ClearSchedDescCache()
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,14 @@ func (task *GuestBatchCreateTask) allocateGuestOnHost(ctx context.Context, guest
|
||||
}
|
||||
}
|
||||
|
||||
if len(candidate.CpuNumaPin) > 0 {
|
||||
if err := guest.SetCpuNumaPin(ctx, task.UserCred, candidate.CpuNumaPin, nil); err != nil {
|
||||
log.Errorf("SetCpuNumaPin fail %s", err)
|
||||
guest.SetStatus(ctx, task.UserCred, api.VM_CREATE_FAILED, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
host, _ := guest.GetHost()
|
||||
|
||||
quotaCpuMem := models.SQuota{Count: 1, Cpu: int(guest.VcpuCount), Memory: guest.VmemSize}
|
||||
|
||||
@@ -85,6 +85,11 @@ func (task *GuestChangeConfigTask) SaveScheduleResult(ctx context.Context, obj I
|
||||
// must get object from task, because of obj is nil
|
||||
guest := task.GetObject().(*models.SGuest)
|
||||
task.Params.Set("sched_session_id", jsonutils.NewString(target.SessionId))
|
||||
|
||||
if len(target.CpuNumaPin) > 0 {
|
||||
task.Params.Set("cpu_numa_pin", jsonutils.Marshal(target.CpuNumaPin))
|
||||
}
|
||||
|
||||
/*confs, err := task.getChangeConfigSetting()
|
||||
if err != nil {
|
||||
task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
|
||||
@@ -258,6 +263,19 @@ func (task *GuestChangeConfigTask) OnGuestChangeCpuMemSpecComplete(ctx context.C
|
||||
task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update fail %s", err)))
|
||||
return
|
||||
}
|
||||
|
||||
if task.Params.Contains("cpu_numa_pin") {
|
||||
cpuNumaPinSched := make([]schedapi.SCpuNumaPin, 0)
|
||||
task.Params.Unmarshal(&cpuNumaPinSched, "cpu_numa_pin")
|
||||
cpuNumaPinTarget := make([]api.SCpuNumaPin, 0)
|
||||
data.Unmarshal(&cpuNumaPinTarget, "cpu_numa_pin")
|
||||
err = guest.UpdateCpuNumaPin(ctx, task.UserCred, cpuNumaPinSched, cpuNumaPinTarget)
|
||||
if err != nil {
|
||||
task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update cpu numa pin fail %s", err)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
changeConfigSpec := guest.GetShortDesc(ctx)
|
||||
if confs.VcpuCount > 0 && confs.AddedCpu() > 0 {
|
||||
changeConfigSpec.Set("add_cpu", jsonutils.NewInt(int64(confs.AddedCpu())))
|
||||
|
||||
@@ -74,6 +74,10 @@ func (task *GuestMigrateTask) GetSchedParams() (*schedapi.ScheduleInput, error)
|
||||
preferHostId, _ := task.Params.GetString("prefer_host_id")
|
||||
input.PreferHostId = preferHostId
|
||||
}
|
||||
if jsonutils.QueryBoolean(task.Params, "reset_cpu_numa_pin", false) {
|
||||
input.ResetCpuNumaPin = true
|
||||
}
|
||||
|
||||
if task.isLiveMigrate() {
|
||||
input.LiveMigrate = true
|
||||
skipCpuCheck := jsonutils.QueryBoolean(task.Params, "skip_cpu_check", false)
|
||||
@@ -105,19 +109,29 @@ func (task *GuestMigrateTask) OnScheduleFailed(ctx context.Context, reason jsonu
|
||||
}
|
||||
|
||||
func (task *GuestMigrateTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, target *schedapi.CandidateResource, index int) {
|
||||
targetHostId := target.HostId
|
||||
guest := obj.(*models.SGuest)
|
||||
if jsonutils.QueryBoolean(task.Params, "reset_cpu_numa_pin", false) {
|
||||
guest.SetCpuNumaPin(ctx, task.UserCred, target.CpuNumaPin, nil)
|
||||
db.OpsLog.LogEvent(guest, db.ACT_RESET_CPU_NUMA_PIN, fmt.Sprintf("reset cpu numa pin %s", jsonutils.Marshal(target.CpuNumaPin)), task.UserCred)
|
||||
task.SetStageComplete(ctx, nil)
|
||||
return
|
||||
}
|
||||
|
||||
targetHostId := target.HostId
|
||||
targetHost := models.HostManager.FetchHostById(targetHostId)
|
||||
if targetHost == nil {
|
||||
task.TaskFailed(ctx, guest, jsonutils.NewString("target host not found?"))
|
||||
return
|
||||
}
|
||||
db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, fmt.Sprintf("guest start migrate from host %s to %s", guest.HostId, targetHostId), task.UserCred)
|
||||
logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_MIGRATING,
|
||||
fmt.Sprintf("guest start migrate from host %s to %s(%s)", guest.HostId, targetHostId, targetHost.GetName()), task.UserCred, true)
|
||||
|
||||
body := jsonutils.NewDict()
|
||||
body.Set("target_host_id", jsonutils.NewString(targetHostId))
|
||||
if len(target.CpuNumaPin) > 0 {
|
||||
body.Set("target_cpu_numa_pin", jsonutils.Marshal(target.CpuNumaPin))
|
||||
} else {
|
||||
body.Set("target_cpu_numa_pin", jsonutils.JSONNull)
|
||||
}
|
||||
|
||||
// for params notes
|
||||
body.Set("target_host_name", jsonutils.NewString(targetHost.Name))
|
||||
srcHost := models.HostManager.FetchHostById(guest.HostId)
|
||||
@@ -166,6 +180,11 @@ func (task *GuestMigrateTask) SaveScheduleResult(ctx context.Context, obj ISched
|
||||
body.Set("cache_templates", jsonutils.NewStringArray(templates))
|
||||
}
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, fmt.Sprintf("guest start migrate from host %s to %s", guest.HostId, targetHostId), task.UserCred)
|
||||
logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_MIGRATING,
|
||||
fmt.Sprintf("guest start migrate from host %s to %s(%s)", guest.HostId, targetHostId, targetHost.GetName()), task.UserCred, true)
|
||||
|
||||
task.SetStage("OnStartCacheImages", body)
|
||||
task.OnStartCacheImages(ctx, guest, nil)
|
||||
}
|
||||
@@ -434,6 +453,12 @@ func (task *GuestMigrateTask) sharedStorageMigrateConf(ctx context.Context, gues
|
||||
body.Set("is_local_storage", jsonutils.JSONFalse)
|
||||
body.Set("qemu_version", jsonutils.NewString(guest.GetQemuVersion(task.UserCred)))
|
||||
targetDesc := guest.GetJsonDescAtHypervisor(ctx, targetHost)
|
||||
if task.Params.Contains("target_cpu_numa_pin") {
|
||||
if err := task.setCpuNumaPin(targetDesc); err != nil {
|
||||
return nil, errors.Wrap(err, "setCpuNumaPin")
|
||||
}
|
||||
}
|
||||
|
||||
body.Set("desc", jsonutils.Marshal(targetDesc))
|
||||
|
||||
sourceHost, _ := guest.GetHost()
|
||||
@@ -488,6 +513,12 @@ func (task *GuestMigrateTask) localStorageMigrateConf(ctx context.Context,
|
||||
if len(targetDesc.Disks) == 0 {
|
||||
return nil, errors.Errorf("Get disksDesc error")
|
||||
}
|
||||
if task.Params.Contains("target_cpu_numa_pin") {
|
||||
if err := task.setCpuNumaPin(targetDesc); err != nil {
|
||||
return nil, errors.Wrap(err, "setCpuNumaPin")
|
||||
}
|
||||
}
|
||||
|
||||
targetStorages, _ := task.Params.GetArray("target_storages")
|
||||
for i := 0; i < len(disks); i++ {
|
||||
targetStorageId, err := targetStorages[i].GetString()
|
||||
@@ -503,6 +534,20 @@ func (task *GuestMigrateTask) localStorageMigrateConf(ctx context.Context,
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func (task *GuestMigrateTask) setCpuNumaPin(targetDesc *api.GuestJsonDesc) error {
|
||||
cpuNumaPin := make([]schedapi.SCpuNumaPin, 0)
|
||||
if err := task.Params.Unmarshal(&cpuNumaPin, "cpu_numa_pin"); err != nil {
|
||||
return errors.Wrap(err, "unmarshal cpu_numa_pin")
|
||||
}
|
||||
for i := range targetDesc.CpuNumaPin {
|
||||
for j := range targetDesc.CpuNumaPin[i].VcpuPin {
|
||||
targetDesc.CpuNumaPin[i].VcpuPin[j].Pcpu = cpuNumaPin[i].CpuPin[j]
|
||||
}
|
||||
}
|
||||
task.Params.Set("target_vcpu_numa_pin", jsonutils.Marshal(targetDesc.CpuNumaPin))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *GuestLiveMigrateTask) OnStartDestComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
|
||||
liveMigrateDestPort, err := data.Get("live_migrate_dest_port")
|
||||
if err != nil {
|
||||
@@ -575,6 +620,29 @@ func (task *GuestMigrateTask) setGuest(ctx context.Context, guest *models.SGuest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if task.Params.Contains("target_cpu_numa_pin") {
|
||||
var cpuNumaPinSrc []schedapi.SCpuNumaPin = nil
|
||||
var cpuNumaPin []api.SCpuNumaPin = nil
|
||||
|
||||
val, _ := task.Params.Get("target_cpu_numa_pin")
|
||||
if !val.Equals(jsonutils.JSONNull) {
|
||||
cpuNumaPinSrc = make([]schedapi.SCpuNumaPin, 0)
|
||||
if err := task.Params.Unmarshal(&cpuNumaPinSrc, "target_cpu_numa_pin"); err != nil {
|
||||
return errors.Wrap(err, "unmarshal target_cpu_numa_pin")
|
||||
}
|
||||
|
||||
cpuNumaPin = make([]api.SCpuNumaPin, 0)
|
||||
if err := task.Params.Unmarshal(&cpuNumaPin, "target_vcpu_numa_pin"); err != nil {
|
||||
return errors.Wrap(err, "unmarshal target_vcpu_numa_pin")
|
||||
}
|
||||
}
|
||||
|
||||
if err := guest.SetCpuNumaPin(ctx, task.UserCred, cpuNumaPinSrc, cpuNumaPin); err != nil {
|
||||
return errors.Wrap(err, "SetCpuNumaPin")
|
||||
}
|
||||
}
|
||||
|
||||
oldHost, _ := guest.GetHost()
|
||||
oldHost.ClearSchedDescCache()
|
||||
err := guest.OnScheduleToHost(ctx, task.UserCred, targetHostId)
|
||||
|
||||
@@ -152,6 +152,11 @@ func (self *GuestSchedStartTask) OnInit(ctx context.Context, obj db.IStandaloneM
|
||||
}
|
||||
|
||||
func (self *GuestSchedStartTask) StartScheduler(ctx context.Context, guest *models.SGuest) {
|
||||
if guest.CpuNumaPin != nil {
|
||||
self.ScheduleFailed(ctx, guest)
|
||||
return
|
||||
}
|
||||
|
||||
host, _ := guest.GetHost()
|
||||
if request := host.GetRunningGuestResourceUsage(); request == nil {
|
||||
self.TaskFailed(ctx, guest, jsonutils.NewString("Guest Start Failed: Can't Get Host Guests CPU Memory Usage"))
|
||||
@@ -170,7 +175,13 @@ func (self *GuestSchedStartTask) StartScheduler(ctx context.Context, guest *mode
|
||||
|
||||
func (self *GuestSchedStartTask) ScheduleFailed(ctx context.Context, guest *models.SGuest) {
|
||||
self.SetStage("OnGuestMigrate", nil)
|
||||
guest.StartMigrateTask(ctx, self.UserCred, false, false, guest.Status, "", self.GetId())
|
||||
|
||||
preferHostId := ""
|
||||
if guest.CpuNumaPin != nil {
|
||||
preferHostId = guest.HostId
|
||||
}
|
||||
|
||||
guest.StartMigrateTask(ctx, self.UserCred, false, false, guest.Status, preferHostId, self.GetId())
|
||||
}
|
||||
|
||||
func (self *GuestSchedStartTask) OnGuestMigrate(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
|
||||
|
||||
@@ -57,10 +57,15 @@ type SMemSlot struct {
|
||||
|
||||
type SCpuNumaPin struct {
|
||||
SizeMB int64
|
||||
Regular bool
|
||||
HostNodes *uint16 `json:",omitempty"`
|
||||
Vcpus *string `json:",omitempty"`
|
||||
Pcpus *string `json:",omitempty"`
|
||||
Unregular bool
|
||||
NodeId *uint16 `json:",omitempty"`
|
||||
|
||||
VcpuPin []SVCpuPin `json:",omitempty"`
|
||||
}
|
||||
|
||||
type SVCpuPin struct {
|
||||
Vcpu int
|
||||
Pcpu int
|
||||
}
|
||||
|
||||
type SMemDesc struct {
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
@@ -581,12 +582,39 @@ func guestHotplugCpuMem(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
|
||||
addCpuCount, _ := body.Int("add_cpu")
|
||||
addMemSize, _ := body.Int("add_mem")
|
||||
hostutils.DelayTaskWithoutReqctx(ctx, guestman.GetGuestManager().HotplugCpuMem,
|
||||
&guestman.SGuestHotplugCpuMem{
|
||||
Sid: sid,
|
||||
AddCpuCount: addCpuCount,
|
||||
AddMemSize: addMemSize,
|
||||
})
|
||||
|
||||
input := &guestman.SGuestHotplugCpuMem{
|
||||
Sid: sid,
|
||||
AddCpuCount: addCpuCount,
|
||||
AddMemSize: addMemSize,
|
||||
}
|
||||
|
||||
if body.Contains("cpu_numa_pin") {
|
||||
cpuNumaPin := make([]schedapi.SCpuNumaPin, 0)
|
||||
if err := body.Unmarshal(&cpuNumaPin, "cpu_numa_pin"); err != nil {
|
||||
return nil, httperrors.NewInputParameterError("failed parse cpu_numa_pin %s", err)
|
||||
}
|
||||
|
||||
if len(cpuNumaPin) > 0 {
|
||||
descCpuNumaPin := make([]*desc.SCpuNumaPin, len(cpuNumaPin))
|
||||
for i := range cpuNumaPin {
|
||||
if cpuNumaPin[i].MemSizeMB != nil {
|
||||
descCpuNumaPin[i].SizeMB = int64(*cpuNumaPin[i].MemSizeMB)
|
||||
nodeId := uint16(cpuNumaPin[i].NodeId)
|
||||
descCpuNumaPin[i].NodeId = &nodeId
|
||||
}
|
||||
if len(cpuNumaPin[i].CpuPin) > 0 {
|
||||
vcpuPin := make([]desc.SVCpuPin, len(cpuNumaPin[i].CpuPin))
|
||||
for j := range vcpuPin {
|
||||
vcpuPin[j].Pcpu = cpuNumaPin[i].CpuPin[j]
|
||||
}
|
||||
descCpuNumaPin[i].VcpuPin = vcpuPin
|
||||
}
|
||||
}
|
||||
input.CpuNumaPin = descCpuNumaPin
|
||||
}
|
||||
}
|
||||
hostutils.DelayTaskWithoutReqctx(ctx, guestman.GetGuestManager().HotplugCpuMem, input)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ type SGuestHotplugCpuMem struct {
|
||||
Sid string
|
||||
AddCpuCount int64
|
||||
AddMemSize int64
|
||||
|
||||
CpuNumaPin []*desc.SCpuNumaPin
|
||||
}
|
||||
|
||||
type SReloadDisk struct {
|
||||
@@ -214,7 +216,7 @@ type CpuSetCounter struct {
|
||||
Lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewGuestCpuSetCounter(info *hostapi.HostTopology, reservedCpus *cpuset.CPUSet, numaAllocate bool, hugepageSizeKB int) (*CpuSetCounter, error) {
|
||||
func NewGuestCpuSetCounter(info *hostapi.HostTopology, reservedCpus *cpuset.CPUSet, numaAllocate bool, hugepageSizeKB, cpuCmtbound int) (*CpuSetCounter, error) {
|
||||
cpuSetCounter := new(CpuSetCounter)
|
||||
cpuSetCounter.Nodes = make([]*NumaNode, len(info.Nodes))
|
||||
cpuSetCounter.NumaEnabled = numaAllocate
|
||||
@@ -241,6 +243,8 @@ func NewGuestCpuSetCounter(info *hostapi.HostTopology, reservedCpus *cpuset.CPUS
|
||||
cpuDie.LogicalProcessors = dieBuilder.Result()
|
||||
node.CpuCount += cpuDie.LogicalProcessors.Size()
|
||||
node.LogicalProcessors = node.LogicalProcessors.Union(cpuDie.LogicalProcessors)
|
||||
cpuDie.initCpuFree(cpuCmtbound)
|
||||
|
||||
cpuDies = append(cpuDies, cpuDie)
|
||||
}
|
||||
if !hasL3Cache {
|
||||
@@ -257,11 +261,14 @@ func NewGuestCpuSetCounter(info *hostapi.HostTopology, reservedCpus *cpuset.CPUS
|
||||
cpuDie.LogicalProcessors = dieBuilder.Result()
|
||||
node.CpuCount += cpuDie.LogicalProcessors.Size()
|
||||
node.LogicalProcessors = node.LogicalProcessors.Union(cpuDie.LogicalProcessors)
|
||||
cpuDie.initCpuFree(cpuCmtbound)
|
||||
|
||||
cpuDies = append(cpuDies, cpuDie)
|
||||
}
|
||||
|
||||
hasL3Cache = false
|
||||
node.CpuDies = cpuDies
|
||||
sort.Sort(node.CpuDies)
|
||||
cpuSetCounter.Nodes[i] = node
|
||||
}
|
||||
sort.Sort(cpuSetCounter)
|
||||
@@ -292,9 +299,9 @@ func (pq *CpuSetCounter) AllocCpusetWithNodeCount(vcpuCount int, memSizeKB int64
|
||||
remPcpuCount -= 1
|
||||
}
|
||||
res[pq.Nodes[i].NodeId] = SAllocNumaCpus{
|
||||
Cpuset: pq.Nodes[i].AllocCpuset(npcpuCount),
|
||||
Cpuset: pq.Nodes[i].AllocCpuset1(npcpuCount),
|
||||
MemSizeKB: nodeAllocSize,
|
||||
Regular: true,
|
||||
Unregular: false,
|
||||
}
|
||||
pq.Nodes[i].NumaHugeFreeMemSizeKB -= nodeAllocSize
|
||||
pq.Nodes[i].VcpuCount += npcpuCount
|
||||
@@ -307,7 +314,7 @@ type SAllocNumaCpus struct {
|
||||
Cpuset []int
|
||||
MemSizeKB int64
|
||||
|
||||
Regular bool
|
||||
Unregular bool
|
||||
}
|
||||
|
||||
func (pq *CpuSetCounter) IsNumaEnabled() bool {
|
||||
@@ -351,9 +358,9 @@ func (pq *CpuSetCounter) AllocNumaNodes(vcpuCount int, memSizeKB int64, perferNu
|
||||
}
|
||||
if pq.Nodes[i].NumaHugeFreeMemSizeKB >= memSizeKB {
|
||||
res[pq.Nodes[i].NodeId] = SAllocNumaCpus{
|
||||
Cpuset: pq.Nodes[i].AllocCpuset(vcpuCount),
|
||||
Cpuset: pq.Nodes[i].AllocCpuset1(vcpuCount),
|
||||
MemSizeKB: memSizeKB,
|
||||
Regular: true,
|
||||
Unregular: false,
|
||||
}
|
||||
pq.Nodes[i].NumaHugeFreeMemSizeKB -= memSizeKB
|
||||
pq.Nodes[i].VcpuCount += vcpuCount
|
||||
@@ -388,9 +395,9 @@ func (pq *CpuSetCounter) AllocNumaNodes(vcpuCount int, memSizeKB int64, perferNu
|
||||
remPcpuCount -= 1
|
||||
}
|
||||
res[pq.Nodes[i].NodeId] = SAllocNumaCpus{
|
||||
Cpuset: pq.Nodes[i].AllocCpuset(npcpuCount),
|
||||
Cpuset: pq.Nodes[i].AllocCpuset1(npcpuCount),
|
||||
MemSizeKB: nodeAllocSize,
|
||||
Regular: true,
|
||||
Unregular: false,
|
||||
}
|
||||
pq.Nodes[i].NumaHugeFreeMemSizeKB -= nodeAllocSize
|
||||
pq.Nodes[i].VcpuCount += npcpuCount
|
||||
@@ -431,9 +438,9 @@ func (pq *CpuSetCounter) setNumaNodes(numaMaps map[int]int, vcpuCount int64) map
|
||||
allocMem := int64(size) * 1024
|
||||
//npcpuCount := int(vcpuCount*allocMem/memSizeKB + (vcpuCount*allocMem)%memSizeKB)
|
||||
res[pq.Nodes[i].NodeId] = SAllocNumaCpus{
|
||||
Cpuset: pq.Nodes[i].AllocCpuset(int(vcpuCount)),
|
||||
Cpuset: pq.Nodes[i].AllocCpuset1(int(vcpuCount)),
|
||||
MemSizeKB: allocMem,
|
||||
Regular: false,
|
||||
Unregular: true,
|
||||
}
|
||||
|
||||
pq.Nodes[i].NumaHugeFreeMemSizeKB -= allocMem
|
||||
@@ -583,6 +590,62 @@ func NewNumaNode(nodeId int, numaAllocate bool, hugepageSizeKB int) (*NumaNode,
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n *NumaNode) AllocCpuset1(vcpuCount int) []int {
|
||||
var allocCount = vcpuCount
|
||||
var dieCnt = 0
|
||||
|
||||
// If request vcpu count great then node cpucount,
|
||||
// vcpus should evenly distributed to all dies.
|
||||
// Otherwise figure out how many dies can hold
|
||||
// all of vcpus at first, and evenly distributed
|
||||
// to selected dies.
|
||||
if vcpuCount > n.CpuCount {
|
||||
dieCnt = len(n.CpuDies)
|
||||
} else {
|
||||
var pcpuCount = 0
|
||||
for dieCnt < len(n.CpuDies) {
|
||||
pcpuCount += n.CpuDies[dieCnt].LogicalProcessors.Size()
|
||||
dieCnt += 1
|
||||
|
||||
if pcpuCount >= vcpuCount {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var perDieCpuCount = vcpuCount / dieCnt
|
||||
var allocCpuCountMap = make([]int, dieCnt)
|
||||
for allocCount > 0 {
|
||||
for i := 0; i < dieCnt; i++ {
|
||||
var allocNum = perDieCpuCount
|
||||
if allocCount < allocNum {
|
||||
allocNum = allocCount
|
||||
}
|
||||
allocCount -= allocNum
|
||||
allocCpuCountMap[i] += allocNum
|
||||
}
|
||||
}
|
||||
|
||||
var pcpus = make([]int, 0)
|
||||
for i := 0; i < len(allocCpuCountMap); i++ {
|
||||
var allocCpuCount = allocCpuCountMap[i]
|
||||
for allocCpuCount > 0 {
|
||||
pcpus := n.CpuDies[i].LogicalProcessors.ToSliceNoSort()
|
||||
for j := 0; j < len(pcpus); j++ {
|
||||
if n.CpuDies[i].CpuFree[pcpus[j]] > 0 {
|
||||
pcpus = append(pcpus, n.CpuDies[i].CpuFree[pcpus[j]])
|
||||
n.CpuDies[i].CpuFree[pcpus[j]] -= 1
|
||||
}
|
||||
allocCpuCount -= 1
|
||||
if allocCpuCount <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pcpus
|
||||
}
|
||||
|
||||
func (n *NumaNode) AllocCpuset(vcpuCount int) []int {
|
||||
cpus := make([]int, 0)
|
||||
|
||||
@@ -602,10 +665,19 @@ func (n *NumaNode) AllocCpuset(vcpuCount int) []int {
|
||||
}
|
||||
|
||||
type CPUDie struct {
|
||||
CpuFree map[int]int
|
||||
LogicalProcessors cpuset.CPUSet
|
||||
VcpuCount int
|
||||
}
|
||||
|
||||
func (d *CPUDie) initCpuFree(cpuCmtbound int) {
|
||||
cpuFree := map[int]int{}
|
||||
for _, cpuId := range d.LogicalProcessors.ToSliceNoSort() {
|
||||
cpuFree[cpuId] = cpuCmtbound
|
||||
}
|
||||
d.CpuFree = cpuFree
|
||||
}
|
||||
|
||||
type SorttedCPUDie []*CPUDie
|
||||
|
||||
func (pq SorttedCPUDie) Len() int { return len(pq) }
|
||||
@@ -648,7 +720,11 @@ func (pq *SorttedCPUDie) ReleaseCpus(cpus []int, vcpuCount int) {
|
||||
|
||||
for i := 0; i < len(*pq); i++ {
|
||||
if _, ok := cpuDies[i]; ok {
|
||||
(*pq)[i].VcpuCount -= vcpuCount
|
||||
d := (*pq)[i]
|
||||
for _, cpu := range cpus {
|
||||
d.CpuFree[cpu] += 1
|
||||
}
|
||||
d.VcpuCount -= vcpuCount
|
||||
}
|
||||
}
|
||||
sort.Sort(pq)
|
||||
@@ -670,8 +746,12 @@ func (pq *SorttedCPUDie) LoadCpus(cpus []int, vcpuCount int) {
|
||||
}
|
||||
|
||||
for i := 0; i < len(*pq); i++ {
|
||||
if _, ok := cpuDies[i]; ok {
|
||||
(*pq)[i].VcpuCount += vcpuCount
|
||||
if cpus, ok := cpuDies[i]; ok {
|
||||
d := (*pq)[i]
|
||||
for _, cpu := range cpus {
|
||||
d.CpuFree[cpu] -= 1
|
||||
}
|
||||
d.VcpuCount += vcpuCount
|
||||
}
|
||||
}
|
||||
sort.Sort(pq)
|
||||
|
||||
@@ -255,9 +255,13 @@ func (m *SGuestManager) CleanServer(sid string) {
|
||||
|
||||
func (m *SGuestManager) Bootstrap() (chan struct{}, error) {
|
||||
hostTypo := m.host.GetHostTopology()
|
||||
m.numaAllocate = m.host.IsNumaAllocateEnabled() && m.host.IsHugepagesEnabled() && (len(hostTypo.Nodes) > 1)
|
||||
|
||||
if options.HostOptions.EnableHostAgentNumaAllocate {
|
||||
m.numaAllocate = m.host.IsNumaAllocateEnabled() && m.host.IsHugepagesEnabled() && (len(hostTypo.Nodes) > 1)
|
||||
}
|
||||
|
||||
cpuSet, err := NewGuestCpuSetCounter(
|
||||
hostTypo, m.host.GetReservedCpusInfo(), m.numaAllocate, m.host.HugepageSizeKb())
|
||||
hostTypo, m.host.GetReservedCpusInfo(), m.numaAllocate, m.host.HugepageSizeKb(), m.host.CpuCmtBound())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1445,7 +1449,7 @@ func (m *SGuestManager) HotplugCpuMem(ctx context.Context, params interface{}) (
|
||||
return nil, hostutils.ParamsError
|
||||
}
|
||||
guest, _ := m.GetKVMServer(hotplugParams.Sid)
|
||||
NewGuestHotplugCpuMemTask(ctx, guest, int(hotplugParams.AddCpuCount), int(hotplugParams.AddMemSize)).Start()
|
||||
NewGuestHotplugCpuMemTask(ctx, guest, int(hotplugParams.AddCpuCount), int(hotplugParams.AddMemSize), hotplugParams.CpuNumaPin).Start()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2393,27 +2393,31 @@ func (task *SGuestOnlineResizeDiskTask) OnResizeSucc(err string) {
|
||||
type SGuestHotplugCpuMemTask struct {
|
||||
*SKVMGuestInstance
|
||||
|
||||
ctx context.Context
|
||||
addCpuCount int
|
||||
addMemSize int
|
||||
ctx context.Context
|
||||
addCpuCount int
|
||||
addMemSize int
|
||||
addMemNodeIndex int
|
||||
|
||||
originalCpuCount int
|
||||
addedCpuCount int
|
||||
addedVcpuIds []int
|
||||
cpuNumaPin []*desc.SCpuNumaPin
|
||||
|
||||
addedMemSize int
|
||||
memSlotNewIndex *int
|
||||
memSlot *desc.SMemSlot
|
||||
addedMemSize int
|
||||
memSlotNewIndex *int
|
||||
memSlotNewIndexs []int
|
||||
memSlots []*desc.SMemSlot
|
||||
}
|
||||
|
||||
func NewGuestHotplugCpuMemTask(
|
||||
ctx context.Context, s *SKVMGuestInstance, addCpuCount, addMemSize int,
|
||||
ctx context.Context, s *SKVMGuestInstance, addCpuCount, addMemSize int, cpuNumaPin []*desc.SCpuNumaPin,
|
||||
) *SGuestHotplugCpuMemTask {
|
||||
return &SGuestHotplugCpuMemTask{
|
||||
SKVMGuestInstance: s,
|
||||
ctx: ctx,
|
||||
addCpuCount: addCpuCount,
|
||||
addMemSize: addMemSize,
|
||||
cpuNumaPin: cpuNumaPin,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2446,12 +2450,14 @@ func (task *SGuestHotplugCpuMemTask) buildVcpusMap() {
|
||||
}
|
||||
}
|
||||
|
||||
allocatedVcpus := make([]int, 0)
|
||||
for i := range task.Desc.CpuNumaPin {
|
||||
if task.Desc.CpuNumaPin[i].Vcpus != nil {
|
||||
allocedVcpus, _ := cpuset.Parse(*task.Desc.CpuNumaPin[i].Vcpus)
|
||||
vcpuSet = vcpuSet.Difference(allocedVcpus)
|
||||
for j := range task.Desc.CpuNumaPin[i].VcpuPin {
|
||||
allocatedVcpus = append(allocatedVcpus, task.Desc.CpuNumaPin[i].VcpuPin[j].Vcpu)
|
||||
}
|
||||
}
|
||||
allocatedCpuset := cpuset.NewCPUSet(allocatedVcpus...)
|
||||
vcpuSet = vcpuSet.Difference(allocatedCpuset)
|
||||
|
||||
task.startAddCpusWithFreeVcpuSet(vcpuSet.ToSlice())
|
||||
}
|
||||
@@ -2470,17 +2476,29 @@ func (task *SGuestHotplugCpuMemTask) startAddCpusWithFreeVcpuSet(vcpuSet []int)
|
||||
return
|
||||
}
|
||||
|
||||
cpus, _ := task.manager.cpuSet.AllocCpuset(1, 0, -1)
|
||||
for _, cpus := range cpus {
|
||||
pcpus := cpuset.NewCPUSet(cpus.Cpuset...).String()
|
||||
vcpus := fmt.Sprintf("%d-%d", vcpuId, vcpuId)
|
||||
cpuPin := &desc.SCpuNumaPin{
|
||||
SizeMB: 0,
|
||||
Pcpus: &pcpus,
|
||||
Vcpus: &vcpus,
|
||||
Regular: true,
|
||||
if len(task.cpuNumaPin) > 0 {
|
||||
for i := range task.cpuNumaPin {
|
||||
for j := range task.cpuNumaPin[i].VcpuPin {
|
||||
if task.cpuNumaPin[i].VcpuPin[j].Vcpu == -1 {
|
||||
task.cpuNumaPin[i].VcpuPin[j].Vcpu = vcpuId
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cpus, _ := task.manager.cpuSet.AllocCpuset(1, 0, -1)
|
||||
for _, cpus := range cpus {
|
||||
//pcpus := cpuset.NewCPUSet(cpus.Cpuset...).String()
|
||||
//vcpus := fmt.Sprintf("%d-%d", vcpuId, vcpuId)
|
||||
vcpuPin := make([]desc.SVCpuPin, 1)
|
||||
vcpuPin[0].Pcpu = cpus.Cpuset[0]
|
||||
vcpuPin[0].Vcpu = vcpuId
|
||||
cpuPin := &desc.SCpuNumaPin{
|
||||
SizeMB: 0,
|
||||
VcpuPin: vcpuPin,
|
||||
Unregular: false,
|
||||
}
|
||||
task.Desc.CpuNumaPin = append(task.Desc.CpuNumaPin, cpuPin)
|
||||
}
|
||||
task.Desc.CpuNumaPin = append(task.Desc.CpuNumaPin, cpuPin)
|
||||
}
|
||||
if task.addedVcpuIds == nil {
|
||||
task.addedVcpuIds = []int{vcpuId}
|
||||
@@ -2529,6 +2547,21 @@ func (task *SGuestHotplugCpuMemTask) onGetSlotIndex(index int) {
|
||||
var newIndex = index + len(task.Desc.MemDesc.Mem.Mems)
|
||||
task.memSlotNewIndex = &newIndex
|
||||
|
||||
var addMemSize = task.addMemSize
|
||||
var numaNodeDesc *desc.SCpuNumaPin
|
||||
for i := task.addMemNodeIndex; i < len(task.cpuNumaPin); i++ {
|
||||
if task.cpuNumaPin[i].SizeMB > 0 {
|
||||
task.addMemNodeIndex = i + 1
|
||||
numaNodeDesc = task.cpuNumaPin[i]
|
||||
addMemSize = int(task.cpuNumaPin[i].SizeMB)
|
||||
break
|
||||
}
|
||||
}
|
||||
var hostNodes *uint16
|
||||
if numaNodeDesc != nil {
|
||||
hostNodes = numaNodeDesc.NodeId
|
||||
}
|
||||
|
||||
var objType string
|
||||
var id = fmt.Sprintf("mem%d", *task.memSlotNewIndex)
|
||||
var opts map[string]string
|
||||
@@ -2544,7 +2577,7 @@ func (task *SGuestHotplugCpuMemTask) onGetSlotIndex(index int) {
|
||||
return
|
||||
}
|
||||
err = procutils.NewRemoteCommandAsFarAsPossible("mount", "-t", "hugetlbfs", "-o",
|
||||
fmt.Sprintf("pagesize=%dK,size=%dM", task.manager.host.HugepageSizeKb(), task.addMemSize),
|
||||
fmt.Sprintf("pagesize=%dK,size=%dM", task.manager.host.HugepageSizeKb(), addMemSize),
|
||||
fmt.Sprintf("hugetlbfs-%s-%d", task.GetId(), index),
|
||||
memPath,
|
||||
).Run()
|
||||
@@ -2557,11 +2590,17 @@ func (task *SGuestHotplugCpuMemTask) onGetSlotIndex(index int) {
|
||||
|
||||
objType = "memory-backend-file"
|
||||
opts = map[string]string{
|
||||
"size": fmt.Sprintf("%dM", task.addMemSize),
|
||||
"size": fmt.Sprintf("%dM", addMemSize),
|
||||
"mem-path": memPath,
|
||||
"share": "on",
|
||||
"prealloc": "on",
|
||||
}
|
||||
|
||||
if hostNodes != nil {
|
||||
opts["host-nodes"] = fmt.Sprintf("%d", *hostNodes)
|
||||
opts["policy"] = "bind"
|
||||
}
|
||||
|
||||
} else {
|
||||
objType = "memory-backend-ram"
|
||||
opts = map[string]string{
|
||||
@@ -2570,14 +2609,12 @@ func (task *SGuestHotplugCpuMemTask) onGetSlotIndex(index int) {
|
||||
}
|
||||
opts["id"] = id
|
||||
cb := func(reason string) {
|
||||
if reason == "" {
|
||||
memObj := desc.NewMemDesc(objType, id, nil, nil)
|
||||
memObj.Options = opts
|
||||
task.memSlot = new(desc.SMemSlot)
|
||||
task.memSlot.MemObj = memObj
|
||||
task.memSlot.SizeMB = int64(task.addMemSize)
|
||||
}
|
||||
task.onAddMemObject(reason)
|
||||
memObj := desc.NewMemDesc(objType, id, nil, nil)
|
||||
memObj.Options = opts
|
||||
memSlot := new(desc.SMemSlot)
|
||||
memSlot.MemObj = memObj
|
||||
memSlot.SizeMB = int64(addMemSize)
|
||||
task.onAddMemObject(reason, memSlot)
|
||||
}
|
||||
task.Monitor.ObjectAdd(objType, opts, cb)
|
||||
}
|
||||
@@ -2589,7 +2626,7 @@ func (task *SGuestHotplugCpuMemTask) onAddMemFailed(reason string) {
|
||||
task.onFail(reason)
|
||||
}
|
||||
|
||||
func (task *SGuestHotplugCpuMemTask) onAddMemObject(reason string) {
|
||||
func (task *SGuestHotplugCpuMemTask) onAddMemObject(reason string, memSlot *desc.SMemSlot) {
|
||||
if len(reason) > 0 {
|
||||
task.onAddMemFailed(reason)
|
||||
return
|
||||
@@ -2600,39 +2637,59 @@ func (task *SGuestHotplugCpuMemTask) onAddMemObject(reason string) {
|
||||
}
|
||||
cb := func(reason string) {
|
||||
if reason == "" {
|
||||
task.memSlot.MemDev = &desc.SMemDevice{
|
||||
memSlot.MemDev = &desc.SMemDevice{
|
||||
Type: "pc-dimm",
|
||||
Id: fmt.Sprintf("dimm%d", *task.memSlotNewIndex),
|
||||
}
|
||||
}
|
||||
task.onAddMemDevice(reason)
|
||||
task.onAddMemDevice(reason, memSlot)
|
||||
}
|
||||
|
||||
task.Monitor.DeviceAdd("pc-dimm", params, cb)
|
||||
}
|
||||
|
||||
func (task *SGuestHotplugCpuMemTask) onAddMemDevice(reason string) {
|
||||
func (task *SGuestHotplugCpuMemTask) onAddMemDevice(reason string, memSlot *desc.SMemSlot) {
|
||||
if len(reason) > 0 {
|
||||
task.onAddMemFailed(reason)
|
||||
return
|
||||
}
|
||||
task.addedMemSize = task.addMemSize
|
||||
task.onSucc()
|
||||
task.addedMemSize = int(memSlot.SizeMB)
|
||||
task.addMemSize -= int(memSlot.SizeMB)
|
||||
if task.memSlots == nil {
|
||||
task.memSlots = []*desc.SMemSlot{memSlot}
|
||||
task.memSlotNewIndexs = []int{*task.memSlotNewIndex}
|
||||
} else {
|
||||
task.memSlots = append(task.memSlots, memSlot)
|
||||
task.memSlotNewIndexs = append(task.memSlotNewIndexs, *task.memSlotNewIndex)
|
||||
}
|
||||
|
||||
if task.addMemSize > 0 {
|
||||
task.startAddMem()
|
||||
} else {
|
||||
task.onSucc()
|
||||
}
|
||||
}
|
||||
|
||||
func (task *SGuestHotplugCpuMemTask) updateGuestDesc() {
|
||||
task.Desc.Cpu += int64(task.addedCpuCount)
|
||||
task.Desc.CpuDesc.Cpus += uint(task.addedCpuCount)
|
||||
task.Desc.Mem += int64(task.addedMemSize)
|
||||
|
||||
if len(task.cpuNumaPin) > 0 {
|
||||
task.Desc.CpuNumaPin = append(task.Desc.CpuNumaPin, task.cpuNumaPin...)
|
||||
}
|
||||
|
||||
if task.addedMemSize > 0 {
|
||||
if task.Desc.MemDesc.MemSlots == nil {
|
||||
task.Desc.MemDesc.MemSlots = make([]*desc.SMemSlot, 0)
|
||||
}
|
||||
task.Desc.MemDesc.MemSlots = append(task.Desc.MemDesc.MemSlots, task.memSlot)
|
||||
task.Desc.MemDesc.MemSlots = append(task.Desc.MemDesc.MemSlots, task.memSlots...)
|
||||
|
||||
if task.manager.numaAllocate {
|
||||
hugepageId := fmt.Sprintf("%s-%d", task.getOriginId(), *task.memSlotNewIndex)
|
||||
task.validateNumaAllocated(hugepageId, false, true, nil)
|
||||
for i := range task.memSlotNewIndexs {
|
||||
hugepageId := fmt.Sprintf("%s-%d", task.getOriginId(), task.memSlotNewIndexs[i])
|
||||
task.validateNumaAllocated(hugepageId, false, true, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2671,7 +2728,12 @@ func (task *SGuestHotplugCpuMemTask) onFail(reason string) {
|
||||
|
||||
func (task *SGuestHotplugCpuMemTask) onSucc() {
|
||||
task.updateGuestDesc()
|
||||
hostutils.TaskComplete(task.ctx, nil)
|
||||
|
||||
res := jsonutils.NewDict()
|
||||
if len(task.cpuNumaPin) > 0 {
|
||||
res.Set("cpu_numa_pin", jsonutils.Marshal(task.Desc.CpuNumaPin))
|
||||
}
|
||||
hostutils.TaskComplete(task.ctx, res)
|
||||
}
|
||||
|
||||
type SGuestBlockIoThrottleTask struct {
|
||||
|
||||
+127
-122
@@ -153,26 +153,16 @@ func (s *SKVMGuestInstance) updateGuestDesc() error {
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) releaseCpuNumaPin(cpuNumaPin []*desc.SCpuNumaPin) {
|
||||
if !s.manager.numaAllocate {
|
||||
return
|
||||
}
|
||||
|
||||
for _, numaCpus := range cpuNumaPin {
|
||||
pcpuSet, err := cpuset.Parse(*numaCpus.Pcpus)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse %s pcpus: %s", s.GetName(), *numaCpus.Pcpus)
|
||||
continue
|
||||
pcpus := make([]int, 0)
|
||||
for i := range numaCpus.VcpuPin {
|
||||
pcpus = append(pcpus, numaCpus.VcpuPin[i].Pcpu)
|
||||
}
|
||||
vcpuCount := int(s.Desc.Cpu)
|
||||
if numaCpus.Vcpus != nil {
|
||||
vcpuSet, err := cpuset.Parse(*numaCpus.Vcpus)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse %s vcpus: %s", s.GetName(), *numaCpus.Vcpus)
|
||||
continue
|
||||
}
|
||||
vcpuCount = vcpuSet.Size()
|
||||
}
|
||||
hostNodes := -1
|
||||
if numaCpus.HostNodes != nil {
|
||||
hostNodes = int(*numaCpus.HostNodes)
|
||||
}
|
||||
s.manager.cpuSet.ReleaseNumaCpus(numaCpus.SizeMB, hostNodes, pcpuSet.ToSlice(), vcpuCount)
|
||||
s.manager.cpuSet.ReleaseNumaCpus(numaCpus.SizeMB, int(*numaCpus.NodeId), pcpus, len(numaCpus.VcpuPin))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,12 +199,15 @@ func (s *SKVMGuestInstance) reallocateMigrateNumaNodes() error {
|
||||
if len(nodeNumaCpus) > 0 {
|
||||
for nodeId, numaCpus := range nodeNumaCpus {
|
||||
unodeId := uint16(nodeId)
|
||||
pcpus := cpuset.NewCPUSet(numaCpus.Cpuset...).String()
|
||||
vcpuPin := make([]desc.SVCpuPin, len(numaCpus.Cpuset))
|
||||
for i := range numaCpus.Cpuset {
|
||||
vcpuPin[i].Pcpu = numaCpus.Cpuset[i]
|
||||
}
|
||||
memPin := &desc.SCpuNumaPin{
|
||||
SizeMB: numaCpus.MemSizeKB / 1024, // MB
|
||||
HostNodes: &unodeId,
|
||||
Pcpus: &pcpus,
|
||||
Regular: numaCpus.Regular,
|
||||
NodeId: &unodeId,
|
||||
VcpuPin: vcpuPin,
|
||||
Unregular: numaCpus.Unregular,
|
||||
}
|
||||
cpuNumaPin = append(cpuNumaPin, memPin)
|
||||
}
|
||||
@@ -222,9 +215,9 @@ func (s *SKVMGuestInstance) reallocateMigrateNumaNodes() error {
|
||||
|
||||
if len(cpuNumaPin) > 0 {
|
||||
s.Desc.CpuNumaPin = cpuNumaPin
|
||||
s.Desc.MemDesc.Mem.SMemDesc.SetHostNodes(int(*cpuNumaPin[0].HostNodes))
|
||||
s.Desc.MemDesc.Mem.SMemDesc.SetHostNodes(int(*cpuNumaPin[0].NodeId))
|
||||
for i := range s.Desc.MemDesc.Mem.Mems {
|
||||
s.Desc.MemDesc.Mem.Mems[i].SetHostNodes(int(*cpuNumaPin[i+1].HostNodes))
|
||||
s.Desc.MemDesc.Mem.Mems[i].SetHostNodes(int(*cpuNumaPin[i+1].NodeId))
|
||||
}
|
||||
} else {
|
||||
s.Desc.MemDesc.Mem.SMemDesc.SetHostNodes(-1)
|
||||
@@ -236,11 +229,13 @@ func (s *SKVMGuestInstance) reallocateMigrateNumaNodes() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) validateNumaAllocated(keywords string, isMigrate, isHotPlug bool, vcpuOrder []string) error {
|
||||
func (s *SKVMGuestInstance) validateNumaAllocated(keywords string, isMigrate, isHotPlug bool, vcpuOrder [][]int) error {
|
||||
if len(s.Desc.CpuNumaPin) > 0 {
|
||||
if isMigrate {
|
||||
for i := range s.Desc.CpuNumaPin {
|
||||
s.Desc.CpuNumaPin[i].Vcpus = &vcpuOrder[i]
|
||||
for j := range s.Desc.CpuNumaPin[i].VcpuPin {
|
||||
s.Desc.CpuNumaPin[i].VcpuPin[j].Vcpu = vcpuOrder[i][j]
|
||||
}
|
||||
}
|
||||
return SaveLiveDesc(s, s.Desc)
|
||||
}
|
||||
@@ -308,12 +303,16 @@ func (s *SKVMGuestInstance) validateNumaAllocated(keywords string, isMigrate, is
|
||||
var cpuNumaPin = make([]*desc.SCpuNumaPin, 0)
|
||||
for nodeId, numaCpus := range nodeNumaCpus {
|
||||
unodeId := uint16(nodeId)
|
||||
pcpus := cpuset.NewCPUSet(numaCpus.Cpuset...).String()
|
||||
vcpuPin := make([]desc.SVCpuPin, len(numaCpus.Cpuset))
|
||||
for i := range numaCpus.Cpuset {
|
||||
vcpuPin[i].Pcpu = numaCpus.Cpuset[i]
|
||||
}
|
||||
|
||||
memPin := &desc.SCpuNumaPin{
|
||||
SizeMB: numaCpus.MemSizeKB / 1024, // MB
|
||||
HostNodes: &unodeId,
|
||||
Pcpus: &pcpus,
|
||||
Regular: numaCpus.Regular,
|
||||
NodeId: &unodeId,
|
||||
VcpuPin: vcpuPin,
|
||||
Unregular: numaCpus.Unregular,
|
||||
}
|
||||
cpuNumaPin = append(cpuNumaPin, memPin)
|
||||
}
|
||||
@@ -325,7 +324,9 @@ func (s *SKVMGuestInstance) validateNumaAllocated(keywords string, isMigrate, is
|
||||
|
||||
if len(vcpuOrder) > 0 {
|
||||
for i := range cpuNumaPin {
|
||||
cpuNumaPin[i].Vcpus = &vcpuOrder[i]
|
||||
for j := range cpuNumaPin[i].VcpuPin {
|
||||
cpuNumaPin[i].VcpuPin[j].Vcpu = vcpuOrder[i][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,66 +379,79 @@ func (s *SKVMGuestInstance) initLiveDescFromSourceGuest(srcDesc *desc.SGuestDesc
|
||||
srcDesc.Nics[i].DownscriptPath = s.getNicDownScriptPath(srcDesc.Nics[i])
|
||||
}
|
||||
|
||||
nodeNumaCpus, err := s.manager.cpuSet.AllocCpusetWithNodeCount(int(srcDesc.Cpu), srcDesc.Mem*1024, len(srcDesc.MemDesc.Mem.Mems)+1)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "AllocCpusetWithNodeCount")
|
||||
}
|
||||
|
||||
var cpus = make([]int, 0)
|
||||
var cpuNumaPin = make([]*desc.SCpuNumaPin, 0)
|
||||
for nodeId, numaCpus := range nodeNumaCpus {
|
||||
if s.manager.numaAllocate {
|
||||
unodeId := uint16(nodeId)
|
||||
pcpus := cpuset.NewCPUSet(numaCpus.Cpuset...).String()
|
||||
memPin := &desc.SCpuNumaPin{
|
||||
SizeMB: numaCpus.MemSizeKB / 1024, // MB
|
||||
HostNodes: &unodeId,
|
||||
Pcpus: &pcpus,
|
||||
Regular: numaCpus.Regular,
|
||||
}
|
||||
cpuNumaPin = append(cpuNumaPin, memPin)
|
||||
}
|
||||
cpus = append(cpus, numaCpus.Cpuset...)
|
||||
}
|
||||
|
||||
if s.manager.numaAllocate {
|
||||
srcDesc.VcpuPin = nil
|
||||
srcDesc.CpuNumaPin = nil
|
||||
var cpuNumaPin []*desc.SCpuNumaPin
|
||||
if len(s.Desc.CpuNumaPin) > 0 {
|
||||
// cpu numa pin allocated by controller
|
||||
cpuNumaPin = s.Desc.CpuNumaPin
|
||||
} else {
|
||||
if scpuset, ok := srcDesc.Metadata[api.VM_METADATA_CGROUP_CPUSET]; ok {
|
||||
s.manager.cpuSet.Lock.Lock()
|
||||
s.manager.cpuSet.ReleaseCpus(cpus, int(srcDesc.Cpu))
|
||||
s.manager.cpuSet.Lock.Unlock()
|
||||
|
||||
cpusetJson, err := jsonutils.ParseString(scpuset)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse server %s cpuset %s: %s", s.Id, scpuset, err)
|
||||
return errors.Errorf("failed parse server %s cpuset %s: %s", s.Id, scpuset, err)
|
||||
}
|
||||
input := new(api.ServerCPUSetInput)
|
||||
err = cpusetJson.Unmarshal(input)
|
||||
if err != nil {
|
||||
log.Errorf("failed unmarshal server %s cpuset %s", s.Id, err)
|
||||
return errors.Errorf("failed unmarshal server %s cpuset %s", s.Id, err)
|
||||
}
|
||||
cpus = input.CPUS
|
||||
// allocate cpu numa pin local
|
||||
nodeNumaCpus, err := s.manager.cpuSet.AllocCpusetWithNodeCount(int(srcDesc.Cpu), srcDesc.Mem*1024, len(srcDesc.MemDesc.Mem.Mems)+1)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "AllocCpusetWithNodeCount")
|
||||
}
|
||||
|
||||
srcDesc.VcpuPin = []desc.SCpuPin{
|
||||
{
|
||||
Vcpus: fmt.Sprintf("0-%d", srcDesc.Cpu-1),
|
||||
Pcpus: cpuset.NewCPUSet(cpus...).String(),
|
||||
},
|
||||
var cpus = make([]int, 0)
|
||||
cpuNumaPin = make([]*desc.SCpuNumaPin, 0)
|
||||
for nodeId, numaCpus := range nodeNumaCpus {
|
||||
if s.manager.numaAllocate {
|
||||
unodeId := uint16(nodeId)
|
||||
vcpuPin := make([]desc.SVCpuPin, len(numaCpus.Cpuset))
|
||||
for i := range numaCpus.Cpuset {
|
||||
vcpuPin[i].Pcpu = numaCpus.Cpuset[i]
|
||||
}
|
||||
|
||||
memPin := &desc.SCpuNumaPin{
|
||||
SizeMB: numaCpus.MemSizeKB / 1024, // MB
|
||||
NodeId: &unodeId,
|
||||
VcpuPin: vcpuPin,
|
||||
Unregular: numaCpus.Unregular,
|
||||
}
|
||||
cpuNumaPin = append(cpuNumaPin, memPin)
|
||||
}
|
||||
cpus = append(cpus, numaCpus.Cpuset...)
|
||||
}
|
||||
for i := range srcDesc.CpuNumaPin {
|
||||
srcDesc.CpuNumaPin[i].Regular = false
|
||||
|
||||
if s.manager.numaAllocate {
|
||||
// reset origin cpu numa pin
|
||||
srcDesc.VcpuPin = nil
|
||||
srcDesc.CpuNumaPin = nil
|
||||
} else {
|
||||
// if host not enable cpu numa pin
|
||||
if scpuset, ok := srcDesc.Metadata[api.VM_METADATA_CGROUP_CPUSET]; ok {
|
||||
s.manager.cpuSet.Lock.Lock()
|
||||
s.manager.cpuSet.ReleaseCpus(cpus, int(srcDesc.Cpu))
|
||||
s.manager.cpuSet.Lock.Unlock()
|
||||
|
||||
cpusetJson, err := jsonutils.ParseString(scpuset)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse server %s cpuset %s: %s", s.Id, scpuset, err)
|
||||
return errors.Errorf("failed parse server %s cpuset %s: %s", s.Id, scpuset, err)
|
||||
}
|
||||
input := new(api.ServerCPUSetInput)
|
||||
err = cpusetJson.Unmarshal(input)
|
||||
if err != nil {
|
||||
log.Errorf("failed unmarshal server %s cpuset %s", s.Id, err)
|
||||
return errors.Errorf("failed unmarshal server %s cpuset %s", s.Id, err)
|
||||
}
|
||||
cpus = input.CPUS
|
||||
}
|
||||
|
||||
srcDesc.VcpuPin = []desc.SCpuPin{
|
||||
{
|
||||
Vcpus: fmt.Sprintf("0-%d", srcDesc.Cpu-1),
|
||||
Pcpus: cpuset.NewCPUSet(cpus...).String(),
|
||||
},
|
||||
}
|
||||
for i := range srcDesc.CpuNumaPin {
|
||||
srcDesc.CpuNumaPin[i].Unregular = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cpuNumaPin) > 0 {
|
||||
srcDesc.MemDesc.Mem.SMemDesc.SetHostNodes(int(*cpuNumaPin[0].HostNodes))
|
||||
srcDesc.MemDesc.Mem.SMemDesc.SetHostNodes(int(*cpuNumaPin[0].NodeId))
|
||||
for i := range srcDesc.MemDesc.Mem.Mems {
|
||||
srcDesc.MemDesc.Mem.Mems[i].SetHostNodes(int(*cpuNumaPin[i+1].HostNodes))
|
||||
srcDesc.MemDesc.Mem.Mems[i].SetHostNodes(int(*cpuNumaPin[i+1].NodeId))
|
||||
}
|
||||
srcDesc.CpuNumaPin = cpuNumaPin
|
||||
} else {
|
||||
@@ -448,7 +462,7 @@ func (s *SKVMGuestInstance) initLiveDescFromSourceGuest(srcDesc *desc.SGuestDesc
|
||||
}
|
||||
|
||||
s.Desc = srcDesc
|
||||
err = s.loadGuestPciAddresses()
|
||||
err := s.loadGuestPciAddresses()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "initLiveDescFromSourceGuest")
|
||||
}
|
||||
@@ -658,26 +672,12 @@ func (s *SKVMGuestInstance) loadGuestCpuset(m *SGuestManager) error {
|
||||
m.cpuSet.LoadCpus(pcpuSet.ToSlice(), vcpuSet.Size())
|
||||
}
|
||||
for _, numaCpuset := range s.Desc.CpuNumaPin {
|
||||
pcpuSet, err := cpuset.Parse(*numaCpuset.Pcpus)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse %s pcpus: %s", s.GetName(), *numaCpuset.Pcpus)
|
||||
continue
|
||||
}
|
||||
vcpuCount := int(s.Desc.Cpu)
|
||||
if numaCpuset.Vcpus != nil {
|
||||
vcpuSet, err := cpuset.Parse(*numaCpuset.Vcpus)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse %s vcpus: %s", s.GetName(), *numaCpuset.Vcpus)
|
||||
continue
|
||||
}
|
||||
vcpuCount = vcpuSet.Size()
|
||||
}
|
||||
hostNodes := -1
|
||||
if numaCpuset.HostNodes != nil {
|
||||
hostNodes = int(*numaCpuset.HostNodes)
|
||||
pcpus := make([]int, 0)
|
||||
for i := range numaCpuset.VcpuPin {
|
||||
pcpus = append(pcpus, numaCpuset.VcpuPin[i].Pcpu)
|
||||
}
|
||||
|
||||
m.cpuSet.LoadNumaCpus(numaCpuset.SizeMB, hostNodes, pcpuSet.ToSlice(), vcpuCount)
|
||||
m.cpuSet.LoadNumaCpus(numaCpuset.SizeMB, int(*numaCpuset.NodeId), pcpus, len(numaCpuset.VcpuPin))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -748,7 +748,7 @@ func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params interfa
|
||||
return nil, errors.Wrap(err, "fuse mount")
|
||||
}
|
||||
|
||||
var vcpuOrder = make([]string, 0)
|
||||
var vcpuOrder = make([][]int, 0)
|
||||
isMigrate := jsonutils.QueryBoolean(data, "need_migrate", false)
|
||||
if isMigrate {
|
||||
var sourceDesc = new(desc.SGuestDesc)
|
||||
@@ -757,10 +757,11 @@ func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params interfa
|
||||
return nil, errors.Wrap(err, "unmarshal src desc")
|
||||
}
|
||||
for i := range sourceDesc.CpuNumaPin {
|
||||
if sourceDesc.CpuNumaPin[i].Vcpus != nil {
|
||||
vcpus := *sourceDesc.CpuNumaPin[i].Vcpus
|
||||
vcpuOrder = append(vcpuOrder, vcpus)
|
||||
vcpus := make([]int, 0)
|
||||
for j := range sourceDesc.CpuNumaPin[i].VcpuPin {
|
||||
vcpus = append(vcpus, sourceDesc.CpuNumaPin[i].VcpuPin[j].Vcpu)
|
||||
}
|
||||
vcpuOrder = append(vcpuOrder, vcpus)
|
||||
}
|
||||
err = s.initLiveDescFromSourceGuest(sourceDesc)
|
||||
} else {
|
||||
@@ -2719,9 +2720,13 @@ func (s *SKVMGuestInstance) setCgroupCPUSet() error {
|
||||
}
|
||||
cpusetStr = strings.Join(cpus, ",")
|
||||
} else {
|
||||
pcpuSetBuilder := cpuset.NewBuilder()
|
||||
for i := range s.Desc.CpuNumaPin {
|
||||
cpusetStr += fmt.Sprintf(",%s", *s.Desc.CpuNumaPin[i].Pcpus)
|
||||
for j := range s.Desc.CpuNumaPin[i].VcpuPin {
|
||||
pcpuSetBuilder.Add(s.Desc.CpuNumaPin[i].VcpuPin[j].Pcpu)
|
||||
}
|
||||
}
|
||||
cpusetStr = pcpuSetBuilder.Result().String()
|
||||
}
|
||||
|
||||
guestPid := strconv.Itoa(s.GetPid())
|
||||
@@ -2737,20 +2742,18 @@ func (s *SKVMGuestInstance) setCgroupCPUSet() error {
|
||||
}
|
||||
|
||||
for i := range s.Desc.CpuNumaPin {
|
||||
if !s.Desc.CpuNumaPin[i].Regular || s.Desc.CpuNumaPin[i].Vcpus == nil {
|
||||
if s.Desc.CpuNumaPin[i].Unregular || s.Desc.CpuNumaPin[i].VcpuPin == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
vcpuSet, _ := cpuset.Parse(*s.Desc.CpuNumaPin[i].Vcpus)
|
||||
pcpuSet := *s.Desc.CpuNumaPin[i].Pcpus
|
||||
for _, vcpuId := range vcpuSet.ToSlice() {
|
||||
vcpuThreadId, ok := vcpuThreads[vcpuId]
|
||||
for j := range s.Desc.CpuNumaPin[i].VcpuPin {
|
||||
vcpuThreadId, ok := vcpuThreads[s.Desc.CpuNumaPin[i].VcpuPin[j].Vcpu]
|
||||
if !ok {
|
||||
return errors.Errorf("failed get vcpu %d thread id from %v", vcpuId, vcpuThreads)
|
||||
return errors.Errorf("failed get vcpu %d thread id from %v", s.Desc.CpuNumaPin[i].VcpuPin[j].Vcpu, vcpuThreads)
|
||||
}
|
||||
|
||||
pcpu := s.Desc.CpuNumaPin[i].VcpuPin[j].Pcpu
|
||||
vcpuCgname := path.Join(cgName, vcpuThreadId)
|
||||
taskVcpu := cgrouputils.NewCGroupSubCPUSetTask(guestPid, vcpuCgname, 0, pcpuSet, []string{vcpuThreadId})
|
||||
taskVcpu := cgrouputils.NewCGroupSubCPUSetTask(guestPid, vcpuCgname, 0, strconv.Itoa(pcpu), []string{vcpuThreadId})
|
||||
if !taskVcpu.SetTask() {
|
||||
return errors.Errorf("Vcpu set cgroup cpuset task failed")
|
||||
}
|
||||
@@ -2778,12 +2781,16 @@ func (s *SKVMGuestInstance) allocGuestNumaCpuset() error {
|
||||
for nodeId, numaCpus := range nodeNumaCpus {
|
||||
if s.manager.numaAllocate {
|
||||
unodeId := uint16(nodeId)
|
||||
pcpus := cpuset.NewCPUSet(numaCpus.Cpuset...).String()
|
||||
vcpuPin := make([]desc.SVCpuPin, len(numaCpus.Cpuset))
|
||||
for i := range numaCpus.Cpuset {
|
||||
vcpuPin[i].Pcpu = numaCpus.Cpuset[i]
|
||||
}
|
||||
|
||||
memPin := &desc.SCpuNumaPin{
|
||||
SizeMB: numaCpus.MemSizeKB / 1024, // MB
|
||||
HostNodes: &unodeId,
|
||||
Pcpus: &pcpus,
|
||||
Regular: numaCpus.Regular,
|
||||
NodeId: &unodeId,
|
||||
VcpuPin: vcpuPin,
|
||||
Unregular: numaCpus.Unregular,
|
||||
}
|
||||
cpuNumaPin = append(cpuNumaPin, memPin)
|
||||
}
|
||||
@@ -2996,11 +3003,9 @@ func (s *SKVMGuestInstance) hotPlugCpus() error {
|
||||
var vcpuSet = make([]int, 0)
|
||||
if len(s.Desc.MemDesc.Mem.Mems) > 0 {
|
||||
for i := range s.Desc.CpuNumaPin {
|
||||
vcpus, err := cpuset.Parse(*s.Desc.CpuNumaPin[i].Vcpus)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parse vcpus")
|
||||
for j := range s.Desc.CpuNumaPin[i].VcpuPin {
|
||||
vcpuSet = append(vcpuSet, s.Desc.CpuNumaPin[i].VcpuPin[j].Vcpu)
|
||||
}
|
||||
vcpuSet = append(vcpuSet, vcpus.ToSlice()...)
|
||||
}
|
||||
}
|
||||
return s.startHotPlugVcpus(vcpuSet)
|
||||
|
||||
@@ -883,11 +883,13 @@ func (s *SKVMGuestInstance) initCpuDesc(cpuMax uint) error {
|
||||
}
|
||||
s.Desc.CpuDesc = cpuDesc
|
||||
|
||||
err = s.allocGuestNumaCpuset()
|
||||
if err != nil {
|
||||
return err
|
||||
// if region not allocate cpu numa pin
|
||||
if len(s.Desc.CpuNumaPin) == 0 {
|
||||
err = s.allocGuestNumaCpuset()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -917,9 +919,15 @@ func (s *SKVMGuestInstance) initGuestMemObjects(memSizeMB int64) error {
|
||||
var numaMems int64
|
||||
var numaCpus = int(s.Desc.CpuDesc.MaxCpus) / len(s.Desc.CpuNumaPin)
|
||||
var leastCpus = int(s.Desc.CpuDesc.MaxCpus) % len(s.Desc.CpuNumaPin)
|
||||
var numaVcpuCount = int(s.Desc.Cpu) / len(s.Desc.CpuNumaPin)
|
||||
var cpuStart = 0
|
||||
var cpuEnd = numaCpus - 1
|
||||
|
||||
var mems = make([]desc.SMemDesc, 0)
|
||||
for i := 0; i < len(s.Desc.CpuNumaPin); i++ {
|
||||
if s.Desc.CpuNumaPin[i].SizeMB <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
numaMems += s.Desc.CpuNumaPin[i].SizeMB
|
||||
memId := "mem"
|
||||
nodeId := uint16(i)
|
||||
@@ -927,25 +935,23 @@ func (s *SKVMGuestInstance) initGuestMemObjects(memSizeMB int64) error {
|
||||
memId += strconv.Itoa(i - 1)
|
||||
}
|
||||
|
||||
vcpuCount := numaVcpuCount
|
||||
if i == 0 {
|
||||
vcpuCount += int(s.Desc.Cpu) % len(s.Desc.CpuNumaPin)
|
||||
}
|
||||
|
||||
cpuStart := i * numaCpus
|
||||
cpuEnd := (i+1)*numaCpus - 1
|
||||
if i+1 == len(s.Desc.CpuNumaPin) {
|
||||
cpuEnd += leastCpus
|
||||
}
|
||||
vcpus := fmt.Sprintf("%d-%d", cpuStart, cpuEnd)
|
||||
vcpuAlloc := fmt.Sprintf("%d-%d", cpuStart, cpuStart+vcpuCount-1)
|
||||
s.Desc.CpuNumaPin[i].Vcpus = &vcpuAlloc
|
||||
|
||||
if !s.Desc.CpuNumaPin[i].Regular {
|
||||
for j := range s.Desc.CpuNumaPin[i].VcpuPin {
|
||||
s.Desc.CpuNumaPin[i].VcpuPin[j].Vcpu = cpuStart + j
|
||||
}
|
||||
|
||||
cpuStart = cpuEnd + 1
|
||||
cpuEnd = cpuStart + numaCpus - 1
|
||||
|
||||
if s.Desc.CpuNumaPin[i].Unregular {
|
||||
continue
|
||||
}
|
||||
memDesc := desc.NewMemDesc(s.memObjectType(), memId, &nodeId, &vcpus)
|
||||
memDesc.Options = s.getMemObjectOptions(s.Desc.CpuNumaPin[i].SizeMB, s.Desc.Uuid, s.Desc.CpuNumaPin[i].HostNodes)
|
||||
memDesc.Options = s.getMemObjectOptions(s.Desc.CpuNumaPin[i].SizeMB, s.Desc.Uuid, s.Desc.CpuNumaPin[i].NodeId)
|
||||
mems = append(mems, *memDesc)
|
||||
}
|
||||
if len(mems) == 0 {
|
||||
@@ -954,9 +960,6 @@ func (s *SKVMGuestInstance) initGuestMemObjects(memSizeMB int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if numaMems != memSizeMB {
|
||||
return errors.Errorf("numa memory size not equal request mem size")
|
||||
}
|
||||
s.Desc.MemDesc.Mem = desc.NewMemsDesc(mems[0], mems[1:])
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ type SHostInfo struct {
|
||||
onHostDown string
|
||||
reservedCpusInfo *api.HostReserveCpusInput
|
||||
enableNumaAllocate bool
|
||||
cpuCmtBound int
|
||||
|
||||
IsolatedDeviceMan isolated_device.IsolatedDeviceManager
|
||||
|
||||
@@ -541,6 +542,9 @@ func (h *SHostInfo) detectHostInfo() error {
|
||||
h.sysinfo.Topology = topoInfo
|
||||
h.sysinfo.CPUInfo = cpuInfo
|
||||
|
||||
if err = h.GetNodeHugepages(); err != nil {
|
||||
return errors.Wrap(err, "GetNodeHugepages")
|
||||
}
|
||||
system_service.Init()
|
||||
if options.HostOptions.CheckSystemServices {
|
||||
if err := h.checkSystemServices(); err != nil {
|
||||
@@ -630,6 +634,33 @@ func (h *SHostInfo) EnableTransparentHugepages() {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SHostInfo) GetNodeHugepages() error {
|
||||
if options.HostOptions.HugepagesOption != "native" {
|
||||
return nil
|
||||
}
|
||||
|
||||
hugepageSizeKB := h.sysinfo.HugepageSizeKb
|
||||
nodeHugepages := make([]hostapi.HostNodeHugepageNr, len(h.sysinfo.Topology.Nodes))
|
||||
|
||||
for i := range h.sysinfo.Topology.Nodes {
|
||||
nodeId := h.sysinfo.Topology.Nodes[i].ID
|
||||
nodeHugepagePath := fmt.Sprintf("/sys/devices/system/node/node%d/hugepages/hugepages-%dkB", nodeId, hugepageSizeKB)
|
||||
if !fileutils2.Exists(nodeHugepagePath) {
|
||||
return errors.Errorf("node %s has no hugepages ?", nodeHugepagePath)
|
||||
}
|
||||
nrHugepage, err := fileutils2.FileGetIntContent(path.Join(nodeHugepagePath, "nr_hugepages"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get node nr hugepage")
|
||||
}
|
||||
|
||||
nodeHugepages[i].NodeId = nodeId
|
||||
nodeHugepages[i].HugepageNr = nrHugepage
|
||||
}
|
||||
|
||||
h.sysinfo.NodeHugepages = nodeHugepages
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SHostInfo) GetMemory() int {
|
||||
return h.Mem.Total
|
||||
}
|
||||
@@ -1167,6 +1198,7 @@ func (h *SHostInfo) initHostRecord() (*api.HostDetails, error) {
|
||||
}
|
||||
|
||||
h.HostId = hostInfo.Id
|
||||
h.cpuCmtBound = int(hostInfo.CpuCmtbound)
|
||||
hostInfo, err = h.updateHostMetadata(hostInfo.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "updateHostMetadata")
|
||||
@@ -2466,6 +2498,10 @@ func (h *SHostInfo) GetContainerRuntimeEndpoint() string {
|
||||
return options.HostOptions.ContainerRuntimeEndpoint
|
||||
}
|
||||
|
||||
func (h *SHostInfo) CpuCmtBound() int {
|
||||
return h.cpuCmtBound
|
||||
}
|
||||
|
||||
func NewHostInfo() (*SHostInfo, error) {
|
||||
var res = new(SHostInfo)
|
||||
res.sysinfo = &SSysInfo{}
|
||||
|
||||
@@ -327,9 +327,10 @@ type SSysInfo struct {
|
||||
|
||||
StorageType string `json:"storage_type"`
|
||||
|
||||
HugepagesOption string `json:"hugepages_option"`
|
||||
HugepageSizeKb int `json:"hugepage_size_kb"`
|
||||
HugepageNr *int `json:"hugepage_nr"`
|
||||
HugepagesOption string `json:"hugepages_option"`
|
||||
HugepageSizeKb int `json:"hugepage_size_kb"`
|
||||
HugepageNr *int `json:"hugepage_nr"`
|
||||
NodeHugepages []hostapi.HostNodeHugepageNr `json:"node_hugepages"`
|
||||
|
||||
Topology *hostapi.HostTopology `json:"topology"`
|
||||
CPUInfo *hostapi.HostCPUInfo `json:"cpu_info"`
|
||||
|
||||
@@ -60,6 +60,7 @@ type IHost interface {
|
||||
IsHugepagesEnabled() bool
|
||||
HugepageSizeKb() int
|
||||
IsNumaAllocateEnabled() bool
|
||||
CpuCmtBound() int
|
||||
|
||||
IsKvmSupport() bool
|
||||
IsNestedVirtualization() bool
|
||||
|
||||
@@ -132,8 +132,9 @@ type SHostOptions struct {
|
||||
SetVncPassword bool `default:"true" help:"Auto set vnc password after monitor connected"`
|
||||
UseBootVga bool `default:"false" help:"Use boot VGA GPU for guest"`
|
||||
|
||||
EnableCpuBinding bool `default:"true" help:"Enable cpu binding and rebalance"`
|
||||
EnableOpenflowController bool `default:"false"`
|
||||
EnableHostAgentNumaAllocate bool `default:"false" help:"Enable host agent numa allocate"`
|
||||
EnableCpuBinding bool `default:"true" help:"Enable cpu binding and rebalance"`
|
||||
EnableOpenflowController bool `default:"false"`
|
||||
|
||||
PingRegionInterval int `default:"60" help:"interval to ping region, deefault is 1 minute"`
|
||||
LogSystemdUnits []string `help:"Systemd units log collected by fluent-bit"`
|
||||
|
||||
@@ -62,6 +62,10 @@ func (p *ClassMetadataPredicate) Clone() core.FitPredicate {
|
||||
|
||||
func (p *ClassMetadataPredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
info := u.SchedData()
|
||||
if info.ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
tenant, err := db.TenantCacheManager.FetchTenantById(ctx, info.Project)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch tenant %s", info.Project)
|
||||
|
||||
@@ -48,6 +48,9 @@ func (p *CloudproviderSchedtagPredicate) PreExecute(ctx context.Context, u *core
|
||||
if driver == nil || !driver.DoScheduleCloudproviderTagFilter() {
|
||||
return false, nil
|
||||
}
|
||||
if u.SchedData().ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
return p.ServerBaseSchedtagPredicate.PreExecute(ctx, u, cs)
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ func (f *ImagePredicate) Clone() core.FitPredicate {
|
||||
}
|
||||
|
||||
func (f *ImagePredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
if u.SchedData().ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
disks := u.SchedData().Disks
|
||||
if len(disks) == 0 {
|
||||
return false, nil
|
||||
|
||||
@@ -16,7 +16,11 @@ package guest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
)
|
||||
@@ -64,6 +68,40 @@ func (p *MemoryPredicate) Execute(ctx context.Context, u *core.Unit, c core.Cand
|
||||
h.AppendInsufficientResourceError(reqMemSize, totalMemSize, freeMemSize)
|
||||
}
|
||||
|
||||
if cpuNumaFree := getter.GetFreeCpuNuma(); cpuNumaFree != nil {
|
||||
allcateEnough := false
|
||||
reqCpuCount := d.Ncpu
|
||||
if d.CpuNumaPin != nil {
|
||||
nodeCount := len(d.CpuNumaPin)
|
||||
if scheduler.NodesFreeCpuEnough(nodeCount, d.Ncpu, cpuNumaFree) &&
|
||||
scheduler.NodesFreeMemSizeEnough(nodeCount, int(reqMemSize), cpuNumaFree) {
|
||||
allcateEnough = true
|
||||
}
|
||||
} else {
|
||||
for nodeCount := 1; nodeCount <= len(cpuNumaFree); nodeCount *= 2 {
|
||||
if nodeCount > reqCpuCount {
|
||||
break
|
||||
}
|
||||
|
||||
if !scheduler.NodesFreeCpuEnough(nodeCount, d.Ncpu, cpuNumaFree) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !scheduler.NodesFreeMemSizeEnough(nodeCount, int(reqMemSize), cpuNumaFree) {
|
||||
continue
|
||||
}
|
||||
allcateEnough = true
|
||||
}
|
||||
}
|
||||
|
||||
if !allcateEnough {
|
||||
h.AppendPredicateFailMsg(
|
||||
fmt.Sprintf("cpu numa free %s can't alloc with req mem %v req cpu %v ",
|
||||
jsonutils.Marshal(cpuNumaFree).String(), d.Memory, d.Ncpu),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
h.SetCapacity(freeMemSize / reqMemSize)
|
||||
return h.GetResult()
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ func (p *MigratePredicate) Clone() core.FitPredicate {
|
||||
}
|
||||
|
||||
func (p *MigratePredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
if u.SchedData().ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return len(u.SchedData().HostId) > 0, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,10 @@ func (p *StoragePredicate) PreExecute(ctx context.Context, u *core.Unit, cs []co
|
||||
if driver != nil && !driver.DoScheduleStorageFilter() {
|
||||
return false, nil
|
||||
}
|
||||
if u.SchedData().ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@ func (f *IsolatedDevicePredicate) Clone() core.FitPredicate {
|
||||
|
||||
func (f *IsolatedDevicePredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
data := u.SchedData()
|
||||
|
||||
if data.ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if len(data.IsolatedDevices) > 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -75,6 +75,11 @@ type INetworkNicCountGetter interface {
|
||||
|
||||
func (p *NetworkPredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
data := u.SchedData()
|
||||
|
||||
if data.ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if len(data.Networks) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -417,6 +417,10 @@ func (p *BaseSchedtagPredicate) PreExecute(ctx context.Context, sp ISchedtagPred
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if u.SchedData().ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
p.Hypervisor = u.GetHypervisor()
|
||||
p.Provider = u.SchedInfo.Provider
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@ func (p *InstanceTypePredicate) Clone() core.FitPredicate {
|
||||
|
||||
func (p *InstanceTypePredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
driver := u.GetHypervisorDriver()
|
||||
if u.SchedData().ResetCpuNumaPin {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if u.SchedData().InstanceType == "" || (driver == nil || !driver.DoScheduleSKUFilter()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 guest
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/algorithm/priorities"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
)
|
||||
|
||||
type CpuNumaPinPriority struct {
|
||||
priorities.BasePriority
|
||||
}
|
||||
|
||||
func (p *CpuNumaPinPriority) Name() string {
|
||||
return "cpu_numa_pin"
|
||||
}
|
||||
|
||||
func (p *CpuNumaPinPriority) Clone() core.Priority {
|
||||
return &CpuNumaPinPriority{}
|
||||
}
|
||||
|
||||
func (p *CpuNumaPinPriority) Map(u *core.Unit, c core.Candidater) (core.HostPriority, error) {
|
||||
h := priorities.NewPriorityHelper(p, u, c)
|
||||
|
||||
getter := c.Getter()
|
||||
if getter.Host().EnableNumaAllocate && getter.NumaAllocateEnabled() && len(u.SchedData().CpuNumaPin) == 0 {
|
||||
cpuNumaFree := getter.GetFreeCpuNuma()
|
||||
|
||||
reqCpuCount := u.SchedInfo.Ncpu
|
||||
reqMemSize := u.SchedInfo.Memory
|
||||
nodeCount := 1
|
||||
for ; nodeCount <= len(cpuNumaFree); nodeCount *= 2 {
|
||||
if nodeCount > reqCpuCount {
|
||||
nodeCount = 0
|
||||
break
|
||||
}
|
||||
|
||||
if scheduler.NodesFreeCpuEnough(nodeCount, reqCpuCount, cpuNumaFree) &&
|
||||
scheduler.NodesFreeMemSizeEnough(nodeCount, int(reqMemSize), cpuNumaFree) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if nodeCount > 0 && nodeCount <= len(cpuNumaFree) {
|
||||
score := 100 / nodeCount
|
||||
h.SetScore(int(score))
|
||||
}
|
||||
}
|
||||
return h.GetResult()
|
||||
}
|
||||
@@ -59,5 +59,6 @@ func defaultPriorities() sets.String {
|
||||
factory.RegisterPriority("guest-lowload", &priorityguest.LowLoadPriority{}, 1),
|
||||
factory.RegisterPriority("guest-creating", &priorityguest.CreatingPriority{}, 1),
|
||||
factory.RegisterPriority("guest-capacity", &priorityguest.CapacityPriority{}, 1),
|
||||
factory.RegisterPriority("guest-cpunumapin", &priorityguest.CpuNumaPinPriority{}, 1),
|
||||
)
|
||||
}
|
||||
|
||||
+17
@@ -19,6 +19,7 @@ import (
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
@@ -44,6 +45,14 @@ func (h baremetalGetter) FreeMemorySize(_ bool) int64 {
|
||||
return h.bm.FreeMemSize()
|
||||
}
|
||||
|
||||
func (h *baremetalGetter) NumaAllocateEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *baremetalGetter) GetFreeCpuNuma() []*scheduler.SFreeNumaCpuMem {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h baremetalGetter) IsEmpty() bool {
|
||||
return h.bm.ServerID == ""
|
||||
}
|
||||
@@ -106,6 +115,14 @@ func (bd *BaremetalDesc) IndexKey() string {
|
||||
return bd.Id
|
||||
}
|
||||
|
||||
func (bd *BaremetalDesc) AllocCpuNumaPin(vcpuCount, memSizeKB int) []scheduler.SCpuNumaPin {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bd *BaremetalDesc) AllocCpuNumaPinWithNodeCount(vcpuCount, memSizeKB, nodeCount int) []scheduler.SCpuNumaPin {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bd *BaremetalDesc) FreeCPUCount() int64 {
|
||||
if bd.ServerID == "" {
|
||||
return int64(bd.CpuCount)
|
||||
|
||||
+1
-1
@@ -443,7 +443,7 @@ func (b BaseHostDesc) GetSchedDesc() *jsonutils.JSONDict {
|
||||
func (b *BaseHostDesc) GetPendingUsage() *schedmodels.SPendingUsage {
|
||||
usage, err := schedmodels.HostPendingUsageManager.GetPendingUsage(b.GetId())
|
||||
if err != nil {
|
||||
return schedmodels.NewPendingUsageBySchedInfo(b.GetId(), nil)
|
||||
return schedmodels.NewPendingUsageBySchedInfo(b.GetId(), nil, nil)
|
||||
}
|
||||
return usage
|
||||
}
|
||||
|
||||
+461
-7
@@ -15,10 +15,13 @@
|
||||
package candidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
gosync "sync"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
@@ -26,11 +29,14 @@ import (
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
"yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
computedb "yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
o "yunion.io/x/onecloud/pkg/scheduler/options"
|
||||
"yunion.io/x/onecloud/pkg/util/cgrouputils/cpuset"
|
||||
)
|
||||
|
||||
type hostGetter struct {
|
||||
@@ -65,6 +71,14 @@ func (h *hostGetter) FreeMemorySize(useRsvd bool) int64 {
|
||||
return h.h.GetFreeMemSize(useRsvd)
|
||||
}
|
||||
|
||||
func (h *hostGetter) NumaAllocateEnabled() bool {
|
||||
return h.h.HostTopo.NumaEnabled
|
||||
}
|
||||
|
||||
func (h *hostGetter) GetFreeCpuNuma() []*scheduler.SFreeNumaCpuMem {
|
||||
return h.h.GetFreeCpuNuma()
|
||||
}
|
||||
|
||||
func (h *hostGetter) RunningMemorySize() int64 {
|
||||
return h.h.RunningMemSize
|
||||
}
|
||||
@@ -116,6 +130,9 @@ type HostDesc struct {
|
||||
RequiredMemSize int64 `json:"required_mem_size"`
|
||||
FakeDeletedMemSize int64 `json:"fake_deleted_mem_size"`
|
||||
|
||||
EnableCpuNumaAllocate bool `json:"enable_cpu_numa_allocate"`
|
||||
HostTopo *SHostTopo `json:"host_topo"`
|
||||
|
||||
// storage
|
||||
StorageTypes []string `json:"storage_types"`
|
||||
|
||||
@@ -135,6 +152,346 @@ type HostDesc struct {
|
||||
GuestReservedResourceUsed *ReservedResource `json:"guest_reserved_used"`
|
||||
}
|
||||
|
||||
type CPUDie struct {
|
||||
LogicalProcessors cpuset.CPUSet
|
||||
CpuFree map[int]int
|
||||
VcpuCount int
|
||||
}
|
||||
|
||||
func (d *CPUDie) initCpuFree(cpuCmtbound int) {
|
||||
cpuFree := map[int]int{}
|
||||
for _, cpuId := range d.LogicalProcessors.ToSliceNoSort() {
|
||||
cpuFree[cpuId] = cpuCmtbound
|
||||
}
|
||||
d.CpuFree = cpuFree
|
||||
}
|
||||
|
||||
type SorttedCPUDie []*CPUDie
|
||||
|
||||
func (pq SorttedCPUDie) Len() int { return len(pq) }
|
||||
|
||||
func (pq SorttedCPUDie) Less(i, j int) bool {
|
||||
return pq[i].VcpuCount < pq[j].VcpuCount
|
||||
}
|
||||
|
||||
func (pq SorttedCPUDie) Swap(i, j int) {
|
||||
pq[i], pq[j] = pq[j], pq[i]
|
||||
}
|
||||
|
||||
func (pq *SorttedCPUDie) Push(item interface{}) {
|
||||
*pq = append(*pq, item.(*CPUDie))
|
||||
}
|
||||
|
||||
func (pq *SorttedCPUDie) Pop() interface{} {
|
||||
old := *pq
|
||||
n := len(old)
|
||||
item := old[n-1]
|
||||
old[n-1] = nil // avoid memory leak
|
||||
*pq = old[0 : n-1]
|
||||
return item
|
||||
}
|
||||
|
||||
func (pq *SorttedCPUDie) LoadCpus(cpus []int, vcpuCount int) {
|
||||
var cpuDies = map[int][]int{}
|
||||
for i := 0; i < len(cpus); i++ {
|
||||
for j := 0; j < len(*pq); j++ {
|
||||
if (*pq)[j].LogicalProcessors.Contains(cpus[i]) {
|
||||
if cpuDie, ok := cpuDies[j]; !ok {
|
||||
cpuDies[j] = []int{cpus[i]}
|
||||
} else {
|
||||
cpuDies[j] = append(cpuDie, cpus[i])
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(*pq); i++ {
|
||||
if cpus, ok := cpuDies[i]; ok {
|
||||
d := (*pq)[i]
|
||||
for _, cpu := range cpus {
|
||||
d.CpuFree[cpu] -= 1
|
||||
}
|
||||
d.VcpuCount += vcpuCount
|
||||
}
|
||||
}
|
||||
sort.Sort(pq)
|
||||
}
|
||||
|
||||
type NumaNode struct {
|
||||
CpuDies SorttedCPUDie
|
||||
LogicalProcessors cpuset.CPUSet
|
||||
VcpuCount int
|
||||
CpuCount int
|
||||
|
||||
NodeId int
|
||||
NumaHugeMemSizeKB int
|
||||
NumaHugeFreeMemSizeKB int
|
||||
}
|
||||
|
||||
func (n *NumaNode) allocCpuset(vcpuCount int, usedCpu map[int]int) {
|
||||
for i := range n.CpuDies {
|
||||
for cpuId, nFree := range n.CpuDies[i].CpuFree {
|
||||
if cnt, ok := usedCpu[cpuId]; ok {
|
||||
if cnt < nFree {
|
||||
usedCpu[cpuId] = cnt + 1
|
||||
vcpuCount -= 1
|
||||
if vcpuCount <= 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if nFree > 0 {
|
||||
usedCpu[cpuId] = 1
|
||||
vcpuCount -= 1
|
||||
if vcpuCount <= 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
n.allocCpuset(vcpuCount, usedCpu)
|
||||
}
|
||||
|
||||
func (n *NumaNode) AllocCpuset(vcpuCount int) []int {
|
||||
var usedCpuCount = make(map[int]int)
|
||||
n.allocCpuset(vcpuCount, usedCpuCount)
|
||||
|
||||
var ret = make([]int, 0)
|
||||
for cpuId, cnt := range usedCpuCount {
|
||||
for cnt > 0 {
|
||||
ret = append(ret, cpuId)
|
||||
cnt -= 1
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func NewNumaNode(nodeId, hugepageSizeKb int, nodeHugepages []hostapi.HostNodeHugepageNr) *NumaNode {
|
||||
n := new(NumaNode)
|
||||
n.LogicalProcessors = cpuset.NewCPUSet()
|
||||
n.NodeId = nodeId
|
||||
|
||||
for i := range nodeHugepages {
|
||||
if nodeHugepages[i].NodeId == nodeId {
|
||||
n.NumaHugeMemSizeKB = nodeHugepages[i].HugepageNr * hugepageSizeKb
|
||||
}
|
||||
}
|
||||
|
||||
n.NumaHugeFreeMemSizeKB = n.NumaHugeMemSizeKB
|
||||
return n
|
||||
}
|
||||
|
||||
type SHostTopo struct {
|
||||
Nodes []*NumaNode
|
||||
NumaEnabled bool
|
||||
CPUCmtbound int
|
||||
}
|
||||
|
||||
func (pq SHostTopo) Len() int { return len(pq.Nodes) }
|
||||
|
||||
func (pq SHostTopo) Less(i, j int) bool {
|
||||
if pq.NumaEnabled {
|
||||
if pq.Nodes[i].NumaHugeFreeMemSizeKB == pq.Nodes[j].NumaHugeFreeMemSizeKB {
|
||||
return pq.Nodes[i].VcpuCount < pq.Nodes[j].VcpuCount
|
||||
}
|
||||
return pq.Nodes[i].NumaHugeFreeMemSizeKB > pq.Nodes[j].NumaHugeFreeMemSizeKB
|
||||
} else {
|
||||
return pq.Nodes[i].VcpuCount < pq.Nodes[j].VcpuCount
|
||||
}
|
||||
}
|
||||
|
||||
func (pq SHostTopo) Swap(i, j int) {
|
||||
pq.Nodes[i], pq.Nodes[j] = pq.Nodes[j], pq.Nodes[i]
|
||||
}
|
||||
|
||||
func (pq *SHostTopo) Push(item interface{}) {
|
||||
(*pq).Nodes = append((*pq).Nodes, item.(*NumaNode))
|
||||
}
|
||||
|
||||
func (h *SHostTopo) LoadCpuNumaPin(guestsCpuNumaPin []scheduler.SCpuNumaPin) {
|
||||
for _, gCpuNumaPin := range guestsCpuNumaPin {
|
||||
var node *NumaNode
|
||||
for i := range h.Nodes {
|
||||
if h.Nodes[i].NodeId == gCpuNumaPin.NodeId {
|
||||
node = h.Nodes[i]
|
||||
}
|
||||
}
|
||||
|
||||
cpus := gCpuNumaPin.CpuPin
|
||||
node.CpuDies.LoadCpus(cpus, len(cpus))
|
||||
if h.NumaEnabled && gCpuNumaPin.MemSizeMB != nil {
|
||||
node.NumaHugeFreeMemSizeKB -= *gCpuNumaPin.MemSizeMB * 1024
|
||||
}
|
||||
node.VcpuCount += len(cpus)
|
||||
}
|
||||
sort.Sort(h)
|
||||
}
|
||||
|
||||
func (h *SHostTopo) nodesEnough(nodeCount, vcpuCount int, memSizeKB int) bool {
|
||||
var leastFree = memSizeKB / nodeCount
|
||||
var leastCpuCount = vcpuCount / nodeCount
|
||||
var remPcpuCount = vcpuCount % nodeCount
|
||||
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
if h.NumaEnabled {
|
||||
if h.Nodes[i].NumaHugeFreeMemSizeKB < leastFree {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
requireCpuCount := leastCpuCount
|
||||
if remPcpuCount > 0 {
|
||||
requireCpuCount += 1
|
||||
remPcpuCount -= 1
|
||||
}
|
||||
if (h.Nodes[i].VcpuCount + requireCpuCount) > h.Nodes[i].CpuCount*h.CPUCmtbound {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *SHostTopo) AllocCpuNumaNodes(vcpuCount, memSizeKB int) []scheduler.SCpuNumaPin {
|
||||
res := make([]scheduler.SCpuNumaPin, 0)
|
||||
for nodeCount := 1; nodeCount <= len(h.Nodes); nodeCount *= 2 {
|
||||
if nodeCount > vcpuCount {
|
||||
break
|
||||
}
|
||||
if ok := h.nodesEnough(nodeCount, vcpuCount, memSizeKB); !ok {
|
||||
log.Infof("node count %d not enough", nodeCount)
|
||||
continue
|
||||
}
|
||||
log.Infof("use node count %d", nodeCount)
|
||||
|
||||
var nodeAllocSize = memSizeKB / nodeCount
|
||||
if h.NumaEnabled {
|
||||
if nodeAllocSize/1024%1024 > 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var pcpuCount = vcpuCount / nodeCount
|
||||
var remPcpuCount = vcpuCount % nodeCount
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
var npcpuCount = pcpuCount
|
||||
if remPcpuCount > 0 {
|
||||
npcpuCount += 1
|
||||
remPcpuCount -= 1
|
||||
}
|
||||
cpuNumaPin := scheduler.SCpuNumaPin{
|
||||
CpuPin: h.Nodes[i].AllocCpuset(npcpuCount),
|
||||
NodeId: h.Nodes[i].NodeId,
|
||||
}
|
||||
if h.NumaEnabled {
|
||||
allocSize := nodeAllocSize / 1024
|
||||
cpuNumaPin.MemSizeMB = &allocSize
|
||||
}
|
||||
res = append(res, cpuNumaPin)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (h *SHostTopo) AllocCpuNumaNodesWithNodeCount(vcpuCount, memSizeKB, nodeCount int) []scheduler.SCpuNumaPin {
|
||||
res := make([]scheduler.SCpuNumaPin, 0)
|
||||
var nodeAllocSize = memSizeKB / nodeCount
|
||||
var pcpuCount = vcpuCount / nodeCount
|
||||
var remPcpuCount = vcpuCount % nodeCount
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
var npcpuCount = pcpuCount
|
||||
if remPcpuCount > 0 {
|
||||
npcpuCount += 1
|
||||
remPcpuCount -= 1
|
||||
}
|
||||
|
||||
cpuNumaPin := scheduler.SCpuNumaPin{
|
||||
CpuPin: h.Nodes[i].AllocCpuset(npcpuCount),
|
||||
NodeId: h.Nodes[i].NodeId,
|
||||
}
|
||||
if h.NumaEnabled {
|
||||
allocSize := nodeAllocSize / 1024
|
||||
cpuNumaPin.MemSizeMB = &allocSize
|
||||
}
|
||||
res = append(res, cpuNumaPin)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (b *HostBuilder) buildHostTopo(
|
||||
desc *HostDesc, reservedCpus *cpuset.CPUSet,
|
||||
hugepageSizeKb int, nodeHugepages []hostapi.HostNodeHugepageNr,
|
||||
info *hostapi.HostTopology,
|
||||
) error {
|
||||
hostTopo := new(SHostTopo)
|
||||
hostTopo.Nodes = make([]*NumaNode, len(info.Nodes))
|
||||
|
||||
hasL3Cache := false
|
||||
for i := 0; i < len(info.Nodes); i++ {
|
||||
node := NewNumaNode(info.Nodes[i].ID, hugepageSizeKb, nodeHugepages)
|
||||
|
||||
cpuDies := make([]*CPUDie, 0)
|
||||
for j := 0; j < len(info.Nodes[i].Caches); j++ {
|
||||
if info.Nodes[i].Caches[j].Level != 3 {
|
||||
continue
|
||||
}
|
||||
hasL3Cache = true
|
||||
cpuDie := new(CPUDie)
|
||||
dieBuilder := cpuset.NewBuilder()
|
||||
for k := 0; k < len(info.Nodes[i].Caches[j].LogicalProcessors); k++ {
|
||||
if reservedCpus != nil && reservedCpus.Contains(int(info.Nodes[i].Caches[j].LogicalProcessors[k])) {
|
||||
continue
|
||||
}
|
||||
dieBuilder.Add(int(info.Nodes[i].Caches[j].LogicalProcessors[k]))
|
||||
}
|
||||
cpuDie.LogicalProcessors = dieBuilder.Result()
|
||||
cpuDie.initCpuFree(int(desc.CPUCmtbound))
|
||||
|
||||
node.CpuCount += cpuDie.LogicalProcessors.Size()
|
||||
node.LogicalProcessors = node.LogicalProcessors.Union(cpuDie.LogicalProcessors)
|
||||
cpuDies = append(cpuDies, cpuDie)
|
||||
|
||||
// TODO: add cpu core builder
|
||||
}
|
||||
if !hasL3Cache {
|
||||
cpuDie := new(CPUDie)
|
||||
dieBuilder := cpuset.NewBuilder()
|
||||
for j := 0; j < len(info.Nodes[i].Cores); j++ {
|
||||
for k := 0; k < len(info.Nodes[i].Cores[j].LogicalProcessors); k++ {
|
||||
if reservedCpus != nil && reservedCpus.Contains(info.Nodes[i].Cores[j].LogicalProcessors[k]) {
|
||||
continue
|
||||
}
|
||||
dieBuilder.Add(info.Nodes[i].Cores[j].LogicalProcessors[k])
|
||||
}
|
||||
}
|
||||
cpuDie.LogicalProcessors = dieBuilder.Result()
|
||||
node.CpuCount += cpuDie.LogicalProcessors.Size()
|
||||
node.LogicalProcessors = node.LogicalProcessors.Union(cpuDie.LogicalProcessors)
|
||||
cpuDies = append(cpuDies, cpuDie)
|
||||
}
|
||||
|
||||
hasL3Cache = false
|
||||
node.CpuDies = cpuDies
|
||||
hostTopo.Nodes[i] = node
|
||||
}
|
||||
hostTopo.CPUCmtbound = int(desc.CPUCmtbound)
|
||||
if len(nodeHugepages) > 0 {
|
||||
hostTopo.NumaEnabled = true
|
||||
}
|
||||
|
||||
desc.HostTopo = hostTopo
|
||||
log.Infof("host topo %s", jsonutils.Marshal(hostTopo))
|
||||
|
||||
sort.Sort(desc.HostTopo)
|
||||
desc.EnableCpuNumaAllocate = true
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReservedResource struct {
|
||||
CPUCount int64 `json:"cpu_count"`
|
||||
MemorySize int64 `json:"memory_size"`
|
||||
@@ -343,6 +700,36 @@ func (h *HostDesc) GetFreeMemSize(useRsvd bool) int64 {
|
||||
return reservedResourceAddCal(h.FreeMemSize, h.GuestReservedMemSizeFree(), useRsvd) - int64(h.GetPendingUsage().Memory)
|
||||
}
|
||||
|
||||
func (h *HostDesc) GetFreeCpuNuma() scheduler.SortedFreeNumaCpuMam {
|
||||
if !h.EnableCpuNumaAllocate {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make(scheduler.SortedFreeNumaCpuMam, 0)
|
||||
cpuPin := h.GetPendingUsage().CpuPin
|
||||
numaPin := h.GetPendingUsage().NumaMemPin
|
||||
for i := range h.HostTopo.Nodes {
|
||||
nodeFree := new(scheduler.SFreeNumaCpuMem)
|
||||
nodeFree.NodeId = h.HostTopo.Nodes[i].NodeId
|
||||
nodeFree.CpuCount = h.HostTopo.Nodes[i].CpuCount
|
||||
nodeFree.MemSize = h.HostTopo.Nodes[i].NumaHugeFreeMemSizeKB * 1024
|
||||
nodeFree.EnableNumaAllocate = h.HostTopo.NumaEnabled
|
||||
nodeFree.FreeCpuCount = h.HostTopo.Nodes[i].CpuCount*int(h.CPUCmtbound) - h.HostTopo.Nodes[i].VcpuCount
|
||||
for cpuId, pending := range cpuPin {
|
||||
if h.HostTopo.Nodes[i].LogicalProcessors.Contains(cpuId) {
|
||||
nodeFree.FreeCpuCount -= pending
|
||||
}
|
||||
}
|
||||
|
||||
if memSize, ok := numaPin[h.HostTopo.Nodes[i].NodeId]; ok {
|
||||
nodeFree.MemSize -= memSize
|
||||
}
|
||||
res = append(res, nodeFree)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return res
|
||||
}
|
||||
|
||||
func (h *HostDesc) GuestReservedMemSizeFree() int64 {
|
||||
return h.GuestReservedResource.MemorySize - h.GuestReservedResourceUsed.MemorySize
|
||||
}
|
||||
@@ -379,6 +766,20 @@ func (h *HostDesc) IndexKey() string {
|
||||
return h.Id
|
||||
}
|
||||
|
||||
func (h *HostDesc) AllocCpuNumaPin(vcpuCount, memSizeKB int) []scheduler.SCpuNumaPin {
|
||||
if !h.EnableCpuNumaAllocate {
|
||||
return nil
|
||||
}
|
||||
return h.HostTopo.AllocCpuNumaNodes(vcpuCount, memSizeKB)
|
||||
}
|
||||
|
||||
func (h *HostDesc) AllocCpuNumaPinWithNodeCount(vcpuCount, memSizeKB, nodeCount int) []scheduler.SCpuNumaPin {
|
||||
if !h.EnableCpuNumaAllocate {
|
||||
return nil
|
||||
}
|
||||
return h.HostTopo.AllocCpuNumaNodesWithNodeCount(vcpuCount, memSizeKB, nodeCount)
|
||||
}
|
||||
|
||||
type WaitGroupWrapper struct {
|
||||
gosync.WaitGroup
|
||||
}
|
||||
@@ -694,13 +1095,13 @@ func (b *HostBuilder) InitFuncs() []InitFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// build host desc
|
||||
func (b *HostBuilder) BuildOne(host *computemodels.SHost, getter *networkGetter, baseDesc *BaseHostDesc) (interface{}, error) {
|
||||
desc := &HostDesc{
|
||||
BaseHostDesc: baseDesc,
|
||||
}
|
||||
|
||||
desc.Metadata = make(map[string]string)
|
||||
|
||||
desc.CPUCmtbound = host.GetCPUOvercommitBound()
|
||||
desc.MemCmtbound = host.GetMemoryOvercommitBound()
|
||||
|
||||
@@ -712,10 +1113,11 @@ func (b *HostBuilder) BuildOne(host *computemodels.SHost, getter *networkGetter,
|
||||
desc.GuestReservedResourceUsed = guestRsvdUsed
|
||||
|
||||
fillFuncs := []func(*HostDesc, *computemodels.SHost) error{
|
||||
b.fillGuestsResourceInfo,
|
||||
//b.fillResidentGroups,
|
||||
b.fillMetadata,
|
||||
b.fillCPUIOLoads,
|
||||
b.fillGuestsCpuNumaPin,
|
||||
b.fillGuestsResourceInfo,
|
||||
}
|
||||
|
||||
for _, f := range fillFuncs {
|
||||
@@ -728,13 +1130,52 @@ func (b *HostBuilder) BuildOne(host *computemodels.SHost, getter *networkGetter,
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
func _in(s string, ss []string) bool {
|
||||
for _, str := range ss {
|
||||
if s == str {
|
||||
return true
|
||||
func (b *HostBuilder) fillGuestsCpuNumaPin(desc *HostDesc, host *computemodels.SHost) error {
|
||||
if !host.EnableNumaAllocate {
|
||||
return nil
|
||||
}
|
||||
|
||||
topoObj, err := host.SysInfo.Get("topology")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get topology from host sys_info")
|
||||
}
|
||||
hostTopo := new(hostapi.HostTopology)
|
||||
if err := topoObj.Unmarshal(hostTopo); err != nil {
|
||||
return errors.Wrap(err, "Unmarshal host topology struct")
|
||||
}
|
||||
var reservedCpus *cpuset.CPUSet
|
||||
reservedCpusStr := host.GetMetadata(context.Background(), computeapi.HOSTMETA_RESERVED_CPUS_INFO, nil)
|
||||
if reservedCpusStr != "" {
|
||||
reservedCpusJson, err := jsonutils.ParseString(reservedCpusStr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parse reserved cpus info failed")
|
||||
}
|
||||
reservedCpusInfo := computeapi.HostReserveCpusInput{}
|
||||
err = reservedCpusJson.Unmarshal(&reservedCpusInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unmarshal host reserved cpus info failed")
|
||||
}
|
||||
reservedCpuset, err := cpuset.Parse(reservedCpusInfo.Cpus)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cpuset parse reserved cpus")
|
||||
}
|
||||
reservedCpus = &reservedCpuset
|
||||
}
|
||||
|
||||
nodeHugepages := make([]hostapi.HostNodeHugepageNr, 0)
|
||||
if host.SysInfo.Contains("node_hugepages") {
|
||||
err = host.SysInfo.Unmarshal(&nodeHugepages, "node_hugepages")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unmarshal node hugepages")
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
hugepageSizeKb, err := host.SysInfo.Int("hugepage_size_kb")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unmarshal hugepage size kb")
|
||||
}
|
||||
|
||||
return b.buildHostTopo(desc, reservedCpus, int(hugepageSizeKb), nodeHugepages, hostTopo)
|
||||
}
|
||||
|
||||
func (b *HostBuilder) fillGuestsResourceInfo(desc *HostDesc, host *computemodels.SHost) error {
|
||||
@@ -752,6 +1193,7 @@ func (b *HostBuilder) fillGuestsResourceInfo(desc *HostDesc, host *computemodels
|
||||
creatingMemSize int64
|
||||
creatingCPUCount int64
|
||||
creatingGuestCount int64
|
||||
guestsCpuNumaPin = make([]scheduler.SCpuNumaPin, 0)
|
||||
)
|
||||
guestsOnHost, ok := b.hostGuests[host.Id]
|
||||
if !ok {
|
||||
@@ -775,6 +1217,13 @@ func (b *HostBuilder) fillGuestsResourceInfo(desc *HostDesc, host *computemodels
|
||||
runningCount++
|
||||
memSize += int64(guest.VmemSize)
|
||||
cpuCount += int64(guest.VcpuCount)
|
||||
if guest.CpuNumaPin != nil {
|
||||
cpuNumaPin := make([]scheduler.SCpuNumaPin, 0)
|
||||
if err := guest.CpuNumaPin.Unmarshal(&cpuNumaPin); err != nil {
|
||||
return errors.Wrap(err, "unmarshal cpu numa pin")
|
||||
}
|
||||
guestsCpuNumaPin = append(guestsCpuNumaPin, cpuNumaPin...)
|
||||
}
|
||||
} else if IsGuestCreating(guest) {
|
||||
creatingGuestCount++
|
||||
creatingMemSize += int64(guest.VmemSize)
|
||||
@@ -796,6 +1245,11 @@ func (b *HostBuilder) fillGuestsResourceInfo(desc *HostDesc, host *computemodels
|
||||
//}
|
||||
//}
|
||||
}
|
||||
|
||||
if len(guestsCpuNumaPin) > 0 {
|
||||
desc.HostTopo.LoadCpuNumaPin(guestsCpuNumaPin)
|
||||
}
|
||||
|
||||
desc.GuestCount = guestCount
|
||||
desc.CreatingGuestCount = creatingGuestCount
|
||||
desc.RunningGuestCount = runningCount
|
||||
|
||||
@@ -147,6 +147,7 @@ func (g *GenericScheduler) Schedule(ctx context.Context, unit *Unit, candidates
|
||||
var selectedCandidates []*SelectedCandidate
|
||||
if len(filteredCandidates) > 0 {
|
||||
trace.Step("Prioritizing")
|
||||
// prioritizing candidates
|
||||
// load all priorities and calculate the candidate's score
|
||||
priorityList, err := PrioritizeCandidates(unit, filteredCandidates, g.priorities)
|
||||
if err != nil {
|
||||
@@ -154,7 +155,7 @@ func (g *GenericScheduler) Schedule(ctx context.Context, unit *Unit, candidates
|
||||
}
|
||||
|
||||
trace.Step("Selecting hosts")
|
||||
// select target candate hosts
|
||||
// select target candidate hosts
|
||||
selectedCandidates, err = SelectHosts(unit, priorityList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -603,6 +604,7 @@ func PrioritizeCandidates(
|
||||
results[i] = make(HostPriorityList, len(candidates))
|
||||
}
|
||||
|
||||
// map reduce take priorities
|
||||
processCandidate := func(index int) {
|
||||
var err error
|
||||
candidate := candidates[index]
|
||||
|
||||
@@ -77,13 +77,25 @@ func (its SchedResultItems) Less(i, j int) bool {
|
||||
|
||||
func (item *SchedResultItem) ToCandidateResource(storageUsed *StorageUsed) *schedapi.CandidateResource {
|
||||
return &schedapi.CandidateResource{
|
||||
HostId: item.ID,
|
||||
Name: item.Name,
|
||||
Disks: item.getDisks(storageUsed),
|
||||
Nets: item.Nets,
|
||||
HostId: item.ID,
|
||||
CpuNumaPin: item.selectCpuNumaPin(),
|
||||
Name: item.Name,
|
||||
Disks: item.getDisks(storageUsed),
|
||||
Nets: item.Nets,
|
||||
}
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) selectCpuNumaPin() []schedapi.SCpuNumaPin {
|
||||
// if !item.Candidater.Getter().Host().EnableNumaAllocate {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
if item.SchedData.LiveMigrate && len(item.SchedData.CpuNumaPin) > 0 {
|
||||
return item.Candidater.AllocCpuNumaPinWithNodeCount(item.SchedData.Ncpu, item.SchedData.Memory, len(item.SchedData.CpuNumaPin))
|
||||
}
|
||||
return item.Candidater.AllocCpuNumaPin(item.SchedData.Ncpu, item.SchedData.Memory*1024)
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) getDisks(used *StorageUsed) []*schedapi.CandidateDisk {
|
||||
inputs := item.SchedData.Disks
|
||||
ret := make([]*schedapi.CandidateDisk, 0)
|
||||
|
||||
@@ -61,6 +61,7 @@ func transToSchedResult(result *SchedResultItemList, schedInfo *api.SchedInfo) *
|
||||
}
|
||||
}
|
||||
|
||||
// trans to region sched results
|
||||
func transToRegionSchedResult(result SchedResultItems, count int64, sid string) *schedapi.ScheduleOutput {
|
||||
apiResults := make([]*schedapi.CandidateResource, 0)
|
||||
succCount := 0
|
||||
|
||||
@@ -97,6 +97,8 @@ type CandidatePropertyGetter interface {
|
||||
RunningMemorySize() int64
|
||||
TotalMemorySize(useRsvd bool) int64
|
||||
FreeMemorySize(useRsvd bool) int64
|
||||
GetFreeCpuNuma() []*schedapi.SFreeNumaCpuMem
|
||||
NumaAllocateEnabled() bool
|
||||
|
||||
StorageInfo() []*baremetal.BaremetalStorage
|
||||
GetFreeStorageSizeOfType(storageType string, mediumType string, useRsvd bool, reqMaxSize int64) (int64, int64, error)
|
||||
@@ -140,6 +142,8 @@ type Candidater interface {
|
||||
GetSchedDesc() *jsonutils.JSONDict
|
||||
GetGuestCount() int64
|
||||
GetResourceType() string
|
||||
AllocCpuNumaPin(vcpuCount, memSizeKB int) []schedapi.SCpuNumaPin
|
||||
AllocCpuNumaPinWithNodeCount(vcpuCount, memSizeKB, nodeCount int) []schedapi.SCpuNumaPin
|
||||
}
|
||||
|
||||
// HostPriority represents the priority of scheduling to particular host, higher priority is better.
|
||||
|
||||
@@ -84,6 +84,7 @@ func (te *TaskExecutor) Execute(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// do execute schedule()
|
||||
func (te *TaskExecutor) execute(ctx context.Context) (*core.ScheduleResult, error) {
|
||||
scheduler := te.scheduler
|
||||
genericScheduler, err := core.NewGenericScheduler(scheduler.(core.Scheduler))
|
||||
@@ -99,6 +100,7 @@ func (te *TaskExecutor) execute(ctx context.Context) (*core.ScheduleResult, erro
|
||||
|
||||
te.unit = scheduler.Unit()
|
||||
schedInfo := te.unit.SchedInfo
|
||||
// generate result helper
|
||||
helper := GenerateResultHelper(schedInfo)
|
||||
result, err := genericScheduler.Schedule(ctx, te.unit, candidates, helper)
|
||||
if err != nil {
|
||||
@@ -108,6 +110,8 @@ func (te *TaskExecutor) execute(ctx context.Context) (*core.ScheduleResult, erro
|
||||
return result, nil
|
||||
}
|
||||
driver := te.unit.GetHypervisorDriver()
|
||||
|
||||
// set sched pending usage
|
||||
if err := setSchedPendingUsage(driver, schedInfo, result.Result); err != nil {
|
||||
return nil, errors.Wrap(err, "setSchedPendingUsage")
|
||||
}
|
||||
|
||||
@@ -50,14 +50,14 @@ func (m *SHostPendingUsageManager) Keyword() string {
|
||||
return "pending_usage_manager"
|
||||
}
|
||||
|
||||
func (m *SHostPendingUsageManager) newSessionUsage(req *api.SchedInfo, hostId string) *SessionPendingUsage {
|
||||
func (m *SHostPendingUsageManager) newSessionUsage(req *api.SchedInfo, hostId string, candidate *schedapi.CandidateResource) *SessionPendingUsage {
|
||||
su := NewSessionUsage(req.SessionId, hostId)
|
||||
su.Usage = NewPendingUsageBySchedInfo(hostId, req)
|
||||
su.Usage = NewPendingUsageBySchedInfo(hostId, req, candidate)
|
||||
return su
|
||||
}
|
||||
|
||||
func (m *SHostPendingUsageManager) newPendingUsage(hostId string) *SPendingUsage {
|
||||
return NewPendingUsageBySchedInfo(hostId, nil)
|
||||
return NewPendingUsageBySchedInfo(hostId, nil, nil)
|
||||
}
|
||||
|
||||
func (m *SHostPendingUsageManager) GetPendingUsage(hostId string) (*SPendingUsage, error) {
|
||||
@@ -81,7 +81,7 @@ func (m *SHostPendingUsageManager) AddPendingUsage(req *api.SchedInfo, candidate
|
||||
|
||||
sessionUsage, _ := m.GetSessionUsage(req.SessionId, hostId)
|
||||
if sessionUsage == nil {
|
||||
sessionUsage = m.newSessionUsage(req, hostId)
|
||||
sessionUsage = m.newSessionUsage(req, hostId, candidate)
|
||||
sessionUsage.StartTimer()
|
||||
}
|
||||
m.addSessionUsage(candidate.HostId, sessionUsage)
|
||||
@@ -100,6 +100,7 @@ func (m *SHostPendingUsageManager) addSessionUsage(hostId string, usage *Session
|
||||
if pendingUsage == nil {
|
||||
pendingUsage = m.newPendingUsage(hostId)
|
||||
}
|
||||
// add pending usage
|
||||
pendingUsage.Add(usage.Usage)
|
||||
usage.AddCount()
|
||||
m.store.SetSessionUsage(usage.SessionId, hostId, usage)
|
||||
@@ -190,7 +191,7 @@ func NewSessionUsage(sid, hostId string) *SessionPendingUsage {
|
||||
su := &SessionPendingUsage{
|
||||
HostId: hostId,
|
||||
SessionId: sid,
|
||||
Usage: NewPendingUsageBySchedInfo(hostId, nil),
|
||||
Usage: NewPendingUsageBySchedInfo(hostId, nil, nil),
|
||||
count: 0,
|
||||
countLock: new(sync.Mutex),
|
||||
cancelCh: make(chan string),
|
||||
@@ -292,7 +293,9 @@ func (u *SResourcePendingUsage) IsEmpty() bool {
|
||||
type SPendingUsage struct {
|
||||
HostId string
|
||||
Cpu int
|
||||
CpuPin map[int]int
|
||||
Memory int
|
||||
NumaMemPin map[int]int
|
||||
IsolatedDevice int
|
||||
DiskUsage *SResourcePendingUsage
|
||||
NetUsage *SResourcePendingUsage
|
||||
@@ -300,7 +303,7 @@ type SPendingUsage struct {
|
||||
InstanceGroupUsage map[string]*api.CandidateGroup
|
||||
}
|
||||
|
||||
func NewPendingUsageBySchedInfo(hostId string, req *api.SchedInfo) *SPendingUsage {
|
||||
func NewPendingUsageBySchedInfo(hostId string, req *api.SchedInfo, candidate *schedapi.CandidateResource) *SPendingUsage {
|
||||
u := &SPendingUsage{
|
||||
HostId: hostId,
|
||||
DiskUsage: NewResourcePendingUsage(nil),
|
||||
@@ -309,6 +312,8 @@ func NewPendingUsageBySchedInfo(hostId string, req *api.SchedInfo) *SPendingUsag
|
||||
|
||||
// group init
|
||||
u.InstanceGroupUsage = make(map[string]*api.CandidateGroup)
|
||||
u.CpuPin = make(map[int]int)
|
||||
u.NumaMemPin = make(map[int]int)
|
||||
|
||||
if req == nil {
|
||||
return u
|
||||
@@ -317,6 +322,24 @@ func NewPendingUsageBySchedInfo(hostId string, req *api.SchedInfo) *SPendingUsag
|
||||
u.Memory = req.Memory
|
||||
u.IsolatedDevice = len(req.IsolatedDevices)
|
||||
|
||||
if candidate != nil && len(candidate.CpuNumaPin) > 0 {
|
||||
for _, cpuNumaPin := range candidate.CpuNumaPin {
|
||||
if cpuNumaPin.MemSizeMB != nil {
|
||||
if v, ok := u.NumaMemPin[cpuNumaPin.NodeId]; ok {
|
||||
u.NumaMemPin[cpuNumaPin.NodeId] = v + *cpuNumaPin.MemSizeMB
|
||||
}
|
||||
}
|
||||
|
||||
for i := range cpuNumaPin.CpuPin {
|
||||
if v, ok := u.CpuPin[cpuNumaPin.CpuPin[i]]; ok {
|
||||
u.CpuPin[cpuNumaPin.CpuPin[i]] = v + 1
|
||||
} else {
|
||||
u.CpuPin[cpuNumaPin.CpuPin[i]] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, disk := range req.Disks {
|
||||
backend := disk.Backend
|
||||
size := disk.SizeMb
|
||||
@@ -361,7 +384,22 @@ func (self *SPendingUsage) ToMap() map[string]interface{} {
|
||||
|
||||
func (self *SPendingUsage) Add(sUsage *SPendingUsage) {
|
||||
self.Cpu = self.Cpu + sUsage.Cpu
|
||||
for k, v1 := range sUsage.CpuPin {
|
||||
if v2, ok := self.CpuPin[k]; ok {
|
||||
self.CpuPin[k] = v1 + v2
|
||||
} else {
|
||||
self.CpuPin[k] = v1
|
||||
}
|
||||
}
|
||||
|
||||
self.Memory = self.Memory + sUsage.Memory
|
||||
for k, v1 := range sUsage.NumaMemPin {
|
||||
if v2, ok := self.NumaMemPin[k]; ok {
|
||||
self.NumaMemPin[k] = v1 + v2
|
||||
} else {
|
||||
self.NumaMemPin[k] = v1
|
||||
}
|
||||
}
|
||||
self.IsolatedDevice = self.IsolatedDevice + sUsage.IsolatedDevice
|
||||
self.DiskUsage.Add(sUsage.DiskUsage)
|
||||
self.NetUsage.Add(sUsage.NetUsage)
|
||||
@@ -376,7 +414,19 @@ func (self *SPendingUsage) Add(sUsage *SPendingUsage) {
|
||||
|
||||
func (self *SPendingUsage) Sub(sUsage *SPendingUsage) {
|
||||
self.Cpu = quotas.NonNegative(self.Cpu - sUsage.Cpu)
|
||||
for k, v1 := range sUsage.CpuPin {
|
||||
if v2, ok := self.CpuPin[k]; ok {
|
||||
self.CpuPin[k] = quotas.NonNegative(v2 - v1)
|
||||
}
|
||||
}
|
||||
|
||||
self.Memory = quotas.NonNegative(self.Memory - sUsage.Memory)
|
||||
for k, v1 := range sUsage.NumaMemPin {
|
||||
if v2, ok := self.NumaMemPin[k]; ok {
|
||||
self.NumaMemPin[k] = quotas.NonNegative(v2 - v1)
|
||||
}
|
||||
}
|
||||
|
||||
self.IsolatedDevice = quotas.NonNegative(self.IsolatedDevice - sUsage.IsolatedDevice)
|
||||
self.DiskUsage.Sub(sUsage.DiskUsage)
|
||||
self.NetUsage.Sub(sUsage.NetUsage)
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
|
||||
jsonutils "yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
types "yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
baremetal "yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
models "yunion.io/x/onecloud/pkg/compute/models"
|
||||
@@ -150,6 +151,30 @@ func (mr *MockCandidatePropertyGetterMockRecorder) FreeMemorySize(arg0 interface
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FreeMemorySize", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).FreeMemorySize), arg0)
|
||||
}
|
||||
|
||||
func (m *MockCandidatePropertyGetter) NumaAllocateEnabled() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NumaAllocateEnabled")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) NumaAllocateEnabled() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NumaAllocateEnabled", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).NumaAllocateEnabled))
|
||||
}
|
||||
|
||||
func (m *MockCandidatePropertyGetter) GetFreeCpuNuma() []*scheduler.SFreeNumaCpuMem {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFreeCpuNuma")
|
||||
ret0, _ := ret[0].([]*scheduler.SFreeNumaCpuMem)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetFreeCpuNuma() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFreeCpuNuma", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetFreeCpuNuma))
|
||||
}
|
||||
|
||||
// GetFreeGroupCount mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetFreeGroupCount(arg0 string) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -863,6 +888,30 @@ func (mr *MockCandidaterMockRecorder) IndexKey() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IndexKey", reflect.TypeOf((*MockCandidater)(nil).IndexKey))
|
||||
}
|
||||
|
||||
func (m *MockCandidater) AllocCpuNumaPin(arg0, arg1 int) []scheduler.SCpuNumaPin {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AllocCpuNumaPin", arg0, arg1)
|
||||
ret0, _ := ret[0].([]scheduler.SCpuNumaPin)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *MockCandidaterMockRecorder) AllocCpuNumaPin(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocCpuNumaPin", reflect.TypeOf((*MockCandidater)(nil).AllocCpuNumaPin), arg0, arg1)
|
||||
}
|
||||
|
||||
func (m *MockCandidater) AllocCpuNumaPinWithNodeCount(arg0, arg1, arg2 int) []scheduler.SCpuNumaPin {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AllocCpuNumaPinWithNodeCount", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]scheduler.SCpuNumaPin)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *MockCandidaterMockRecorder) AllocCpuNumaPinWithNodeCount(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocCpuNumaPinWithNodeCount", reflect.TypeOf((*MockCandidater)(nil).AllocCpuNumaPinWithNodeCount), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Type mocks base method
|
||||
func (m *MockCandidater) Type() int {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -83,6 +83,7 @@ func buildCandidate(ctrl *gomock.Controller, param sGetterParams) *mock.MockCand
|
||||
cn.EXPECT().Getter().AnyTimes().Return(getter)
|
||||
cn.EXPECT().IndexKey().AnyTimes().Return(getter.Id())
|
||||
cn.EXPECT().GetResourceType().AnyTimes().Return(getter.ResourceType())
|
||||
cn.EXPECT().AllocCpuNumaPin(gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
|
||||
return cn
|
||||
}
|
||||
|
||||
@@ -171,6 +172,7 @@ func buildGetter(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandida
|
||||
cg.EXPECT().FreeCPUCount(gomock.Any()).AnyTimes().Return(param.FreeCPUCount)
|
||||
cg.EXPECT().TotalMemorySize(gomock.Any()).AnyTimes().Return(param.TotalMemorySize)
|
||||
cg.EXPECT().FreeMemorySize(gomock.Any()).AnyTimes().Return(param.FreeMemorySize)
|
||||
cg.EXPECT().GetFreeCpuNuma().AnyTimes().Return(nil)
|
||||
cg.EXPECT().GetFreeStorageSizeOfType(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(param.FreeStorageSizeAnyType, int64(0), nil)
|
||||
if param.QuotaKeys != nil {
|
||||
cg.EXPECT().GetQuotaKeys(gomock.Any()).AnyTimes().Return(param.QuotaKeys)
|
||||
|
||||
Reference in New Issue
Block a user