Example #1
0
 def make_rows(self):
     repr_source = self.repr_source()
     for dev in self.options.devices:
         dev_node = self.numa.devices.get(dev)
         dev_color = ColorsNode.get(dev_node)
         _dev = wrap(dev, dev_color)
         yield [_dev] + self.colorize_stats(dev, repr_source)
Example #2
0
 def cpu_colorize(self, cpu):
     """
     :param cpu: cpu number (0)
     :return: highlighted by NUMA-node cpu number.
     """
     if not self.topology or not self.options.color:
         return cpu
     return wrap(cpu, cpu_color(cpu, topology=self.topology))
Example #3
0
 def dev_colorize(self):
     """
     :return: highlighted by NUMA-node name of the device
     """
     if not self.pci or not self.options.color:
         return self.options.dev
     color = COLORS_NODE.get(self.pci.devices.get(self.options.dev))
     return wrap(self.options.dev, color)
Example #4
0
 def make_rows(self):
     return [[
         wrap("CPU{0}".format(stat.cpu), cpu_color(stat.cpu, self.topology)),
         self.colorize_total(stat.total),
         self.colorize_dropped(stat.dropped),
         self.colorize_time_squeeze(stat.time_squeeze),
         self.colorize_cpu_collision(stat.cpu_collision),
         stat.received_rps
     ] for stat in self.repr_source()]
Example #5
0
 def make_rows(self):
     if not self.numa.devices:
         self.numa.devices = self.numa.node_dev_dict(self.options.devices, self.options.random)
     repr_source = self.repr_source()
     for dev in self.options.devices:
         dev_node = self.numa.devices.get(dev)
         dev_color = COLORS_NODE.get(dev_node)
         _dev = wrap(dev, dev_color)
         yield [_dev] + self.colorize_stats(dev, repr_source)
Example #6
0
 def __repr__(self):
     active_cpu_count = self.__active_cpu_count__(self.current)
     header = ["CPU", "NET_RX", "NET_TX"]
     net_rx = self.repr_source().get('NET_RX')[:active_cpu_count]
     net_tx = self.repr_source().get('NET_TX')[:active_cpu_count]
     rows = [[
         wrap("CPU{0}".format(n), cpu_color(n, self.numa)), v[0], v[1]
     ] for n, v in enumerate(zip(net_rx, net_tx))]
     table = make_table(header, ['l', 'r', 'r'], rows)
     return self.__repr_table__(table)
Example #7
0
 def make_rows(self):
     return [[
         wrap("CPU{0}".format(stat.cpu), cpu_color(stat.cpu, self.numa)),
         colorize(stat.total, self.total_warning, self.total_error),
         colorize(stat.dropped, self.dropped_warning, self.dropped_error),
         colorize(stat.time_squeeze, self.time_squeeze_warning,
                  self.time_squeeze_error),
         colorize(stat.cpu_collision, self.cpu_collision_warning,
                  self.cpu_collision_error), stat.received_rps
     ] for stat in self.repr_source()]
Example #8
0
 def __repr__(self):
     active_cpu_count = self.__active_cpu_count__(self.current)
     header = ['CPU', 'NET_RX', 'NET_TX']
     net_rx = self.repr_source().get('NET_RX')[:active_cpu_count]
     net_tx = self.repr_source().get('NET_TX')[:active_cpu_count]
     rows = [[
         wrap('CPU{0}'.format(n), cpu_color(n, self.topology)),
         self.colorize_net_rx(v[0]),
         self.colorize_net_tx(v[1])
     ] for n, v in enumerate(zip(net_rx, net_tx))]
     table = make_table(header, ['l', 'r', 'r'], rows)
     return self.__repr_table__(table)
Example #9
0
 def __repr_cpu_make_rows(self, irqtop, network_output, softirq_top,
                          softnet_stat_top):
     return [[
         wrap("CPU{0}".format(stat.cpu), cpu_color(stat.cpu,
                                                   self.topology)),
         irqtop.colorize_irq_per_cpu(irq),
         softirq_top.colorize_net_rx(net_rx),
         softirq_top.colorize_net_tx(net_tx),
         softnet_stat_top.colorize_total(stat.total),
         softnet_stat_top.colorize_dropped(stat.dropped),
         softnet_stat_top.colorize_time_squeeze(stat.time_squeeze),
         softnet_stat_top.colorize_cpu_collision(stat.cpu_collision),
         stat.received_rps
     ] for irq, net_rx, net_tx, stat in network_output]
Example #10
0
 def __repr_cpu_make_rows(self, irqtop, network_output, softirq_top, softnet_stat_top):
     rows = [
         [
             wrap("CPU{0}".format(stat.cpu), cpu_color(stat.cpu, self.numa)),
             colorize(irq, irqtop.irq_warning, irqtop.irq_error),
             colorize(softirq_rx, softirq_top.net_rx_warning, softirq_top.net_rx_error),
             colorize(softirq_tx, softirq_top.net_tx_warning, softirq_top.net_tx_error),
             colorize(stat.total, softnet_stat_top.total_warning, softnet_stat_top.total_error),
             colorize(stat.dropped, softnet_stat_top.dropped_warning, softnet_stat_top.dropped_error),
             colorize(stat.time_squeeze, softnet_stat_top.time_squeeze_warning, softnet_stat_top.time_squeeze_error),
             colorize(stat.cpu_collision, softnet_stat_top.cpu_collision_warning,
                      softnet_stat_top.cpu_collision_error),
             stat.received_rps
         ]
         for irq, softirq_rx, softirq_tx, stat in network_output
     ]
     return rows
Example #11
0
 def apply(self, decision):
     """
     '* 4' is in case of NIC has more queues than socket has CPUs
     :param decision: list of tuples(irq, queue_name, socket)
     """
     affinity = list(decision)
     cpus = [socket_cpu for irq, queue, socket_cpu in affinity]
     if len(set(cpus)) != len(cpus):
         warning = "WARNING: some CPUs process multiple queues, consider reduce queue count for this network device"
         if self.options.color:
             print_(wrap(warning, YELLOW))
         else:
             print_(warning)
     for irq, queue_name, socket_cpu in affinity:
         print_("  - {0}: irq {1} {2} -> {3}".format(
             self.dev_colorize(), irq, queue_name,
             self.cpu_colorize(socket_cpu)))
         if self.options.dry_run:
             continue
         filename = "/proc/irq/{0}/smp_affinity_list".format(irq)
         with open(filename, 'w') as irq_file:
             irq_file.write(str(socket_cpu))
Example #12
0
class BaseTop(object):
    """ Base class for all these top-like utils. """
    current = None
    previous = None
    diff = None
    header = wrap("Press CTRL-C to exit...\n", Fore.LIGHTBLACK_EX)
    options = None

    def __init__(self):
        """
        Base __init__() should only list common options that will be used in
        all specific top-like utils. All specific top-like utils should extend,
        but NOT OVERRIDE self.specific_options.
        """
        self.specific_options = [
            Option('-i',
                   '--interval',
                   default=1,
                   type=int,
                   help='Interval between screen renew in seconds.'),
            Option('-n',
                   '--iterations',
                   dest='iterations',
                   default=60,
                   type=int,
                   help="Count of screen's renews, -1 - infinite loop."),
            Option('--no-delta-mode',
                   action='store_false',
                   dest='delta_mode',
                   default=True,
                   help="Shows metrics' values instead of growth."),
            Option('--no-delta-small-hide',
                   action='store_false',
                   dest='delta_small_hide',
                   default=True,
                   help="Prevent lines with only small changes or without"
                   "changes at all from hiding."),
            Option('-l',
                   '--delta-small-hide-limit',
                   default=80,
                   type=int,
                   help='Hides lines with only changes less than this limit'),
            Option('--no-color',
                   dest='color',
                   default=True,
                   action='store_false',
                   help="Don't highlight NUMA nodes or sockets"),
            Option(
                '--spaces',
                default=False,
                action='store_true',
                help="Add spaces in numbers' representation, e.g. '1234567' "
                "will be '1 234 567'"),
            Option('--random',
                   default=False,
                   action='store_true',
                   help="Shows random diff data instead of real evaluation. "
                   "Helpful for testing on static files"),
            Option(
                '--no-clear',
                default=True,
                dest='clear',
                action='store_false',
                help=
                "Don't clear screen after each iteration. May be useful in scripts/logging to file."
            ),
        ]

    def parse_options(self, options=None):
        """ That should be explicitly called in __main__ part of any top-like utils """
        parser = OptionParser()
        for opt in self.specific_options:
            try:
                parser.add_option(opt)
            except OptionConflictError:
                pass
        self.options, _ = parser.parse_args()
        if options:
            for name, value in iteritems(options):
                setattr(self.options, name, value)
        if hasattr(self, 'post_optparse'):
            # pylint: disable=E1101
            self.post_optparse()

    def tick(self):
        """ Gathers new data + evaluate diff between current & previous data """
        self.previous = self.current
        self.current = self.parse()
        if all((self.previous, self.current)):
            self.eval()

    def list_diff(self, current, previous):
        """ It's strange that there is no [3,4,3] - [1,2,1] -> [2,2,2] in standard library """
        if self.options.random:
            return [randint(0, 10000) for _ in current]
        return [data - previous[n] for n, data in enumerate(current)]

    def run(self):
        """ Default main()-like function for specific top-like utils except meta-utils. """
        infinite = -1
        if self.options.iterations != infinite:
            self.options.iterations += 1
        try:
            while self.options.iterations > 0 or self.options.iterations == infinite:
                if self.options.iterations != infinite:
                    self.options.iterations -= 1
                sleep(self.options.interval)
                self.tick()
                if self.options.clear:
                    system('clear')
                if self.diff:
                    print_(self)
        except KeyboardInterrupt:
            print_()
            exit(0)

    def repr_source(self):
        return self.diff if self.options.delta_mode else self.current

    @staticmethod
    def int(item):
        return int(item) if item.isdigit() else item

    def spaces(self, number, sep=' '):
        """ 1234567 -> 1 234 567 """
        if not self.options.spaces:
            return number
        output = str()
        while number / 1000 > 0:
            output = str(number % 1000).zfill(3) + sep + output
            number /= 1000
        return (str(number % 1000) + sep + output).strip()

    def __repr_table__(self, table):
        if self.options.clear:
            return BaseTop.header + str(table)
        return str(table)

    def parse(self):
        """ Should read some file(s) into python structure (dict/list) """
        raise NotImplementedError

    def eval(self):
        """ Should evaluate self.diff using self.previous / self.current """
        raise NotImplementedError

    def __repr__(self):
        """ Should return string, representing self.diff """
        raise NotImplementedError
Example #13
0
class BaseTop(object):
    """ Base class for all these top-like utils. """
    current = None
    previous = None
    diff = None
    header = wrap('Press CTRL-C to exit...\n', GREY)
    options = None
    file_arg = None
    file_value = None

    @staticmethod
    def make_base_parser(parser=None):
        """ That should be explicitly called in __main__ part of any top-like utils """
        if not parser:
            parser = argparse.ArgumentParser()
        parser.add_argument('-i', '--interval', default=1, type=int,
                            help='Interval between screen renew in seconds.')
        parser.add_argument('-n', '--iterations', dest='iterations', default=60, type=int,
                            help='Count of screen\'s renews, -1 - infinite loop.')
        parser.add_argument('--no-delta-mode', action='store_false', dest='delta_mode',
                            default=True, help="Shows metrics' values instead of growth.")
        parser.add_argument('--no-delta-small-hide', action='store_false',
                            dest='delta_small_hide', default=True,
                            help='Prevent lines with only small changes or without'
                                 'changes at all from hiding.')
        parser.add_argument('-l', '--delta-small-hide-limit', default=80, type=int,
                            help='Hides lines with only changes less than this limit')
        parser.add_argument('--no-color', dest='color', default=True, action='store_false',
                            help="Don't highlight NUMA nodes or sockets")
        parser.add_argument('--spaces', default=False, action='store_true',
                            help="Add spaces in numbers' representation, e.g. '1234567' "
                                 "will be '1 234 567'")
        parser.add_argument('--random', default=False, action='store_true',
                            help='Shows random diff data instead of real evaluation. '
                                 'Helpful for testing on static files')
        parser.add_argument('--no-clear', default=True, dest='clear', action='store_false',
                            help="Don't clear screen after each iteration. "
                                 "May be useful in scripts/logging to file.")
        parser.add_argument('--lscpu-output', help='Specify file with lscpu -p output')
        return parser

    def make_parser(self, parser=None):
        if type(self) == BaseTop:
            raise TypeError('make_parser should not be called directly by BaseTop')
        if not parser:
            parser = BaseTop.make_base_parser()
        parser.add_argument(self.file_arg, default=self.file_value, help='Option for testing on MacOS purpose.')
        return parser

    def tick(self):
        """ Gathers new data + evaluate diff between current & previous data """
        self.previous = self.current
        self.current = self.parse()
        if all((self.previous, self.current)):
            self.eval()

    def list_diff(self, current, previous):
        """ It's strange that there is no [3,4,3] - [1,2,1] -> [2,2,2] in standard library """
        if self.options.random:
            return [randint(0, 10000) for _ in current]
        return [data - previous[n] for n, data in enumerate(current)]

    def run(self):
        """ Default main()-like function for specific top-like utils except meta-utils. """
        infinite = -1
        if self.options.iterations != infinite:
            self.options.iterations += 1
        try:
            while self.options.iterations > 0 or self.options.iterations == infinite:
                if self.options.iterations != infinite:
                    self.options.iterations -= 1
                sleep(self.options.interval)
                self.tick()
                if self.options.clear:
                    system('clear')
                if self.diff:
                    print_(self)
        except KeyboardInterrupt:
            print_()
            exit(0)

    def repr_source(self):
        return self.diff if self.options.delta_mode else self.current

    @staticmethod
    def int(item):
        return int(item) if item.isdigit() else item

    def spaces(self, number, sep=' '):
        """ 1234567 -> 1 234 567 """
        if not self.options.spaces:
            return number
        output = str()
        while number / 1000 > 0:
            output = str(number % 1000).zfill(3) + sep + output
            number /= 1000
        return (str(number % 1000) + sep + output).strip()

    def __repr_table__(self, table):
        if self.options.clear:
            return BaseTop.header + str(table)
        return str(table)

    @abstractmethod
    def parse(self):
        """ Should read some file(s) into python structure (dict/list) """

    @abstractmethod
    def eval(self):
        """ Should evaluate self.diff using self.previous / self.current """

    @abstractmethod
    def __repr__(self):
        """ Should return string, representing self.diff """

    def main(self):
        """ Default entry point for most of top-like utils """
        self.options = self.make_parser().parse_args()
        if hasattr(self, 'post_optparse'):
            self.post_optparse()
        self.run()