using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using XenAPI; namespace XenAdmin.Controls { public partial class CPUTopologyComboBox : LongStringComboBox { public CPUTopologyComboBox() { DropDownStyle = ComboBoxStyle.DropDownList; Sorted = false; } public long CoresPerSocket { get; private set; } private long origNoOfVCPUs; private long origCoresPerSocket; private long maxNoOfCoresPerSocket; /// /// Populate the combo box options, based on maxVCPUs. /// /// Current value VCPUs_at_startup /// Current value of VCPUs_max /// Current value of platform:cores-per-socket /// Number of cores per socket on the underlying server public void Populate(long noOfVCPUs, long maxVCPUs, long coresPerSocket, long maxCoresPerSocket) { origNoOfVCPUs = noOfVCPUs; origCoresPerSocket = CoresPerSocket = coresPerSocket; maxNoOfCoresPerSocket = maxCoresPerSocket; Update(maxVCPUs); } /// /// Repopulate the combobox options, based on number of vCPUs and update the selected item /// /// public void Update(long noOfVCPUs) { BeginUpdate(); try { Items.Clear(); // Build the list of topologies, based on number of vCPUs var topologies = GetTopologies(noOfVCPUs, maxNoOfCoresPerSocket); Items.AddRange(topologies.ToArray()); // if the original value is not in the list (because is invalid) and the noOfVCPU hasn't changed, // then add it to the combo box as an invalid configuration if (origNoOfVCPUs == noOfVCPUs && !topologies.Any(topologyTuple => topologyTuple.Cores == origCoresPerSocket)) { Items.Add(new TopologyTuple(origCoresPerSocket)); } // try to re-select the current value foreach (var item in Items) { if (item as TopologyTuple != null && (item as TopologyTuple ).Cores.Equals(CoresPerSocket)) { SelectedItem = item; break; } } } finally { if (SelectedIndex < 0 && Items.Count > 0) // if nothing selected, select first item SelectedIndex = 0; EndUpdate(); } } /// /// Build the list of topologies, based on number of vCPUs. /// This list will contain only valid values, i.e. cores per socket is a factor of number of vCPUs /// and does not exceed the number of cores per socket on the underlying server. /// /// Number of vCPUs /// Maximum number of cores per socket /// A list of topologies private static List GetTopologies(long noOfVCPUs, long maxNoOfCoresPerSocket) { var result = new List(); var maxCoresPerSocket = maxNoOfCoresPerSocket > 0 ? Math.Min(noOfVCPUs, maxNoOfCoresPerSocket) : noOfVCPUs; for (var cores = 1; cores <= maxCoresPerSocket; cores++) { if (noOfVCPUs % cores == 0 && noOfVCPUs / cores <= VM.MAX_SOCKETS) result.Add(new TopologyTuple(noOfVCPUs / cores, cores)); } return result; } public bool IsValidVCPU(long noOfVCPUs) { return GetTopologies(noOfVCPUs, maxNoOfCoresPerSocket).Count != 0; } protected override void OnSelectedIndexChanged(EventArgs e) { var selectedTopology = SelectedItem as TopologyTuple; if (selectedTopology != null) CoresPerSocket = selectedTopology.Cores; base.OnSelectedIndexChanged(e); } } public class TopologyTuple { public readonly long Sockets; public readonly long Cores; /// /// Constructor used for valid configurations /// /// /// public TopologyTuple(long sockets, long cores) { this.Sockets = sockets; this.Cores = cores; } /// /// Constructor used for invalid cores per socket value /// /// public TopologyTuple(long cores) { this.Sockets = 0; this.Cores = cores; } public override string ToString() { return VM.GetTopology(Sockets, Cores); } } }