1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import sys 17import os 18import time 19import platform 20from datetime import datetime 21import re 22from pathlib import Path 23import subprocess 24from collections import defaultdict 25 26from resources.global_var import ROOT_CONFIG_FILE 27from log_util import LogUtil 28from io_util import IoUtil 29 30GB_CONSTANT = 1024 ** 3 31MEM_CONSTANT = 1024 32RET_CONSTANT = 0 33MONITOR_TIME_CONSTANT = 30 34SNOP_TIME_CONSTANT = 5 35 36memory_info = [RET_CONSTANT] * 3 37target_keys = ['MemTotal', 'SwapTotal', 'MemFree'] 38key_indices = {key: index for index, key in enumerate(target_keys)} 39 40 41class Monitor(): 42 def __init__(self): 43 self.now_times = [] 44 self.usr_cpus = [] 45 self.sys_cpus = [] 46 self.idle_cpus = [] 47 self.total_mems = [] 48 self.swap_mems = [] 49 self.free_mems = [] 50 self.log_path = "" 51 52 def collect_cpu_info(self): 53 if platform.system() != "Linux": 54 return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT 55 56 try: 57 top_command = ["top", "-bn1"] 58 grep_command = ["grep", "%Cpu(s)"] 59 top_output = subprocess.check_output(top_command, universal_newlines=True) 60 result = subprocess.check_output(grep_command, input=top_output, universal_newlines=True).strip() 61 if result: 62 parts = result.split() 63 if len(parts) >= 5: 64 usr_cpu_str = parts[1] 65 sys_cpu_str = parts[3] 66 idle_cpu_str = parts[7] 67 68 usr_cpu_str = usr_cpu_str.split(',')[0].rstrip('%') 69 sys_cpu_str = sys_cpu_str.split(',')[0].rstrip('%') 70 idle_cpu_str = idle_cpu_str.split(',')[0].rstrip('%') 71 72 usr_cpu = float(usr_cpu_str) if usr_cpu_str.replace('.', '', 1).isdigit() else RET_CONSTANT 73 sys_cpu = float(sys_cpu_str) if sys_cpu_str.replace('.', '', 1).isdigit() else RET_CONSTANT 74 idle_cpu = float(idle_cpu_str) if idle_cpu_str.replace('.', '', 1).isdigit() else RET_CONSTANT 75 76 self.usr_cpu = usr_cpu 77 self.sys_cpu = sys_cpu 78 self.idle_cpu = idle_cpu 79 return self.usr_cpu, self.sys_cpu, self.idle_cpu 80 else: 81 return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT 82 else: 83 return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT 84 except subprocess.CalledProcessError: 85 return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT 86 87 def extract_memory_value(self, line: str): 88 match = re.search(r'\d+', line) 89 return int(match.group()) * MEM_CONSTANT if match else RET_CONSTANT 90 91 def get_ret_num(self, line: str): 92 key = line.split(':')[0] 93 if key in target_keys: 94 value = self.extract_memory_value(line) 95 memory_info[key_indices[key]] = value 96 97 def get_linux_mem_info(self): 98 try: 99 with open('/proc/meminfo', 'r') as f: 100 for line in f: 101 self.get_ret_num(line) 102 return memory_info[0], memory_info[1], memory_info[2] 103 except FileNotFoundError: 104 return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT 105 except Exception as e: 106 print(f"Error occurred while getting memory info: {e}") 107 return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT 108 109 def collect_linux_mem_info(self): 110 total_memory, swap_memory, free_memory = self.get_linux_mem_info() 111 total_mem = round(total_memory / GB_CONSTANT, 1) 112 free_mem = round(free_memory / GB_CONSTANT, 1) 113 swap_mem = round(swap_memory / GB_CONSTANT, 1) 114 return total_mem, free_mem, swap_mem 115 116 def get_current_time(self): 117 now_time = datetime.now().strftime("%H:%M:%S") 118 self.now_times.append(now_time) 119 120 def get_current_cpu(self): 121 usr_cpu, sys_cpu, idle_cpu = self.collect_cpu_info() 122 self.usr_cpus.append(usr_cpu) 123 self.sys_cpus.append(sys_cpu) 124 self.idle_cpus.append(idle_cpu) 125 LogUtil.write_log(self.log_path, f"User Cpu%: {usr_cpu}%", "info") 126 LogUtil.write_log(self.log_path, f"System Cpu%: {sys_cpu}%", "info") 127 LogUtil.write_log(self.log_path, f"Idle CPU%: {idle_cpu}%", "info") 128 129 def get_current_memory(self): 130 total_mem, free_mem, swap_mem = self.collect_linux_mem_info() 131 self.total_mems.append(total_mem) 132 self.free_mems.append(free_mem) 133 self.swap_mems.append(swap_mem) 134 LogUtil.write_log(self.log_path, f"Total Memory: {total_mem}GB", "info") 135 LogUtil.write_log(self.log_path, f"Free Memory: {free_mem}GB", "info") 136 LogUtil.write_log(self.log_path, f"Swap Memory: {swap_mem}GB", "info") 137 138 def get_log_path(self): 139 count = 0 140 config_content = IoUtil.read_json_file(ROOT_CONFIG_FILE) 141 while not os.path.exists(ROOT_CONFIG_FILE) or not config_content.get('out_path', None) and count <= 60: 142 time.sleep(SNAP_TIME_CONSTANT) 143 count += 1 144 return config_content.get('out_path', None) 145 146 def get_disk_usage(self): 147 result = subprocess.run(['df', '-h'], stdout=subprocess.PIPE, text=True) 148 if result.returncode == 0: 149 lines = result.stdout.strip().split('\n')[1:] 150 for line in lines: 151 columns = line.split() 152 if len(columns) > 5: 153 filesystem, size, used, available, percent, mountpoint = columns[:6] 154 LogUtil.write_log(self.log_path, 155 f"Filesystem: {filesystem}, " 156 f"Size: {size}, " 157 f"Used: {used}, " 158 f"Available: {available}, " 159 f"Use%: {percent}, " 160 f"Mounted on: {mountpoint}", 161 "info") 162 else: 163 LogUtil.write_log(self.log_path, f"Error running df command:{result.stderr}", "info") 164 165 def run(self): 166 if platform.system() != "Linux": 167 return 168 out_path = self.get_log_path() 169 self.log_path = os.path.join(out_path, "build.log") 170 self.get_current_time() 171 self.get_current_cpu() 172 self.get_current_memory() 173 self.get_disk_usage() 174