def _get_possible_cpu_topologies(vcpus, maxtopology, allow_threads, specified_threads): """Get a list of possible topologies for a vCPU count :param vcpus: total number of CPUs for guest instance :param maxtopology: nova.objects.VirtCPUTopology for upper limits :param allow_threads: if the hypervisor supports CPU threads :param specified_threads: if there is a specific request for threads we should attempt to honour Given a total desired vCPU count and constraints on the maximum number of sockets, cores and threads, return a list of nova.objects.VirtCPUTopology instances that represent every possible topology that satisfies the constraints. exception.ImageVCPULimitsRangeImpossible is raised if it is impossible to achieve the total vcpu count given the maximum limits on sockets, cores & threads. :returns: list of nova.objects.VirtCPUTopology instances """ # Clamp limits to number of vcpus to prevent # iterating over insanely large list maxsockets = min(vcpus, maxtopology.sockets) maxcores = min(vcpus, maxtopology.cores) maxthreads = min(vcpus, maxtopology.threads) if not allow_threads: # NOTE (ndipanov): If we don't support threads - it doesn't matter that # they are specified by the NUMA logic. specified_threads = None maxthreads = 1 LOG.debug( "Build topologies for %(vcpus)d vcpu(s) " "%(maxsockets)d:%(maxcores)d:%(maxthreads)d", { "vcpus": vcpus, "maxsockets": maxsockets, "maxcores": maxcores, "maxthreads": maxthreads }) def _get_topology_for_vcpus(vcpus, sockets, cores, threads): if threads * cores * sockets == vcpus: return objects.VirtCPUTopology(sockets=sockets, cores=cores, threads=threads) # Figure out all possible topologies that match # the required vcpus count and satisfy the declared # limits. If the total vCPU count were very high # it might be more efficient to factorize the vcpu # count and then only iterate over its factors, but # that's overkill right now possible = [] for s in range(1, maxsockets + 1): for c in range(1, maxcores + 1): if specified_threads: o = _get_topology_for_vcpus(vcpus, s, c, specified_threads) if o is not None: possible.append(o) else: for t in range(1, maxthreads + 1): o = _get_topology_for_vcpus(vcpus, s, c, t) if o is not None: possible.append(o) # We want to # - Minimize threads (ie larger sockets * cores is best) # - Prefer sockets over cores possible = sorted(possible, reverse=True, key=lambda x: (x.sockets * x.cores, x.sockets, x.threads)) LOG.debug("Got %d possible topologies", len(possible)) if len(possible) == 0: raise exception.ImageVCPULimitsRangeImpossible(vcpus=vcpus, sockets=maxsockets, cores=maxcores, threads=maxthreads) return possible
def get_possible_topologies(vcpus, maxtopology, allow_threads): """Get a list of possible topologies for a vCPU count :param vcpus: total number of CPUs for guest instance :param maxtopology: VirtCPUTopology for upper limits :param allow_threads: if the hypervisor supports CPU threads Given a total desired vCPU count and constraints on the maximum number of sockets, cores and threads, return a list of VirtCPUTopology instances that represent every possible topology that satisfies the constraints. exception.ImageVCPULimitsRangeImpossible is raised if it is impossible to achieve the total vcpu count given the maximum limits on sockets, cores & threads. :returns: list of VirtCPUTopology instances """ # Clamp limits to number of vcpus to prevent # iterating over insanely large list maxsockets = min(vcpus, maxtopology.sockets) maxcores = min(vcpus, maxtopology.cores) maxthreads = min(vcpus, maxtopology.threads) if not allow_threads: maxthreads = 1 LOG.debug( "Build topologies for %(vcpus)d vcpu(s) " "%(maxsockets)d:%(maxcores)d:%(maxthreads)d", { "vcpus": vcpus, "maxsockets": maxsockets, "maxcores": maxcores, "maxthreads": maxthreads }) # Figure out all possible topologies that match # the required vcpus count and satisfy the declared # limits. If the total vCPU count were very high # it might be more efficient to factorize the vcpu # count and then only iterate over its factors, but # that's overkill right now possible = [] for s in range(1, maxsockets + 1): for c in range(1, maxcores + 1): for t in range(1, maxthreads + 1): if t * c * s == vcpus: possible.append(VirtCPUTopology(s, c, t)) # We want to # - Minimize threads (ie larger sockets * cores is best) # - Prefer sockets over cores possible = sorted(possible, reverse=True, key=lambda x: (x.sockets * x.cores, x.sockets, x.threads)) LOG.debug("Got %d possible topologies", len(possible)) if len(possible) == 0: raise exception.ImageVCPULimitsRangeImpossible(vcpus=vcpus, sockets=maxsockets, cores=maxcores, threads=maxthreads) return possible