15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2024 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport sys
175f9996aaSopenharmony_ciimport os
185f9996aaSopenharmony_ciimport time
195f9996aaSopenharmony_ciimport platform
205f9996aaSopenharmony_cifrom datetime import datetime
215f9996aaSopenharmony_ciimport re
225f9996aaSopenharmony_cifrom pathlib import Path
235f9996aaSopenharmony_ciimport subprocess
245f9996aaSopenharmony_cifrom collections import defaultdict
255f9996aaSopenharmony_ci
265f9996aaSopenharmony_cifrom resources.global_var import ROOT_CONFIG_FILE
275f9996aaSopenharmony_cifrom log_util import LogUtil
285f9996aaSopenharmony_cifrom io_util import IoUtil
295f9996aaSopenharmony_ci
305f9996aaSopenharmony_ciGB_CONSTANT = 1024 ** 3
315f9996aaSopenharmony_ciMEM_CONSTANT = 1024
325f9996aaSopenharmony_ciRET_CONSTANT = 0
335f9996aaSopenharmony_ciMONITOR_TIME_CONSTANT = 30
345f9996aaSopenharmony_ciSNOP_TIME_CONSTANT = 5
355f9996aaSopenharmony_ci
365f9996aaSopenharmony_cimemory_info = [RET_CONSTANT] * 3
375f9996aaSopenharmony_citarget_keys = ['MemTotal', 'SwapTotal', 'MemFree']
385f9996aaSopenharmony_cikey_indices = {key: index for index, key in enumerate(target_keys)}
395f9996aaSopenharmony_ci
405f9996aaSopenharmony_ci
415f9996aaSopenharmony_ciclass Monitor():
425f9996aaSopenharmony_ci    def __init__(self):
435f9996aaSopenharmony_ci        self.now_times = []
445f9996aaSopenharmony_ci        self.usr_cpus = []
455f9996aaSopenharmony_ci        self.sys_cpus = []
465f9996aaSopenharmony_ci        self.idle_cpus = []
475f9996aaSopenharmony_ci        self.total_mems = []
485f9996aaSopenharmony_ci        self.swap_mems = []
495f9996aaSopenharmony_ci        self.free_mems = []
505f9996aaSopenharmony_ci        self.log_path = ""
515f9996aaSopenharmony_ci
525f9996aaSopenharmony_ci    def collect_cpu_info(self):
535f9996aaSopenharmony_ci        if platform.system() != "Linux":
545f9996aaSopenharmony_ci            return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT
555f9996aaSopenharmony_ci
565f9996aaSopenharmony_ci        try:
575f9996aaSopenharmony_ci            top_command = ["top", "-bn1"]
585f9996aaSopenharmony_ci            grep_command = ["grep", "%Cpu(s)"]
595f9996aaSopenharmony_ci            top_output = subprocess.check_output(top_command, universal_newlines=True)
605f9996aaSopenharmony_ci            result = subprocess.check_output(grep_command, input=top_output, universal_newlines=True).strip()
615f9996aaSopenharmony_ci            if result:
625f9996aaSopenharmony_ci                parts = result.split()
635f9996aaSopenharmony_ci                if len(parts) >= 5:
645f9996aaSopenharmony_ci                    usr_cpu_str = parts[1]
655f9996aaSopenharmony_ci                    sys_cpu_str = parts[3]
665f9996aaSopenharmony_ci                    idle_cpu_str = parts[7]
675f9996aaSopenharmony_ci
685f9996aaSopenharmony_ci                    usr_cpu_str = usr_cpu_str.split(',')[0].rstrip('%')
695f9996aaSopenharmony_ci                    sys_cpu_str = sys_cpu_str.split(',')[0].rstrip('%')
705f9996aaSopenharmony_ci                    idle_cpu_str = idle_cpu_str.split(',')[0].rstrip('%')
715f9996aaSopenharmony_ci
725f9996aaSopenharmony_ci                    usr_cpu = float(usr_cpu_str) if usr_cpu_str.replace('.', '', 1).isdigit() else RET_CONSTANT
735f9996aaSopenharmony_ci                    sys_cpu = float(sys_cpu_str) if sys_cpu_str.replace('.', '', 1).isdigit() else RET_CONSTANT
745f9996aaSopenharmony_ci                    idle_cpu = float(idle_cpu_str) if idle_cpu_str.replace('.', '', 1).isdigit() else RET_CONSTANT
755f9996aaSopenharmony_ci
765f9996aaSopenharmony_ci                    self.usr_cpu = usr_cpu
775f9996aaSopenharmony_ci                    self.sys_cpu = sys_cpu
785f9996aaSopenharmony_ci                    self.idle_cpu = idle_cpu
795f9996aaSopenharmony_ci                    return self.usr_cpu, self.sys_cpu, self.idle_cpu
805f9996aaSopenharmony_ci                else:
815f9996aaSopenharmony_ci                    return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT
825f9996aaSopenharmony_ci            else:
835f9996aaSopenharmony_ci                return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT
845f9996aaSopenharmony_ci        except subprocess.CalledProcessError:
855f9996aaSopenharmony_ci            return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT
865f9996aaSopenharmony_ci
875f9996aaSopenharmony_ci    def extract_memory_value(self, line: str):
885f9996aaSopenharmony_ci        match = re.search(r'\d+', line)
895f9996aaSopenharmony_ci        return int(match.group()) * MEM_CONSTANT if match else RET_CONSTANT
905f9996aaSopenharmony_ci
915f9996aaSopenharmony_ci    def get_ret_num(self, line: str):
925f9996aaSopenharmony_ci        key = line.split(':')[0]
935f9996aaSopenharmony_ci        if key in target_keys:
945f9996aaSopenharmony_ci            value = self.extract_memory_value(line)
955f9996aaSopenharmony_ci            memory_info[key_indices[key]] = value
965f9996aaSopenharmony_ci
975f9996aaSopenharmony_ci    def get_linux_mem_info(self):
985f9996aaSopenharmony_ci        try:
995f9996aaSopenharmony_ci            with open('/proc/meminfo', 'r') as f:
1005f9996aaSopenharmony_ci                for line in f:
1015f9996aaSopenharmony_ci                    self.get_ret_num(line)
1025f9996aaSopenharmony_ci            return memory_info[0], memory_info[1], memory_info[2]
1035f9996aaSopenharmony_ci        except FileNotFoundError:
1045f9996aaSopenharmony_ci            return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT
1055f9996aaSopenharmony_ci        except Exception as e:
1065f9996aaSopenharmony_ci            print(f"Error occurred while getting memory info: {e}")
1075f9996aaSopenharmony_ci            return RET_CONSTANT, RET_CONSTANT, RET_CONSTANT
1085f9996aaSopenharmony_ci
1095f9996aaSopenharmony_ci    def collect_linux_mem_info(self):
1105f9996aaSopenharmony_ci        total_memory, swap_memory, free_memory = self.get_linux_mem_info()
1115f9996aaSopenharmony_ci        total_mem = round(total_memory / GB_CONSTANT, 1)
1125f9996aaSopenharmony_ci        free_mem = round(free_memory / GB_CONSTANT, 1)
1135f9996aaSopenharmony_ci        swap_mem = round(swap_memory / GB_CONSTANT, 1)
1145f9996aaSopenharmony_ci        return total_mem, free_mem, swap_mem
1155f9996aaSopenharmony_ci
1165f9996aaSopenharmony_ci    def get_current_time(self):
1175f9996aaSopenharmony_ci        now_time = datetime.now().strftime("%H:%M:%S")
1185f9996aaSopenharmony_ci        self.now_times.append(now_time)
1195f9996aaSopenharmony_ci
1205f9996aaSopenharmony_ci    def get_current_cpu(self):
1215f9996aaSopenharmony_ci        usr_cpu, sys_cpu, idle_cpu = self.collect_cpu_info()
1225f9996aaSopenharmony_ci        self.usr_cpus.append(usr_cpu)
1235f9996aaSopenharmony_ci        self.sys_cpus.append(sys_cpu)
1245f9996aaSopenharmony_ci        self.idle_cpus.append(idle_cpu)
1255f9996aaSopenharmony_ci        LogUtil.write_log(self.log_path, f"User Cpu%: {usr_cpu}%", "info")
1265f9996aaSopenharmony_ci        LogUtil.write_log(self.log_path, f"System Cpu%: {sys_cpu}%", "info")
1275f9996aaSopenharmony_ci        LogUtil.write_log(self.log_path, f"Idle CPU%: {idle_cpu}%", "info")
1285f9996aaSopenharmony_ci
1295f9996aaSopenharmony_ci    def get_current_memory(self):
1305f9996aaSopenharmony_ci        total_mem, free_mem, swap_mem = self.collect_linux_mem_info()
1315f9996aaSopenharmony_ci        self.total_mems.append(total_mem)
1325f9996aaSopenharmony_ci        self.free_mems.append(free_mem)
1335f9996aaSopenharmony_ci        self.swap_mems.append(swap_mem)
1345f9996aaSopenharmony_ci        LogUtil.write_log(self.log_path, f"Total Memory: {total_mem}GB", "info")
1355f9996aaSopenharmony_ci        LogUtil.write_log(self.log_path, f"Free Memory: {free_mem}GB", "info")
1365f9996aaSopenharmony_ci        LogUtil.write_log(self.log_path, f"Swap Memory: {swap_mem}GB", "info")
1375f9996aaSopenharmony_ci
1385f9996aaSopenharmony_ci    def get_log_path(self):
1395f9996aaSopenharmony_ci        count = 0
1405f9996aaSopenharmony_ci        config_content = IoUtil.read_json_file(ROOT_CONFIG_FILE)
1415f9996aaSopenharmony_ci        while not os.path.exists(ROOT_CONFIG_FILE) or not config_content.get('out_path', None) and count <= 60:
1425f9996aaSopenharmony_ci            time.sleep(SNAP_TIME_CONSTANT)
1435f9996aaSopenharmony_ci            count += 1
1445f9996aaSopenharmony_ci        return config_content.get('out_path', None)
1455f9996aaSopenharmony_ci
1465f9996aaSopenharmony_ci    def get_disk_usage(self):
1475f9996aaSopenharmony_ci        result = subprocess.run(['df', '-h'], stdout=subprocess.PIPE, text=True)
1485f9996aaSopenharmony_ci        if result.returncode == 0:
1495f9996aaSopenharmony_ci            lines = result.stdout.strip().split('\n')[1:]
1505f9996aaSopenharmony_ci            for line in lines:
1515f9996aaSopenharmony_ci                columns = line.split()
1525f9996aaSopenharmony_ci                if len(columns) > 5:
1535f9996aaSopenharmony_ci                    filesystem, size, used, available, percent, mountpoint = columns[:6]
1545f9996aaSopenharmony_ci                    LogUtil.write_log(self.log_path,
1555f9996aaSopenharmony_ci                    f"Filesystem: {filesystem}, "
1565f9996aaSopenharmony_ci                    f"Size: {size}, "
1575f9996aaSopenharmony_ci                    f"Used: {used}, "
1585f9996aaSopenharmony_ci                    f"Available: {available}, "
1595f9996aaSopenharmony_ci                    f"Use%: {percent}, "
1605f9996aaSopenharmony_ci                    f"Mounted on: {mountpoint}",
1615f9996aaSopenharmony_ci                    "info")
1625f9996aaSopenharmony_ci        else:
1635f9996aaSopenharmony_ci            LogUtil.write_log(self.log_path, f"Error running df command:{result.stderr}", "info")
1645f9996aaSopenharmony_ci
1655f9996aaSopenharmony_ci    def run(self):
1665f9996aaSopenharmony_ci        if platform.system() != "Linux":
1675f9996aaSopenharmony_ci            return
1685f9996aaSopenharmony_ci        out_path = self.get_log_path()
1695f9996aaSopenharmony_ci        self.log_path = os.path.join(out_path, "build.log")
1705f9996aaSopenharmony_ci        self.get_current_time()
1715f9996aaSopenharmony_ci        self.get_current_cpu()
1725f9996aaSopenharmony_ci        self.get_current_memory()
1735f9996aaSopenharmony_ci        self.get_disk_usage()
174