def _dumpsys_process_meminfo(self, process): ''' dump 进程详细内存 耗时 1s以内 :param process: :return: ''' time_old = time.time() out = self.device.adb.run_shell_cmd('dumpsys meminfo %s' % process) # self.num = self.num + 1 # if self.num % 10 == 0: #避免:在windows 无法创建文件名,不能有冒号: process_rename = process.replace(":", "_") meminfo_file = os.path.join(RuntimeData.package_save_path, 'dumpsys_meminfo_%s.txt' % process_rename) with open(meminfo_file, "a+") as writer: writer.write(TimeUtils.getCurrentTime() + " dumpsys meminfo package info:\n") if out: writer.write(out + "\n\n") # self.num = 0 passedtime = time.time() - time_old #测试meminfo这个命令的耗时,执行的时长在400多ms logger.debug("dumpsys meminfo package time consume:" + str(passedtime)) out.replace('\r', '') return MemInfoPackage(dump=out)
def _collect_thread_num_thread(self, start_time): end_time = time.time() + self._timeout thread_list_titile = ("datatime", "packagename", "pid", "thread_num") thread_num_file = os.path.join(RuntimeData.package_save_path, 'thread_num.csv') try: with open(thread_num_file, 'a+') as df: csv.writer(df, lineterminator='\n').writerow(thread_list_titile) if self.thread_queue: thread_file_dic = {'thread_file': thread_num_file} self.thread_queue.put(thread_file_dic) except RuntimeError as e: logger.error(e) while not self._stop_event.is_set() and time.time() < end_time: try: before = time.time() logger.debug( "-----------into _collect_thread_num_thread loop, thread is : " + str(threading.current_thread().name)) # 获取pakagename的thread num信息 thread_pck_info = self.get_process_thread_num(self.packagename) logger.debug(thread_pck_info) current_time = TimeUtils.getCurrentTime() if not thread_pck_info: continue else: logger.debug("current time: " + current_time + ", processname: " + thread_pck_info[1] + ", pid: " + str(thread_pck_info[2]) + " thread num: " + str(thread_pck_info[3])) if self.thread_queue: self.thread_queue.put(thread_pck_info) if not self.thread_queue: #为了本地单个文件运行 try: with open(thread_num_file, 'a+') as thread_writer: writer_p = csv.writer(thread_writer, lineterminator='\n') thread_pck_info[0] = current_time writer_p.writerow(thread_pck_info) except RuntimeError as e: logger.error(e) after = time.time() time_consume = after - before delta_inter = self._interval - time_consume logger.debug("time_consume for thread num infos: " + str(time_consume)) if delta_inter > 0: time.sleep(delta_inter) except: logger.error( "an exception hanpend in thread num thread, reason unkown!" ) s = traceback.format_exc() logger.debug(s) if self.thread_queue: self.thread_queue.task_done()
def get_max_freq(self): out = self.device.adb.run_shell_cmd( "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq") out.replace('\r', '') max_freq_file = os.path.join(RuntimeData.package_save_path, 'scaling_max_freq.txt') with open(max_freq_file, "a+", encoding="utf-8") as writer: writer.write(TimeUtils.getCurrentTime() + " scaling_max_freq:\n") writer.write(out + "\n\n")
def _monkey_thread_func(self,save_dir): '''获取monkey线程,保存monkey日志,monkey Crash日志暂不处理,后续有需要再处理 ''' self.append_log_line_num = 0 self.file_log_line_num = 0 self.log_file_create_time = None log_is_none = 0 logs = [] logger.debug("monkey_thread_func") if RuntimeData.start_time is None: RuntimeData.start_time = TimeUtils.getCurrentTime() while self.running: try: log = self._log_pipe.stdout.readline().strip() if not isinstance(log, str): # 先编码为unicode try: log = str(log, "utf8") except Exception as e: log = repr(log) logger.error('str error:' + log) logger.error(e) if log: logs.append(log) self.append_log_line_num = self.append_log_line_num + 1 self.file_log_line_num = self.file_log_line_num + 1 # if self.append_log_line_num > 1000: if self.append_log_line_num > 100: if not self.log_file_create_time: self.log_file_create_time = TimeUtils.getCurrentTimeUnderline() log_file = os.path.join(save_dir, 'monkey_%s.log' % self.log_file_create_time) self.append_log_line_num = 0 # 降低音量,避免音量过大,导致语音指令失败 self.device.adb.run_shell_cmd("input keyevent 25") self.save(log_file, logs) logs = [] # 新建文件 if self.file_log_line_num > 600000: # if self.file_log_line_num > 200: self.file_log_line_num = 0 self.log_file_create_time = TimeUtils.getCurrentTimeUnderline() log_file = os.path.join(save_dir, 'monkey_%s.log' % self.log_file_create_time) self.save(log_file, logs) logs = [] else: log_is_none = log_is_none + 1 if log_is_none % 1000 == 0: logger.info("log is none") if not self.device.adb.is_process_running("com.android.commands.monkey") and self.running: self.device.adb.kill_process("com.android.commands.monkey") self._log_pipe = self.device.adb.run_shell_cmd(self.monkey_cmd, sync=False) except: logger.error("an exception hanpend in monkey thread, reason unkown!") s = traceback.format_exc() logger.debug(s)
def _parse_package(self): ''' 解析top命令中的包的cpu信息 :return: ''' if self.packages == None or self.packages == "": logger.error("no process name input, please input") for package in self.packages: package_dic = {"package": package, "pid": "", "pid_cpu": ""} sp_lines = self.source.split('\n') for line in sp_lines: # logger.debug(line) if package in line: #解析进程cpu信息 tmp = line.split() self.pid = tmp[0] target_pck = tmp[-1] #从中解析出的最后一个值是包名 self.datetime = TimeUtils.getCurrentTime() logger.debug("cpuinfos, _parse top target_pck is : " + str(target_pck) + " , self.pacakgename : " + package) if package == target_pck: #只统计包名完全相同的进程 if int(self.pid) > 0: logger.debug( "cpuinfos, into _parse_pck packege is target package, pid is :" + str(self.pid)) # logger.debug("into _parse_pck packege is target package, pid is :" + str(self.pid)) cpu_index = self.get_cpucol_index() uid_index = self.get_uidcol_index() if (len(tmp) > cpu_index): self.pck_cpu_rate = tmp[cpu_index] # CPU% 9% 有的格式会有% self.pck_cpu_rate = self.pck_cpu_rate.replace( "%", "") if (len(tmp) > uid_index): self.uid = tmp[uid_index] package_dic = { "package": package, "pid": self.pid, "pid_cpu": str(self.pck_cpu_rate), "uid": self.uid } # self.package_list.append(package_dic) # 将top中解析出来的信息保存在一个列表中,作为一条记录添加在package_list中 logger.debug("package: " + package + ", cpu_rate: " + str(self.pck_cpu_rate)) self.total_pid_cpu = self.total_pid_cpu + float( self.pck_cpu_rate) break self.package_list.append(package_dic) logger.debug(package_dic)
def _activity_monitor_thread(self): activity_title = ("datetime", "current_activity") self.activity_file = os.path.join(RuntimeData.package_save_path, 'current_activity.csv') try: with open(self.activity_file, 'a+') as af: csv.writer(af, lineterminator='\n').writerow(activity_title) except Exception as e: logger.error("file not found: " + str(self.activity_file)) while not self.stop_event.is_set(): try: before = time.time() self.current_activity = self.device.adb.get_current_activity() collection_time = time.time() activity_list = [collection_time, self.current_activity] if self.activity_queue: logger.debug("activity monitor thread activity_list: " + str(activity_list)) self.activity_queue.put(activity_list) if self.current_activity: logger.debug("current activity: " + self.current_activity) if self.main_activity and self.activity_list: if self.current_activity not in self.activity_list: start_activity = self.packagename + "/" + self.main_activity[ random.randint(0, len(self.main_activity) - 1)] logger.debug("start_activity:" + start_activity) self.device.adb.start_activity(start_activity) activity_tuple = (TimeUtils.getCurrentTime(), self.current_activity) # 写文件 try: with open(self.activity_file, 'a+') as writer: writer_p = csv.writer(writer, lineterminator='\n') writer_p.writerow(activity_tuple) except RuntimeError as e: logger.error(e) time_consume = time.time() - before delta_inter = self.interval - time_consume logger.debug("get app activity time consumed: " + str(time_consume)) if delta_inter > 0: time.sleep(delta_inter) except Exception as e: s = traceback.format_exc() logger.debug(s) # 将堆栈信息打印到log中 if self.activity_queue: self.activity_queue.task_done()
def _top_cpuinfo(self): self._top_pipe = self.device.adb.run_shell_cmd(self.top_cmd, sync=False) out = self._top_pipe.stdout.read() error = self._top_pipe.stderr.read() if error: logger.error("into cpuinfos error : " + str(error)) return out = str(out, "utf-8") out.replace('\r', '') top_file = os.path.join(RuntimeData.package_save_path, 'top.txt') with open(top_file, "a+", encoding="utf-8") as writer: writer.write(TimeUtils.getCurrentTime() + " top info:\n") writer.write(out + "\n\n") #避免文件过大,超过100M清理 if FileUtils.get_FileSize(top_file) > 100: os.remove(top_file) return PckCpuinfo(self.packages, out, self.sdkversion)
def _dumpsys_meminfo(self): ''' 总内存 各进程内存都从dumpsys meminfo中获取 这个方法挺耗时 约6 7秒才能完成 :return: ''' time_old = time.time() out = self.device.adb.run_shell_cmd('dumpsys meminfo') meminfo_file = os.path.join(RuntimeData.package_save_path, 'dumpsys_meminfo.txt') with open(meminfo_file, "a+",encoding="utf-8") as writer: writer.write(TimeUtils.getCurrentTime()+" dumpsys meminfo info:\n") writer.write(out+"\n\n") # self.num = 0 passedtime = time.time() - time_old#测试meminfo这个命令的耗时,执行的时长在400多ms logger.debug("dumpsys meminfo time consume:" + str(passedtime)) out.replace('\r', '') return MemInfoDevice(dump=out,packages=self.packages)
class ThreadNumMonitor(object): def __init__(self, device_id, packagename, interval=1.0, timeout=24 * 60 * 60, thread_queue=None): self.device = AndroidDevice(device_id) if not packagename: packagename = self.device.adb.get_foreground_process() self.thread_package_collector = ThreadNumPackageCollector( self.device, packagename, interval, timeout, thread_queue) def start(self, start_time): self.start_time = start_time self.thread_package_collector.start(start_time) def stop(self): self.thread_package_collector.stop() def save(self): pass if __name__ == "__main__": monitor = ThreadNumMonitor("", "com.yunos.tv.alitvasr", 3) monitor.start(TimeUtils.getCurrentTime()) time.sleep(20) monitor.stop() # monitor.save()
def _collect_cpu_thread(self, start_time): end_time = time.time() + self._timeout cpu_title = ["datetime", "device_cpu_rate%", "user%", "system%"] cpu_file = os.path.join(RuntimeData.package_save_path, 'cpuinfo.csv') for i in range(0, len(self.packages)): cpu_title.append("package", "pid", "pid_cpu%") cpu_title.append("total_pid_cpu%") try: with open(cpu_file, 'a+') as df: csv.writer(df, lineterminator='\n').writerow(cpu_title) if self.cpu_queue: cpu_file_dic = {'cpu_file': cpu_file} self.cpu_queue.put(cpu_file_dic) except RuntimeError as e: logger.error(e) while not self.stop_device_event.is_set() and time.time() < end_time: try: before = time.time() logger.debug("into _collect_cpu_thread loop thread is : " + str(threading.current_thread().name)) cpu_info = self._get_cpu_usage() logger.debug(" get cpu info: " + str(cpu_info)) cpu_pck_info = self._get_pck_cpu_usage() cpu_pck_info = self._trim_pakcage_info(cpu_pck_info, cpu_info) collection_time = time.time() logger.debug(" collection time in cpu is : " + TimeUtils.getCurrentTime()) if cpu_pck_info.pid == -1: logger.debug("cpu_pck pid is -1") continue gather_list = [ collection_time, cpu_info.cpu_rate, cpu_info.user_rate, cpu_info.system_rate ] if self.cpu_queue: self.cpu_queue.put(gather_list) for i in range(0, len(self.packages)): gather_list.append() # 添加进程 总cpu使用率 gather_list.append() if not self.cpu_queue: #为了让单个脚本运行 gather_list[0] = TimeUtils.formatTimeStamp(gather_list[0]) try: with open(cpu_file, 'a+', encoding="utf-8") as f: csv.writer( f, lineterminator='\n').writerow(gather_list) logger.debug("write to file:" + cpu_file) logger.debug(gather_list) except RuntimeError as e: logger.error(e) time_consume = time.time() - before logger.debug( " _collect_cpu_thread time consume for device cpu usage: " + str(format(time_consume, '0.2f'))) delta_inter = self._interval - time_consume if delta_inter > 0: time.sleep(delta_inter) except Exception as e: logger.error( "an exception hanpend in cpu thread , reason unkown!") s = traceback.format_exc() logger.debug(s) #将堆栈信息打印到log中 if self.cpu_queue: self.cpu_queue.task_done() logger.debug("stop event is set or timeout")
def _collect_package_cpu_thread(self, start_time): ''' 按照指定频率,循环搜集cpu的信息 :return: ''' end_time = time.time() + self._timeout cpu_title = [ "datetime", "device_cpu_rate%", "user%", "system%", "idle%" ] cpu_file = os.path.join(RuntimeData.package_save_path, 'cpuinfo.csv') for i in range(0, len(self.packages)): cpu_title.extend(["package", "pid", "pid_cpu%"]) if len(self.packages) > 1: cpu_title.append("total_pid_cpu%") try: with open(cpu_file, 'a+') as df: csv.writer(df, lineterminator='\n').writerow(cpu_title) except RuntimeError as e: logger.error(e) while not self._stop_event.is_set() and time.time() < end_time: try: course = os.system( 'adb shell pidof com.deskmateones') # TODO 调起同桌100 if course == 1: print("检查到同桌100没有运行,正在尝试调起") os.system( 'adb shell am broadcast -a com.baidu.duer.query -e q "打开同桌100"' ) else: pass logger.debug( "---------------cpuinfos, into _collect_package_cpu_thread loop thread is : " + str(threading.current_thread().name)) before = time.time() #为了cpu值的准确性,将采集的时间间隔放在top命令中了 cpu_info = self._top_cpuinfo() after = time.time() time_consume = after - before logger.debug(" ============== time consume for cpu info : " + str(time_consume)) if cpu_info == None or cpu_info.source == '' or not cpu_info.package_list: logger.debug("cpuinfos, can't get cpu info, continue") continue self.cpu_list.extend([ TimeUtils.getCurrentTime(), str(cpu_info.device_cpu_rate), cpu_info.user_rate, cpu_info.system_rate, cpu_info.idle_rate ]) for i in range(0, len(self.packages)): if len(cpu_info.package_list) == len(self.packages): self.cpu_list.extend([ cpu_info.package_list[i]["package"], cpu_info.package_list[i]["pid"], cpu_info.package_list[i]["pid_cpu"] ]) if len(self.packages) > 1: self.cpu_list.append(cpu_info.total_pid_cpu) #校准时间,由于top执行需要耗时,需要将这个损耗加上去 logger.debug("INFO: CpuMonitor save cpu_device_list: " + str(self.cpu_list)) try: with open(cpu_file, 'a+', encoding="utf-8") as df: csv.writer(df, lineterminator='\n').writerow(self.cpu_list) del self.cpu_list[:] except RuntimeError as e: logger.error(e) # self.get_max_freq() delta_inter = self._interval - time_consume if delta_inter > 0: time.sleep(delta_inter) except Exception as e: logger.error( "an exception hanpend in cpu thread , reason unkown!, e:") logger.error(e) s = traceback.format_exc() logger.debug(s) #将堆栈信息打印到log中 if self.cpu_queue: self.cpu_queue.task_done() logger.debug("stop event is set or timeout")
def _collect_memory_thread(self, start_time): end_time = time.time() + self._timeout mem_list_titile = ["datatime", "total_ram(MB)", "free_ram(MB)"] pid_list_titile = ["datatime"] pss_detail_titile = [ "datatime", "package", "pid", "pss", "java_heap", "native_heap", "system" ] for i in range(0, len(self.packages)): mem_list_titile.extend(["package", "pid", "pid_pss(MB)"]) pid_list_titile.extend(["package", "pid"]) if len(self.packages) > 1: mem_list_titile.append("total_pss(MB)") mem_file = os.path.join(RuntimeData.package_save_path, 'meminfo.csv') pid_file = os.path.join(RuntimeData.package_save_path, 'pid_change.csv') for package in self.packages: pss_detail_file = os.path.join( RuntimeData.package_save_path, 'pss_%s.csv' % package.split(".")[-1].replace(":", "_")) with open(pss_detail_file, 'a+') as df: csv.writer(df, lineterminator='\n').writerow(pss_detail_titile) try: with open(mem_file, 'a+') as df: csv.writer(df, lineterminator='\n').writerow(mem_list_titile) if self.mem_queue: mem_file_dic = {'mem_file': mem_file} self.mem_queue.put(mem_file_dic) with open(pid_file, 'a+') as df: csv.writer(df, lineterminator='\n').writerow(pid_list_titile) except RuntimeError as e: logger.error(e) starttime_stamp = TimeUtils.getTimeStamp(start_time, "%Y_%m_%d_%H_%M_%S") old_package_pid_pss_list = [] dumpsys_mem_times = 0 # D系统上会报错 System server has no access to file context # hprof_path = "/sdcard/hprof" hprof_path = "/data/local/tmp" self.device.adb.run_shell_cmd("mkdir " + hprof_path) # sdcard 卡目录下dump需要打开这个开关 self.device.adb.run_shell_cmd("setenforce 0") first_dump = True while not self._stop_event.is_set() and time.time() < end_time: try: before = time.time() logger.debug( "-----------into _collect_mem_thread loop, thread is : " + str(threading.current_thread().name)) collection_time = time.time() # # 获取主进程的详细信息 for package in self.packages: mem_pck_snapshot = self._dumpsys_process_meminfo(package) if 0 == mem_pck_snapshot.totalPSS: logger.error("package total pss is 0:%s" % package) continue pss_detail_file = os.path.join( RuntimeData.package_save_path, 'pss_%s.csv' % package.split(".")[-1].replace(":", "_")) pss_detail_list = [ TimeUtils.formatTimeStamp(collection_time), package, mem_pck_snapshot.pid, mem_pck_snapshot.totalPSS, mem_pck_snapshot.javaHeap, mem_pck_snapshot.nativeHeap, mem_pck_snapshot.system ] with open(pss_detail_file, 'a+') as pss_writer: writer_p = csv.writer(pss_writer, lineterminator='\n') writer_p.writerow(pss_detail_list) # 写到pss_detail表格中 # 手机每5分钟 dumpheap一次 if (before - starttime_stamp) > 300 or first_dump: # 先清理hprof文件 filelist = self.device.adb.list_dir(hprof_path) if filelist: for file in filelist: for package in self.packages: if package in file: self.device.adb.delete_file(hprof_path + "/" + file) # if (before - starttime_stamp) % 60 < self._interval and "D" in self.device.adb.get_system_version(): for package in self.packages: self.device.adb.dumpheap(package, RuntimeData.package_save_path) starttime_stamp = before # self.device.adb.run_shell_cmd("kill -10 %s"%str(mem_pck_snapshot.pid)) # dumpsys meminfo 耗时长,可能会导致system server cpu占用变高,降低采集频率 dumpsys_mem_times = dumpsys_mem_times + 1 # 10倍率frequency dumpsys meminfo一次 if dumpsys_mem_times % 10 == 0 or first_dump: mem_device_snapshot = self._dumpsys_meminfo() # 如果没有采集到dumpsys meminfo的信息,正常情况totalmem不可能为0 if mem_device_snapshot == None or not mem_device_snapshot.package_pid_pss_list or mem_device_snapshot.totalmem == 0: logger.error("mem_device_snapshot is none") # 如果获取不到结果,继续延长采集间隔 dumpsys_mem_times = dumpsys_mem_times - 1 continue first_dump = False logger.debug("current time: " + TimeUtils.getCurrentTime() + ", processname: " + ",total pss:" + str(mem_device_snapshot.total_pss)) logger.debug("collection time in meminfo is : " + TimeUtils.getCurrentTime()) gather_list = [ TimeUtils.formatTimeStamp(collection_time), mem_device_snapshot.totalmem, mem_device_snapshot.freemem ] pid_list = [TimeUtils.formatTimeStamp(collection_time)] pid_change = False for i in range(0, len(self.packages)): if len(mem_device_snapshot.package_pid_pss_list ) == len(self.packages): gather_list.extend([ mem_device_snapshot.package_pid_pss_list[i] ["package"], mem_device_snapshot.package_pid_pss_list[i] ["pid"], mem_device_snapshot.package_pid_pss_list[i] ["pss"] ]) if not old_package_pid_pss_list: old_package_pid_pss_list = mem_device_snapshot.package_pid_pss_list pid_change = True else: for i in range(0, len(self.packages)): package = mem_device_snapshot.package_pid_pss_list[ i]["package"] if mem_device_snapshot.package_pid_pss_list[i]["pid"] and \ old_package_pid_pss_list[i]["pid"]!=mem_device_snapshot.package_pid_pss_list[i]["pid"]: pid_change = True # 确保上次pid也有 if old_package_pid_pss_list[i]["pid"]: if package and package in RuntimeData.config_dic[ "pid_change_focus_package"]: # 确保有tombstones文件才提单 self.device.adb.pull_file( "/data/vendor/tombstones", RuntimeData.package_save_path) if pid_change: old_package_pid_pss_list = mem_device_snapshot.package_pid_pss_list for i in range(0, len(self.packages)): if len(old_package_pid_pss_list) == len( self.packages): pid_list.extend([ old_package_pid_pss_list[i]["package"], old_package_pid_pss_list[i]["pid"] ]) try: with open(pid_file, 'a+') as pid_writer: writer_p = csv.writer(pid_writer, lineterminator='\n') writer_p.writerow(pid_list) logger.debug("write to file:" + pid_file) logger.debug(pid_list) except RuntimeError as e: logger.error(e) if len(self.packages) > 1: gather_list.append(mem_device_snapshot.total_pss) if self.mem_queue: gather_list[0] = collection_time self.mem_queue.put(gather_list) if not self.mem_queue: #为了本地单个文件运行 try: with open(mem_file, 'a+') as mem_writer: writer_p = csv.writer(mem_writer, lineterminator='\n') writer_p.writerow(gather_list) logger.debug("write to file:" + mem_file) logger.debug(gather_list) except RuntimeError as e: logger.error(e) after = time.time() time_consume = after - before delta_inter = self._interval - time_consume logger.info("time consume for meminfos: " + str(time_consume)) if delta_inter > 0: time.sleep(delta_inter) except: logger.error( "an exception hanpend in meminfo thread, reason unkown!") s = traceback.format_exc() logger.debug(s) if self.mem_queue: self.mem_queue.task_done() logger.debug("stop event is set or timeout")