def __init__(self, period, fileName, appName, loghd, serial=None): # threading.Thread.__init__(self); multiprocessing.Process.__init__(self) self.adb = Adb(serial=serial) self.appPid = 0 self.appName = appName self.period = period self.fileName = fileName + ".csv" self.pigName = fileName + ".jpg" self.loghd = loghd # self.getappPid() self.running = True self.lastRecord = {}
def __init__(self, device, taskId, taskName, testResults, loghd, serial=None): threading.Thread.__init__(self) # self.running = True self.adb = Adb(serial=serial) self.logcatSubProcess = None self.device = device self.taskId = taskId self.taskName = taskName self.testResults = testResults self.appPid = 0 self.loghd = loghd self.is_alive = False
class app_monitor(multiprocessing.Process): timeout_in_seconds = 60 def __init__(self, period, fileName, appName, loghd, serial=None, image=False, duration=0): # threading.Thread.__init__(self); multiprocessing.Process.__init__(self) self.adb = Adb(serial=serial) self.appPid = 0 self.appName = appName self.period = period self.fileName = fileName + ".csv" self.pigName = fileName + ".png" self.loghd = loghd # self.getappPid() self.running = True self.lastRecord = {} self.image = image self.duration = duration # self.is_alive = False def stop(self): # self.running = False try: while self.running and self.getAppPid( ) == self.appPid and self.getAppPid() != 0: self.loghd.info("appmonitor process still alive, wait ...") time.sleep(1) except: pass def getAppPid(self): # self.appPid = self.adb.cmd("shell", "set", "`ps|grep com.duowan.mobile$`;", "echo", "$2").communicate()[0].decode("utf-8").strip() outputs = self.adb.cmd("shell", "top", "-m", "10", "-n", "1").communicate()[0].decode("utf-8").strip() r = "(\\d+).*\\s+%s[^:]" % self.appName m = re.search(r, outputs) # print outputs if m: return m.group(1) else: self.loghd.info("app still not get up") return 0 def waitForAppReady(self): start_time = long(time.time()) while self.appPid == 0: elapsed = long(time.time()) - start_time # 做完一部分任务后,判断是否超时 if elapsed >= app_monitor.timeout_in_seconds: self.loghd.info("获取app pid超时,退出") self.running = False break self.loghd.info("appPid == 0") self.appPid = self.getAppPid() self.loghd.info(str(self.appPid)) def pic(self, processcpuRatioList, cpuRatioList, PSSList, NativeHeapList, DalvikHeapList, flowList): # matplotlib.use('Agg') plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 # 设置右侧Y轴显示百分数 fmt = '%.2f%%' yticks = mtick.FormatStrFormatter(fmt) def minY(listData): return round(min(listData) * 0.8, 2) def maxY(listData): return round(max(listData) * 1.2, 2) def drawSubplot(pos, x, y, xlabels, ylabels): plt.subplot(pos) plt.plot(x, y, label=ylabels) plt.xlabel(xlabels) plt.ylabel(ylabels) plt.ylim(minY(y), maxY(y)) # plt.title(u'应用CPU') plt.legend() plt.figure(figsize=(20, 10)) import platform systemtype = platform.system() winFlag = False if 'Darwin' in systemtype or 'Linux' in systemtype: xcoordinate = 'time(s)' elif 'Windows' in systemtype: xcoordinate = u'时间(秒)' winFlag = True else: #默认 xcoordinate = 'time(s)' timeList = [x * 2 for x in range(len(processcpuRatioList))] drawSubplot(321, timeList, processcpuRatioList, xcoordinate, u'应用CPU(%)' if winFlag else 'app-cpu(%)') plt.gca().yaxis.set_major_formatter(yticks) timeList = [x * 2 for x in range(len(cpuRatioList))] drawSubplot(322, timeList, cpuRatioList, xcoordinate, u"总cpu(%)" if winFlag else 'cpu(%)') plt.gca().yaxis.set_major_formatter(yticks) timeList = [x * 2 for x in range(len(PSSList))] drawSubplot(323, timeList, PSSList, xcoordinate, u"总内存(MB)" if winFlag else 'PSS(M)') timeList = [x * 2 for x in range(len(NativeHeapList))] drawSubplot(324, timeList, NativeHeapList, xcoordinate, u"Native内存(MB)" if winFlag else 'Native(M)') timeList = [x * 2 for x in range(len(DalvikHeapList))] drawSubplot(325, timeList, DalvikHeapList, xcoordinate, u"Dalvik内存(MB)" if winFlag else 'Dalvik(M)') timeList = [x * 2 for x in range(len(flowList))] drawSubplot(326, timeList, flowList, xcoordinate, u"流量(kb/s)" if winFlag else 'Traffic(Kbps)') # plt.gca().yaxis.set_minor_formatter(yticks) plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.55, wspace=0.25) # plt.show() print self.pigName plt.savefig(self.pigName) def run(self): # 根据应用的包名称 获取CPU以及内存占用 self.loghd.info("app_monitor run \n") # self.is_alive = True # 等待获取到被监控app的pid后才开始采集数据 print "waitForAppReady begin" self.waitForAppReady() print "Tracing pid = ", self.appPid print "waitForAppReady end\n" flowProfile = FlowProfiler(self.appPid, self.adb, self.loghd) cpuProfile = CpuProfiler(self.appPid, self.adb, self.loghd) memProfile = MemProfiler(self.appPid, self.adb, self.loghd) gpuProfile = GpuProfiler(self.appPid, self.adb, self.loghd) threadcountProfile = ThreadCount(self.appPid, self.appName, self.adb, self.loghd) flowProfile.init() memProfile.init() cpuProfile.init() trafficProfile = AppTrafficProfiler(self.appPid, self.adb, self.loghd) trafficProfile.init() f = open(self.fileName, "w+") f.write('\xEF\xBB\xBF') f.write(DATA_TITLE) firstRun = True errorTimes = 0 print DATA_TITLE.replace(",", " ").decode("utf-8") starttime = datetime.datetime.now() while self.running: try: nowtime = datetime.datetime.now() if self.duration != 0 and ( (nowtime - starttime).total_seconds() - self.period - 1) >= self.duration: self.running = False break str_now_time = time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime(time.time())) processcpuRatio, cpuRatio, retry = cpuProfile.profile() if retry: time.sleep(float(self.period)) continue PSS, NativeHeap, DalvikHeap = memProfile.profile() #flow, upflow, downflow = flowProfile.profile() flow, upflow, downflow = trafficProfile.profile() gpu = gpuProfile.getGpuInfo() threadcount = threadcountProfile.getThreadCount() write_str = "%s,%5s,%5s,%6s,%6s,%6s,%6s,%6s,%6s,%5s,%5s" % ( str(str_now_time), str(processcpuRatio), str(cpuRatio), str(PSS), str(NativeHeap), str(DalvikHeap), str(flow), str(upflow), str(downflow), str(gpu), str(threadcount)) # self.loghd.info(write_str.replace(",", " ")) print write_str.replace(",", " ") # 将数据写入文件 f.write(write_str + "\n") f.flush() except Exception, e: errorTimes += 1 if (errorTimes > 5): # 本来想尝试通过看app是否还在来判断,但是发现用例结束后,app仍然在后台运行 self.loghd.info( "monitor app end or process exception: %s" % e) break else: self.loghd.info("monitor app get data failed: %s" % e) self.waitForAppReady() continue #中低端机型采集数据命令需要约3秒,高端机型如P9/小米6等采集命令时间较短 collectiontime = (datetime.datetime.now() - nowtime).total_seconds() if float(self.period) > float(collectiontime): time.sleep(float(self.period - collectiontime)) f.close() if self.image: print u"开始绘图了" self.pic(cpuProfile.processcpuRatioList, cpuProfile.cpuRatioList, memProfile.PSSList, memProfile.NativeHeapList, memProfile.DalvikHeapList, trafficProfile.flowList) print u"绘图结束了" self.running = False
parser.add_argument('-s', '--device', help=u'target device serial. 设备ID') parser.add_argument( '-f', '--file', help=u'the path to store the result file, no ext. 结果存放文件,不带扩展名') parser.add_argument('-p', '--package', default='com.duowan.mobile', help=u'target app package name. 包名') parser.add_argument('-i', '--image', default=False, help=u'to draw results or not. 是否画图,默认不画') args = parser.parse_args() adbInstance = Adb() if adbInstance and (len(adbInstance.devices().keys()) == 0 or len( adbInstance.devices().keys()) > 1) and not args.device: print 'no device or multiple devices attached but no one is specified.' print adbInstance.devices().keys() raise RuntimeError # 默认值 argvmap['timeIntervalSec'] = args.time argvmap['result'] = os.path.abspath(args.file) if args.file \ else os.path.join(os.getcwd(), 'log', datetime.datetime.now().strftime("%Y%m%d_%H-%M-%S")) argvmap['package'] = args.package argvmap['serial'] = args.device if args.device else adbInstance.devices( ).keys()[0] argvmap['image'] = args.image argvmap['duration'] = args.duration
class app_monitor(multiprocessing.Process): timeout_in_seconds = 60 def __init__(self, period, fileName, appName, loghd, serial=None): # threading.Thread.__init__(self); multiprocessing.Process.__init__(self) self.adb = Adb(serial=serial) self.appPid = 0 self.appName = appName self.period = period self.fileName = fileName + ".csv" self.pigName = fileName + ".jpg" self.loghd = loghd # self.getappPid() self.running = True self.lastRecord = {} # self.is_alive = False def stop(self): # self.running = False try: while self.running and self.getAppPid( ) == self.appPid and self.getAppPid() != 0: self.loghd.info("appmonitor process still alive, wait ...") time.sleep(1) except: pass def getAppPid(self): # self.appPid = self.adb.cmd("shell", "set", "`ps|grep com.duowan.mobile$`;", "echo", "$2").communicate()[0].decode("utf-8").strip() outputs = self.adb.cmd("shell", "top", "-m", "10", "-n", "1").communicate()[0].decode("utf-8").strip() r = "(\\d+).*\\s+%s[^:]" % self.appName m = re.search(r, outputs) # print outputs if m: return m.group(1) else: self.loghd.info("app still not get up") return 0 def waitForAppReady(self): start_time = long(time.time()) while self.appPid == 0: elapsed = long(time.time()) - start_time # 做完一部分任务后,判断是否超时 if elapsed >= app_monitor.timeout_in_seconds: self.loghd.info("获取app pid超时,退出") self.running = False break self.loghd.info("appPid == 0") self.appPid = self.getAppPid() self.loghd.info(str(self.appPid)) def pic(self, processcpuRatioList, cpuRatioList, PSSList, NativeHeapList, DalvikHeapList, flowList): # matplotlib.use('Agg') plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 # 设置右侧Y轴显示百分数 fmt = '%.2f%%' yticks = mtick.FormatStrFormatter(fmt) def minY(listData): return round(min(listData) * 0.8, 2) def maxY(listData): return round(max(listData) * 1.2, 2) def drawSubplot(pos, x, y, xlabels, ylabels): plt.subplot(pos) plt.plot(x, y, label=ylabels) plt.xlabel(xlabels) plt.ylabel(ylabels) plt.ylim(minY(y), maxY(y)) # plt.title(u'应用CPU') plt.legend() plt.figure(figsize=(20, 10)) timeList = [x * 2 for x in range(len(processcpuRatioList))] drawSubplot(321, timeList, processcpuRatioList, u'时间(秒)', u'应用CPU(%)') plt.gca().yaxis.set_major_formatter(yticks) timeList = [x * 2 for x in range(len(cpuRatioList))] drawSubplot(322, timeList, cpuRatioList, u'时间(秒)', u"总cpu(%)") plt.gca().yaxis.set_major_formatter(yticks) timeList = [x * 2 for x in range(len(PSSList))] drawSubplot(323, timeList, PSSList, u'时间(秒)', u"总内存(MB)") timeList = [x * 2 for x in range(len(NativeHeapList))] drawSubplot(324, timeList, NativeHeapList, u'时间(秒)', u"Native内存(MB)") timeList = [x * 2 for x in range(len(DalvikHeapList))] drawSubplot(325, timeList, DalvikHeapList, u'时间(秒)', u"Dalvik内存(MB)") timeList = [x * 2 for x in range(len(flowList))] drawSubplot(326, timeList, flowList, u'时间(秒)', u"流量(kb/s)") # plt.gca().yaxis.set_minor_formatter(yticks) plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.55, wspace=0.25) # plt.show() print self.pigName plt.savefig(self.pigName) def run(self): # 根据应用的包名称 获取CPU以及内存占用 self.loghd.info("app_monitor run \n") # self.is_alive = True # 等待获取到被监控app的pid后才开始采集数据 print "waitForAppReady begin" self.waitForAppReady() print "waitForAppReady end" flowProfile = FlowProfiler(self.appPid, self.adb, self.loghd) cpuProfile = CpuProfiler(self.appPid, self.adb, self.loghd) memProfile = MemProfiler(self.appPid, self.adb, self.loghd) flowProfile.init() cpuProfile.init() f = open(self.fileName, "w+") f.write('\xEF\xBB\xBF') f.write(DATA_TITLE) firstRun = True errorTimes = 0 while self.running: try: str_now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) processcpuRatio, cpuRatio, retry = cpuProfile.profile() if retry: time.sleep(float(self.period)) continue PSS, NativeHeap, DalvikHeap = memProfile.profile() flow = flowProfile.profile() write_str = "%s,%s,%s,%s,%s,%s,%s\n" % (str(str_now_time), \ str(processcpuRatio), str(cpuRatio), \ str(PSS), str(NativeHeap), \ str(DalvikHeap), str(flow)) # self.loghd.info(write_str.replace(",", " ")) print write_str.replace(",", " ") # 将数据写入文件 f.write(write_str) f.flush() except Exception, e: errorTimes += 1 if (errorTimes > 5): # 本来想尝试通过看app是否还在来判断,但是发现用例结束后,app仍然在后台运行 self.loghd.info( "monitor app end or process exception: %s" % e) break else: self.loghd.info("monitor app get data failed: %s" % e) self.waitForAppReady() continue time.sleep(float(self.period)) f.close() print u"开始绘图了" self.pic(cpuProfile.processcpuRatioList, cpuProfile.cpuRatioList, memProfile.PSSList, \ memProfile.NativeHeapList, memProfile.DalvikHeapList, flowProfile.flowList) print u"绘图结束了" self.running = False
class logcateThread(threading.Thread): def __init__(self, device, taskId, taskName, testResults, loghd, serial=None): threading.Thread.__init__(self) # self.running = True self.adb = Adb(serial=serial) self.logcatSubProcess = None self.device = device self.taskId = taskId self.taskName = taskName self.testResults = testResults self.appPid = 0 self.loghd = loghd self.is_alive = False def stop(self): # self.running = False try: while self.is_alive and self.getAppPid( ) == self.appPid and self.getAppPid() != 0: self.loghd.info("logcate Thread still alive, wait ...") time.sleep(1) if self.logcatSubProcess.poll() == None: self.logcatSubProcess.terminate() except: pass def getAppPid(self): # self.appPid = self.adb.cmd("shell", "set", "`ps|grep com.duowan.mobile$`;", "echo", "$2").communicate()[0].decode("utf-8").strip() outputs = self.adb.cmd("shell", "top", "-m", "10", "-n", "1").communicate()[0].decode("utf-8").strip() r = "(\\d+).*\\s+%s[^:]" % "com.duowan.mobile" # hardcode 手y m = re.search(r, outputs) # print outputs if m: return m.group(1) else: self.loghd.info("app still not get up") return 0 # 执行用例中途会退出导致logcat抓取不全 # def run(self): # self.loghd.info("logcateThread run \n") # self.is_alive = True # clearLogcat(self.device) # logcatLogfile=open(getLogPath(self.taskId,consts.logcatLogName %(self.taskName),self.device),'w+') # self.logcatSubProcess=subprocess.Popen((consts.logcatCommand %self.device).split(),stdout=logcatLogfile,stderr=logcatLogfile) # while ((not monitor.isTimeout(self.taskId,self.device)) and self.running): # monitor.heart(self.taskId,self.device) # time.sleep(1) # logcatLogfile.close() # self.is_alive = False def run(self): self.loghd.info("logcateThread run \n") self.is_alive = True # 清楚logcat log clearLogcat(self.device) logcatLogfile = open( getLogPath(self.taskId, consts.logcatLogName % (self.taskName), self.device), 'w+') self.appPid = self.getAppPid() # == start logcat ==subprocess.PIPE self.logcatSubProcess = subprocess.Popen( (consts.logcatCommand % self.device).split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) total = 0 finishedIndex = 0 timeInterval = 0.1 # timeoutFlag=False # while ((not monitor.isTimeout(self.taskId,self.device)) and self.running): while (not monitor.isTimeout(self.taskId, self.device)): content = monitor.timeoutTask(self.taskId, self.device, readStdout, self.logcatSubProcess) if not content: time.sleep(timeInterval) continue logcatLogfile.write(content) logcatLogfile.flush() monitor.heart(self.taskId, self.device) if "1 failed" in content: self.testResults[self.taskName] = False # 结束内容出现,则结束当前logcate抓取线程 # if "): finished:" in content: # self.running = False # break # avoid uiauto log filte = re.findall( r"run finished:\s+(\d+)\s+tests.+?(\d+)\s+ignored", content) if len(filte) and filte[0][0] != 3 and filte[0][1] != 0: # self.running = False self.loghd.info("logcat finish.") break # progress report # filte=re.findall(r"run started:\s+(\d+)\s+tests",content) # if filte: # total=int(filte[0]) # # if step==3: # # total+=self.config.getTotal(self.taskId,self.device) # config.setTotal(self.taskId,self.device,total) # if "): finished:" in content: # finishedIndex+=1 # # if step==1: # totalFinishedIndex=finishedIndex # # if step==3: # # totalFinishedIndex=finishedIndex+config.getFinished(self.taskId,self.device) # config.setFinished(self.taskId,self.device,totalFinishedIndex) # progress=int(float(config.getFinished(self.taskId,self.device))/config.getTotal(self.taskId,self.device)*100) # config.setProgress(self.taskId,self.device,progress) # filte=re.findall(r"run finished:\s+(\d+)\s+tests.+?(\d+)\s+ignored",content) self.is_alive = False