9ec7cf4447
Change spec and scripts to only use python3 explicitly Verification: 1. Regard as the README,in development docker environment, run ./patch-engtools.sh, it will generate the ENGTOOLS-20.01.patch if we scp the patch to controller, we could sw-patch upload and sw-apply it successfully. 2. The engtools-1.0-4.tis.noarch.rpm is not built into bootimage by default thus if we package it into bootimage when to verify it. 1). Run some bash script, such as ceph.sh, memstats.sh, netstats.sh and so on it will display the collect system resource information. 2). The service of collect-engtools.service could start and stop without problem 3). If we run the modified python which we have changed to python3. python3 buddyinfo.py it will deplay the resource information python3 live_stream.py the log of livestream.log will display collect information This package only be packaged into bootimage when we need it to collect system resource information. Change-Id: I9bd77e34650e200f0c65db966635a8ebcdc584aa Story: 2007106 Task: 39112 Depends-on: https://review.opendev.org/#/c/712218/ Depends-on: https://review.opendev.org/#/c/714072/ Signed-off-by: Long Li <lilong-neu@neusoft.com>
124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 textwidth=79 autoindent
|
|
|
|
"""
|
|
Python source code
|
|
Last modified: 15 Feb 2014 - 13:38
|
|
Last author: lmwangi at gmail com
|
|
Displays the available memory fragments
|
|
by querying /proc/buddyinfo
|
|
Example:
|
|
# python3 buddyinfo.py
|
|
"""
|
|
import optparse
|
|
import os
|
|
import re
|
|
from collections import defaultdict
|
|
import logging
|
|
|
|
|
|
class Logger:
|
|
def __init__(self, log_level):
|
|
self.log_level = log_level
|
|
|
|
def get_formatter(self):
|
|
return logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
|
|
def get_handler(self):
|
|
return logging.StreamHandler()
|
|
|
|
def get_logger(self):
|
|
"""Returns a Logger instance for the specified module_name"""
|
|
logger = logging.getLogger('main')
|
|
logger.setLevel(self.log_level)
|
|
log_handler = self.get_handler()
|
|
log_handler.setFormatter(self.get_formatter())
|
|
logger.addHandler(log_handler)
|
|
return logger
|
|
|
|
|
|
class BuddyInfo(object):
|
|
"""BuddyInfo DAO"""
|
|
def __init__(self, logger):
|
|
super(BuddyInfo, self).__init__()
|
|
self.log = logger
|
|
self.buddyinfo = self.load_buddyinfo()
|
|
|
|
def parse_line(self, line):
|
|
line = line.strip()
|
|
self.log.debug("Parsing line: %s" % line)
|
|
parsed_line = re.match("Node\s+(?P<numa_node>\d+).*zone\s+(?P<zone>\w+)\s+(?P<nr_free>.*)", line).groupdict()
|
|
self.log.debug("Parsed line: %s" % parsed_line)
|
|
return parsed_line
|
|
|
|
def read_buddyinfo(self):
|
|
buddyhash = defaultdict(list)
|
|
buddyinfo = open("/proc/buddyinfo").readlines()
|
|
for line in map(self.parse_line, buddyinfo):
|
|
numa_node = int(line["numa_node"])
|
|
zone = line["zone"]
|
|
free_fragments = [int(nr) for nr in line["nr_free"].split()]
|
|
max_order = len(free_fragments)
|
|
fragment_sizes = self.get_order_sizes(max_order)
|
|
usage_in_bytes = [block[0] * block[1] for block in zip(free_fragments, fragment_sizes)]
|
|
buddyhash[numa_node].append({
|
|
"zone": zone,
|
|
"nr_free": free_fragments,
|
|
"sz_fragment": fragment_sizes,
|
|
"usage": usage_in_bytes})
|
|
return buddyhash
|
|
|
|
def load_buddyinfo(self):
|
|
buddyhash = self.read_buddyinfo()
|
|
self.log.info(buddyhash)
|
|
return buddyhash
|
|
|
|
def page_size(self):
|
|
return os.sysconf("SC_PAGE_SIZE")
|
|
|
|
def get_order_sizes(self, max_order):
|
|
return [self.page_size() * 2**order for order in range(0, max_order)]
|
|
|
|
def __str__(self):
|
|
ret_string = ""
|
|
width = 20
|
|
for node in self.buddyinfo:
|
|
ret_string += "Node: %s\n" % node
|
|
for zoneinfo in self.buddyinfo.get(node):
|
|
ret_string += " Zone: %s\n" % zoneinfo.get("zone")
|
|
ret_string += " Free KiB in zone: %.2f\n" % (sum(zoneinfo.get("usage")) / (1024.0))
|
|
ret_string += '\t{0:{align}{width}} {1:{align}{width}} {2:{align}{width}}\n'.format(
|
|
"Fragment size", "Free fragments", "Total available KiB",
|
|
width=width,
|
|
align="<")
|
|
for idx in range(len(zoneinfo.get("sz_fragment"))):
|
|
ret_string += '\t{order:{align}{width}} {nr:{align}{width}} {usage:{align}{width}}\n'.format(
|
|
width=width,
|
|
align="<",
|
|
order=zoneinfo.get("sz_fragment")[idx],
|
|
nr=zoneinfo.get("nr_free")[idx],
|
|
usage=zoneinfo.get("usage")[idx] / 1024.0)
|
|
|
|
return ret_string
|
|
|
|
|
|
def main():
|
|
"""Main function. Called when this file is a shell script"""
|
|
usage = "usage: %prog [options]"
|
|
parser = optparse.OptionParser(usage)
|
|
parser.add_option("-s", "--size", dest="size", choices=["B", "K", "M"],
|
|
action="store", type="choice", help="Return results in bytes, kib, mib")
|
|
|
|
(options, args) = parser.parse_args()
|
|
logger = Logger(logging.DEBUG).get_logger()
|
|
logger.info("Starting....")
|
|
logger.info("Parsed options: %s" % options)
|
|
print(logger)
|
|
buddy = BuddyInfo(logger)
|
|
print(buddy)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|