관리-도구
편집 파일: analyzers.py
# coding=utf-8 # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT import logging from lvestat import LVEStat from lvestats.core.plugin import LveStatsPlugin KB = 1024 FAULTS = ('cpu_fault', 'memphy_fault', 'mem_fault', 'io_fault', 'iops_fault', 'mep_fault', 'nproc_fault') LIMITS = ('lcpu', 'lmemphy', 'lmem', 'io', 'liops', 'lep', 'lnproc') STATS = ('cpu_usage', 'memphy', 'mem_usage', 'io_usage', 'iops', 'mep', 'nproc') LVEUSAGESLOTS = ('lve_version', 'time', 'has_changed_limits', 'has_changed_nproc') + STATS + LIMITS + FAULTS __author__ = 'iseletsk' log = logging.getLogger('LVEUsage') class LVEUsageAnalyzer(LveStatsPlugin): """ Calculates lve usage and updates it in lve_data, in field 'lve_usage' """ def set_config(self, config): self.config = config # pylint: disable=attribute-defined-outside-init def execute(self, lve_data): """ :param dict lve_data: """ # from /proc/lve new_stats = lve_data['stats'] old_stats = lve_data['old_stats'] del lve_data['old_stats'] old_now = lve_data.get('old_now', None) lve_data['old_now'] = self.now total_hz = lve_data['totalHz'] procs = lve_data['procs'] result = {} for _id, lve_stat in new_stats.items(): u = LVEUsage(lve_version=lve_data['LVE_VERSION']) lve_stat_old = old_stats.get(_id, None) u.calc(lve_stat_old, lve_stat, total_hz, self.now - old_now if old_now else None, procs) # LVES-210: clear all data if EP and NPROC == 0 and all other data not changed if _id == 0 \ or lve_stat.nproc > 0 \ or lve_stat.mep > 0 \ or (lve_stat_old is not None and u.is_lve_data_changed(lve_stat_old, lve_stat)): result[_id] = u lve_usages = lve_data.get('lve_usages', []) lve_usages.append(result) lve_data['lve_usages_5s'] = [result] lve_data['lve_active_ids'] = list(result.keys()) lve_data['lve_usages'] = lve_usages class LVEUsage(object): __slots__ = LVEUSAGESLOTS def __init__(self, lve_version): self.lve_version = lve_version self.time = None self.has_changed_limits = False self.has_changed_nproc = False # if LVE_VERSION >= 4 self.cpu_usage = 0 self.cpu_fault = 0 self.mep = 0 self.mem_fault = 0 self.mep_fault = 0 self.mem_usage = 0 self.lep = 0 self.lcpu = 0 self.lmem = 0 # if LVE_VERSION >=6 self.io = 0 self.io_usage = 0 self.io_fault = 0 self.lmemphy = 0 self.memphy = 0 self.memphy_fault = 0 self.lnproc = 0 self.nproc = 0 self.nproc_fault = 0 # if LVE_VERSION >= 8 self.liops = 0 self.iops = 0 self.iops_fault = 0 def init_limits_from_lvestat(self, lvestat: LVEStat, procs): """ Prepares LVEUsage obj taking limits from LVEStat """ self.lep = lvestat.lep self.lcpu = self.convert_lcpu_to_new_kernel_format(lvestat.cpu, self.lve_version, procs) # CMT-509: the incorrect LVE I/O units on CMT dashboard # Proc saves this value is in KBps, # but we should send it is in Bps, # because for an active user this value is sent in Bps self.io = lvestat.io * KB self.lmemphy = lvestat.lmemphy self.lnproc = lvestat.lnproc if self.lve_version >= 8: self.liops = lvestat.liops return self def __repr__(self): representation = '<' for k in (k for k in dir(self) if not k.startswith("_")): v = getattr(self, k) if isinstance(v, (str, int, float, bool, type(None))): representation += f'{k}:{v}, ' representation += '>' return representation def has_interesting_values(self): if any((self.cpu_usage, self.nproc, self.io_usage, self.iops)): return True if any((getattr(self, k) for k in FAULTS)): return True return False def _has_changed_limits(self, new, old): """ :type old: lvestat.LVEStat :type new: lvestat.LVEStat """ for attr in LIMITS: if getattr(new, attr, None) != getattr(old, attr, None): return True return False def _has_changed_nproc(self, new, old): """ :type old: lvestat.LVEStat :type new: lvestat.LVEStat """ return old.nproc != new.nproc def convert_lcpu_to_new_kernel_format(self, lcpu, lve_ver, procs): """ New kernel format lcpu is 100 times bigger than previous. So that it's 0-10000 """ if lve_ver >= 8: return lcpu else: # new_kernel_format = (old_format * 10000 * procs / 100) = old_format * 100 * procs return lcpu * procs * 100 def is_lve_data_changed(self, old, new): """ Check if LVE data is changed :param old: Previous data :param new: Current data :return: True - changes, false - not """ # Common data if old.cpu_usage != new.cpu_usage \ or old.mep != new.mep \ or old.mem_fault != new.mem_fault \ or old.mep_fault != new.mep_fault \ or old.mem_usage != new.mem_usage \ or old.lep != new.lep \ or old.io != new.io \ or old.io_usage != new.io_usage: return True # LVE6+ data if (old.memphy != new.memphy or old.memphy_fault != new.memphy_fault or old.nproc != new.nproc or old.nproc_fault != new.nproc_fault): return True # LVE8+ data if self.lve_version >= 8 and old.iops != new.iops: return True return False def calc(self, old, new, hz, time, procs): self.time = time # LCPU 100% now is 100*100 = 10 000 # LCPU 0% is 0 self.lcpu = self.convert_lcpu_to_new_kernel_format(new.cpu, self.lve_version, procs) if bool(old): # Previous data present self.has_changed_limits = self._has_changed_limits(new, old) self.has_changed_nproc = self._has_changed_nproc(new, old) # CPU USAGE is 0-10000*procs # new_kernel_format = (old_format * 10000 * procs / 100) = old_format * 100 * procs; # (100 * (new.cpu_usage - self.cpu_usage) / (hz * time)) = old_format assert time is not None, "oldstats is not None, but time is unknown" assert time != 0, "oldstats is not None, but time is 0" if new.cpu_usage > old.cpu_usage: self.cpu_usage = int(round(10000 * (new.cpu_usage - old.cpu_usage) * procs / (hz * time))) if new.mem_fault > old.mem_fault: self.mem_fault = new.mem_fault - old.mem_fault if new.mep_fault > old.mep_fault: self.mep_fault = new.mep_fault - old.mep_fault if new.memphy_fault > old.memphy_fault: self.memphy_fault = new.memphy_fault - old.memphy_fault if new.nproc_fault > old.nproc_fault: self.nproc_fault = new.nproc_fault - old.nproc_fault if new.io_usage > old.io_usage: # bytes per second self.io_usage = int(round(KB * (new.io_usage - old.io_usage) / time)) if self.lve_version >= 8: if new.iops > old.iops: self.iops = int(round((new.iops - old.iops) / time)) if self.cpu_usage < 0: self.cpu_usage = 0 elif self.cpu_usage >= self.lcpu > 0: self.cpu_usage = self.lcpu self.cpu_fault += 1 self.lmem = new.lmem if self.mem_fault > 0 or new.mem_usage > new.lmem > 0: self.mem_usage = new.lmem else: self.mem_fault = 0 self.mem_usage = new.mem_usage self.lep = new.lep if self.mep_fault > 0 or new.mep > new.lep > 0: self.mep = new.lep else: self.mep_fault = 0 self.mep = new.mep if self.lve_version >= 8: self.liops = new.liops if self.iops >= self.liops > 0: self.iops = self.liops self.iops_fault += 1 self.io = KB * new.io # limit in bytes per second if self.io_usage < 0: self.io_usage = 0 elif self.io_usage >= self.io > 0: self.io_usage = self.io self.io_fault += 1 self.lmemphy = new.lmemphy self.lnproc = new.lnproc if self.memphy_fault > 0 or new.memphy > new.lmemphy > 0: self.memphy = new.lmemphy else: self.memphy_fault = 0 self.memphy = new.memphy if self.nproc_fault > 0 or new.nproc > new.lnproc > 0: self.nproc = new.lnproc else: self.nproc_fault = 0 self.nproc = new.nproc def __str__(self): return "(cpu_usage=" + str(self.cpu_usage) + ", mep=" + str(self.mep) + ")" def __getitem__(self, key): return getattr(self, key)