1# 2# Copyright (c) 2024 Huawei Device Co., Ltd. 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16import os 17import sys 18import subprocess 19import sqlite3 20import threading 21import time 22import re 23import shutil 24import uuid 25import random 26import json 27import sqlite3 28import datetime 29import pandas as pd 30import inspect 31 32# The following programs are packaged as exe commands 33# pyinstaller --onefile get_mem_excel.py 34 35now_time = "null" 36now_version = "null" 37hidumper_num = 0 38pid_list = [] 39mem_file_name = "" 40mem_smaps_file_name = "" 41 42 43# Run a cmd command 44def run_cmd(cmd): 45 __func__ = inspect.currentframe().f_code.co_name 46 print(f"{__func__}: {cmd}") 47 output = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, 48 check=True).stdout 49 print(f"{__func__}: result:{str(output)}") 50 return output 51 52 53# Wait for the HDC to connect to the device 54def wait_for_device(): 55 __func__ = inspect.currentframe().f_code.co_name 56 print(f"{__func__}: in") 57 run_cmd("hdc wait-for-device") 58 59 60# Gets the current time, which is used as the file name part of the scraped data 61def update_now_time(): 62 __func__ = inspect.currentframe().f_code.co_name 63 print(f"{__func__}: in") 64 global now_time 65 now_time = str(datetime.datetime.now().strftime("%Y%m%d-%H%M%S")) 66 67 68# Obtain the current device version number, which is used as the file name part of the scraped data 69def update_now_version(): 70 __func__ = inspect.currentframe().f_code.co_name 71 print(f"{__func__}: in") 72 global now_version 73 now_version = str(run_cmd("hdc shell param get const.product.software.version")).replace("\n", "").replace(" ", "") 74 75 76# Obtain the list of process names to be captured from the pid_list.txt, if not configured, there is a default value 77def get_pid_list(): 78 __func__ = inspect.currentframe().f_code.co_name 79 print(f"{__func__}: in") 80 global pid_list 81 list_file_path = "pid_list.txt" 82 if os.path.exists(list_file_path): 83 list_file = open(list_file_path, 'r') 84 for line in list_file.readlines(): 85 pid_list.append(line.replace('\n', '')) 86 else: 87 print(f"{__func__}: pid_list.txt not exists, get mem for sensor_host,vibrator_host,audio_host,allocator_host") 88 pid_list.append('sensor_host') 89 pid_list.append('vibrator_host') 90 pid_list.append('audio_host') 91 pid_list.append('allocator_host') 92 93 94# Grab simple memory information for a process 95def get_mem(p_name): 96 __func__ = inspect.currentframe().f_code.co_name 97 print(f"{__func__}: in, p_name {p_name}") 98 global mem_file_name 99 mem_file_name = "result-mem" + now_version + p_name + now_time + ".txt" 100 cmd = "hdc shell \"hidumper --mem `pidof " + p_name + "`\" > " + mem_file_name 101 run_cmd(cmd) 102 103 104# Fetch detailed memory information for a process 105def get_mem_smaps(p_name): 106 __func__ = inspect.currentframe().f_code.co_name 107 print(f"{__func__}: in, p_name {p_name}") 108 global mem_smaps_file_name 109 mem_smaps_file_name = "result-mem_smaps" + now_version + p_name + now_time + ".txt" 110 cmd = "hdc shell \"hidumper --mem-smaps `pidof " + p_name + "` -v\" > " + mem_smaps_file_name 111 run_cmd(cmd) 112 113 114# Parse Excel sheets based on detailed memory information for a process 115def get_mem_smaps_excel(p_name): 116 global hidumper_num 117 __func__ = inspect.currentframe().f_code.co_name 118 print(f"{__func__}: in") 119 mem_file = open(mem_smaps_file_name, "r") 120 datas = mem_file.readlines() 121 result_map = {} 122 result_list = [] 123 mem_index = -1 124 for line in datas: 125 fields = line.split() 126 if len(fields) > 2 and 'Pss' in fields: 127 hidumper_num = len(fields) 128 mem_index = fields.index("Pss") 129 continue 130 if len(fields) == 10: 131 mem_data = int(fields[mem_index]) 132 result_map["总和"] = mem_data 133 continue 134 if len(fields) != hidumper_num or hidumper_num == 0 or mem_index == -1: 135 continue 136 mem_data = int(fields[mem_index]) 137 mem_name = fields[hidumper_num - 1] 138 matchs = [ 139 r'\[anon:guard:\d*\]', 140 r'\[anon:stack:\d*\]', 141 r'\[anon:signal_stack:\d*\]' 142 ] 143 for match in matchs: 144 if re.findall(match, mem_name): 145 mem_name = match 146 if mem_name not in result_map: 147 result_map[mem_name] = 0 148 result_map[mem_name] += mem_data 149 for key in result_map: 150 result_list.append([key, result_map[key]]) 151 headers = ['作用域名', '内存值'] 152 df = pd.DataFrame(result_list, columns=headers) 153 output_file = "result-mem-" + now_version + p_name + now_time + ".xlsx" 154 df.to_excel(output_file, index=False) 155 156 157# Scrape a process's in-memory data 158def get_data(p_name): 159 get_mem(p_name) 160 get_mem_smaps(p_name) 161 get_mem_smaps_excel(p_name) 162 163 164# Scrapes the memory data of all configured processes 165def get_all_process_data(): 166 for p_name in pid_list: 167 get_data(p_name) 168 169 170# Perform a one-time crawl of memory data for all processes configured 171def get_data_once(): 172 wait_for_device() 173 update_now_time() 174 update_now_version() 175 get_all_process_data() 176 177 178# Perform num fetch of the memory data of all processes configured at daily intervals 179def get_data_more(num, daily): 180 for i in range(num): 181 get_data_once() 182 time.sleep(daily) 183 184 185if __name__ == "__main__": 186 get_pid_list() 187 get_data_more(1, 10) 188 pass 189