def create_lwkcpu_spec(self, ratio): lwkcpuspec = 'lwkcpus=' self.lwkcpus = CpuSet(0) self.utilcpus = CpuSet(0) self.n_cpus = self.topology.allcpus.countCpus() assert (self.n_cpus > 0), "Invalid topology" if ratio >= 1: lwkcpuspec += '0.{}'.format(self.topology.allcpus.toList()) return lwkcpuspec elif ratio <= 0: return lwkcpuspec self.n_lwkcpus = int(ratio * self.n_cpus) self.n_linuxcpus = self.n_cpus - self.n_lwkcpus lwkcpus_per_sc_cpu = math.ceil(self.n_lwkcpus / self.n_linuxcpus) assert (self.n_lwkcpus > 0), 'Invalid no. of LWKCPUs' assert (self.n_linuxcpus > 0), 'Invalid no. of Linux CPUs' assert (lwkcpus_per_sc_cpu > 0), 'Invalid no. of LWKCPUs per utility CPU' logging.debug('Total CPUs : {}'.format(self.n_cpus)) logging.debug('Total LWK CPUs : {}'.format(self.n_lwkcpus)) logging.debug('Total Linux CPUs: {}'.format(self.n_linuxcpus)) logging.debug( 'LWK CPUs per utility CPU: {}'.format(lwkcpus_per_sc_cpu)) sc = 0 lwkcpus_count = 0 mask = CpuSet(0) for i in range(self.n_linuxcpus, self.n_cpus): if lwkcpus_count >= lwkcpus_per_sc_cpu: if lwkcpuspec != 'lwkcpus=': lwkcpuspec += ':' lwkcpuspec += '{}.{}'.format(sc, mask.toList()) self.lwkcpus += mask self.utilcpus += self.topology.allcpus.nthCpu(sc + 1) sc += 1 mask = CpuSet(0) lwkcpus_count = 0 mask += self.topology.allcpus.nthCpu(i + 1) lwkcpus_count += 1 if lwkcpus_count != 0: if lwkcpuspec != 'lwkcpus=': lwkcpuspec += ':' lwkcpuspec += '{}.{}'.format(sc, mask.toList()) self.lwkcpus += mask self.utilcpus += self.topology.allcpus.nthCpu(sc + 1) return lwkcpuspec
def create_lwkcpu_spec(self, ratio, noutility_cpus=False): KEY_FMT = 'ratio_{}_noutility_cpus_{}' def clearFirstNCores(cs, N): cpumask = CpuSet(0) for i in range(N): cpumask += cs.selectNthBy(i + 1, self.topology.cores) return cs - cpumask def clearLastNCores(cs, N): cpumask = CpuSet(0) nthCore = cs.countBy(self.topology.cores) for i in range(N): cpumask += cs.selectNthBy(nthCore, self.topology.cores) nthCore -= 1 return cs - cpumask def update_cache_lwkcpuspec(ratio, noutility_cpus, value): key = KEY_FMT.format(ratio, noutility_cpus) self.cache[key] = value # Try to look up for a cached spec before computing from scratch key = KEY_FMT.format(ratio, noutility_cpus) if key in self.cache: return self.cache[key] # Manufacture one and store in the cache lwkcpuspec = 'lwkcpus=' utilcpus = CpuSet(0) lwkcpus = CpuSet(0) if ratio <= 0: return lwkcpuspec, utilcpus, lwkcpus if ratio > 1: ratio = 1 # Consider core 0 as Linux core irrespective of topology. core0_cpus = self.topology.nodes[0].selectNthBy(1, self.topology.cores) numa_nodes = len(self.topology.nodes) node_utilcpus = self.topology.nodes.copy() node_lwkcpus = self.topology.nodes.copy() node_lwkcpus[0] -= core0_cpus # Find base minimum utility CPUs for the given hardware. These are the # number of Linux CPUs left after balancing number of LWK CPUs across # NUMA nodes. We do not scale the number of utility CPUs with ratio. # Instead we scale only the number of LWK CPUs using the given ratio. lwkcorespn_max = min( *[node.countBy(self.topology.cores) for node in node_lwkcpus]) lwkcorespn = math.ceil(lwkcorespn_max * ratio) logging.debug('LWK cores per node: {} max x {} ratio = {}'.format( lwkcorespn_max, ratio, lwkcorespn)) # Create maps of Linux and LWK cpus for every node total_util_cpus = 0 for n in range(numa_nodes): node_utilcpus[n] = clearLastNCores(node_utilcpus[n], lwkcorespn_max) node_lwkcpus[n] -= node_utilcpus[n] if lwkcorespn_max != lwkcorespn: node_lwkcpus[n] = clearFirstNCores(node_lwkcpus[n], lwkcorespn_max - lwkcorespn) lwkcpus += node_lwkcpus[n] utilcpus += node_utilcpus[n] total_util_cpus += node_utilcpus[n].countCpus() logging.debug('Node[{}] Linux CPUs : {}'.format( n, node_utilcpus[n].toList())) logging.debug('Node[{}] LWK CPUs : {}'.format( n, node_lwkcpus[n].toList())) if noutility_cpus == True: if lwkcpuspec != 'lwkcpus=': lwkcpuspec += ':' lwkcpuspec += '{}'.format(node_lwkcpus[n].toList()) # If there are no utility cpus requested then we are done here if noutility_cpus == True: rval = (lwkcpuspec, CpuSet(0), lwkcpus) update_cache_lwkcpuspec(ratio, True, rval) return rval # Assign LWKCPUs to Utility CPU mapping utilitycpuspn = int(total_util_cpus / numa_nodes) assert (utilitycpuspn >= 1), 'Utility CPUs {} lesser than NUMA nodes {}'.format( total_util_cpus, numa_nodes) lwkcores_per_utilitycpu = int(lwkcorespn / utilitycpuspn) if lwkcores_per_utilitycpu < 1: lwkcores_per_utilitycpu = 1 # Compute LWKCPU specification for each node logging.debug('Utility cpus per node : {}'.format(utilitycpuspn)) logging.debug( 'LWK cores per utility cpus: {}'.format(lwkcores_per_utilitycpu)) for n in range(numa_nodes): for i in range(1, utilitycpuspn + 1): subgroup_cpumask = CpuSet(0) for j in range(lwkcores_per_utilitycpu): cpumask = node_lwkcpus[n].selectNthBy( 1, self.topology.cores) subgroup_cpumask += cpumask node_lwkcpus[n] -= cpumask # Add any remaining LWK CPUs due to the truncation # from integer division to the last subgroup if i == utilitycpuspn and node_lwkcpus[n].isEmpty() == False: subgroup_cpumask += node_lwkcpus[n] node_lwkcpus[n] -= node_lwkcpus[n] # Pick a target utility CPU # Try current node first utilcpumask = node_utilcpus[n].nthCpu(1) if utilcpumask.isEmpty() == False: node_utilcpus[n] -= utilcpumask else: # If there is no utility CPU on this node # then try to get one from other NUMA nodes for m in range(numa_nodes): utilcpumask = node_utilcpus[m].nthCpu(1) if utilcpumask.isEmpty() == False: node_utilcpus[m] -= utilcpumask break assert ( utilcpumask.isEmpty() == False ), 'Node[{}]: Ran out of utility cpus to assign'.format(n) assert ( utilcpumask.countCpus() == 1 ), 'Node[{}]: More than 1 utility cpus selected: {}'.format(n) if lwkcpuspec != 'lwkcpus=': lwkcpuspec += ':' node_lwkcpuspec = '{}.{}'.format(utilcpumask.toList(), subgroup_cpumask.toList()) lwkcpuspec += node_lwkcpuspec logging.debug('Node[{}] LWKCPU spec: {}'.format( n, node_lwkcpuspec)) assert ( node_lwkcpus[n].countCpus() == 0 ), 'Node[{}]: LWKCPUs {} are not assigned a utility CPU'.format( n, node_lwkcpus[n].toList()) logging.debug('LWKCPU spec: {}'.format(lwkcpuspec)) rval = (lwkcpuspec, utilcpus, lwkcpus) update_cache_lwkcpuspec(ratio, False, rval) return rval