Example #1
0
    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
Example #2
0
    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