打造一套客户端功能最全的APM监控系统.pdf
《打造一套客户端功能最全的APM监控系统.pdf》由会员分享,可在线阅读,更多相关《打造一套客户端功能最全的APM监控系统.pdf(330页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、APM 是 Application Perf ormance Monitoring 的缩写,监视和管理软件应用程序的性能和可用性。应用性能管理对一个应用的持续稳定运行至关重要。所以这篇文章就从一个iOS A p p 的性能管理的纬度谈谈如何精确监控以及数据如何上报等技术点A p p 的性能问题是影响用户体验的重要因素之一。性能问题主要包含:Crash,网络请求错误或者超时、U I响应速度慢、主线程卡顿、CPU和内存使用率高、耗电量大等等。大多数的问题原因在于开发者错误地使用了线程锁、系统函数、编程规范问题、数据结构等等。解决问题的关键在于尽早的发现和定位问题。本篇文章着重总结了 A P M 的
2、原因以及如何收集数据。A P M 数据收集后结合数据上报机制,按照一定策略上传数据到服务端。服务端消费这些信息并产出报告。请结合姊妹篇,总结了如何打造一款灵活可配置、功能强大的数据上报组件。一、卡顿监控卡顿问题,就是在主线程上无法响应用户交互的问题。影响着用户的直接体验,所 以 针 对 A p p 的卡顿监控是A P M 里面重要的一环。FPS(f rame per second)每秒钟的帧刷新次数,iPhone手 机 以 6 0 为最佳,iPad某 些 型 号 是 1 2 0,也是作为卡顿监控的一项参考参数,为什么说是参考参数?因为它不准确。先说说怎么获取到FPSo CADisplayLin
3、k是一个系统定时器,会以帧刷新频率一*样的速率来刷新视图。CADisp/agLMk displayUikVJitkTargetself。至于为什么不准我们来看看下面的小例代码_AisplagLi八k=CADisplayLink displayLiiakWitkTargetelfselectOK:selector(p_displayLikkTick:);_displayUik setPaased:YES;匚displagLi八k“ddToR 八Loop:NSR 八Loop c“Ru八LoopfModc:NSRu 八 LoopCoNHAOnModcsJ;代码所示,CADi spl ay Li nk
4、对象是被添加到指定的Ru nLo o p的 某 个 M o d e 下。所 以 还 是 CPU层面的操作,卡顿的体验是整个图像渲染的结果:CPU+GPUo请继续往下看1.屏幕绘制原理讲 讲 老 式 的 CRT显示器的原理。CRT电子枪按照上面方式,从上到下一行行扫描,扫面完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描。为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号。当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(h o ri z o nal sy nch ro ni z at i o n),简称 H
5、Sync;当一帧画面绘制完成后,电子枪恢复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(Vertical synchronization),简 称 VSync。显示器通常以固定的频率进行刷新,这个固定的刷新频率就是VSync信号产生的频率。虽然现在的显示器基本都是液晶显示屏,但是原理保持不变。通常,屏幕上一张画面的显示是由CPU、G PU 和显示器是按照上图的方式协同工作的。C P U 根据工程师写的代码计算好需要现实的内容(比如视图创建、布局计算、图片解码、文本绘制等),然后把计算结果提交到GPU,G P U 负责图层合成、纹理渲染,随 后 G PU 将渲染结果提交到帧缓冲区。随后视
6、频控制器会按 照 VSync信号逐行读取帧缓冲区的数据,经过数模转换传递给显示器显示。在帧缓冲区只有一个的情况下,帧缓冲区的读取和刷新都存在效率问题,为了解决效率问题,显示系统会引入2 个缓冲区,即双缓冲机制。在这种情况下,GPU会预先渲染好一帧放入帧缓冲区,让视频控制器来读取,当下一帧渲染好后,G P U 直接把视频控制器的指针指向第二个缓冲区。提升了效率。目前来看,双缓冲区提高了效率,但是带来了新的问题:当视频控制器还未读取完成时,即屏幕内容显示了部分,GPU将新渲染好的一帧提交到另一个帧缓冲区并把视频控制器的指针指向新的帧缓冲区,视频控制器就会把新的一帧数据的下半段显示到屏幕上,造成画面
7、撕裂的情况。为了解决这个问题,GPU通常有一个机制叫垂直同步信号(V-Sync),当开启垂直同步信号后,GPU会等到视频控制器发送V-Sync信号后,才进行新的一帧的渲染和帧缓冲区的更新。这样的几个机制解决了画面撕裂的情况,也增加了画面流畅度。但需要更多的计算资源答疑可能有些人会看到 当开启垂直同步信号后,GPU会等到视频控制器发送V-Sync信号后,才进行新的一帧的渲染和帧缓冲区的更新这里会想,GPU收到V-Sync才进行新的一帧渲染和帧缓冲区的更新,那是不是双缓冲区就失去意义了?设想一个显示器显示第一帧图像和第二帧图像的过程。首先在双缓冲区的情况下,GPU首先渲染好一帧图像存入到帧缓冲区,
8、然后让视频控制器的指针直接直接这个缓冲区,显示第一帧图像。第一帧图像的内容显示完成后,视频控制器发送V-Sync信号,GPU收 到V-Sync信号后渲染第二帧图像并将视频控制器的指针指向第二个帧缓冲区。看上去第二帧图像是在等第一帧显示后的视频控制器发送V-Sync信号。是吗?真是这样的吗?揭秘。请看下图1.Singlebuffering2.Doublebuffering3.*IHple-bufferingF VideoI memoryBufferVideomemoryBuffer 1Buffier2Videomemory4,Doublebufferingwith frameB delayed5
9、.7Hple-bufferingwith frameB delayedBuffer 1Buffer 2VideomemoryarwAdvertical vertical vertical 1retrace retjace retrace-6wBd(uPWarcdpPQWDdBufferVideomemoryarEdop/Cop/cop/AB当第一次V-S yn c信号到来时,先渲染好一帧图像放到帧缓冲区,但是不展示,当收到第二个V-S yn c信号后读取第一次渲染好的结果(视频控制器的指针指向第一个帧缓冲区),并同时渲染新的一帧图像并将结果存入第二个帧缓冲区,等收到第三个V-S ync信号后,
10、读取第二个帧缓冲区的内容(视频控制器的指针指向第二个帧缓冲区),并开始第三帧图像的渲染并送入第个帧缓冲区,依次不断循环往复。请查看资料,需要梯子:Multiple buffering2.卡顿产生的原因VSync信号到来后,系统图形服务会通过CADisplayLink等机制通知App,A pp主线程开始在C PU 中计算显示内容(视图创建、布局计算、图片解码、文本绘制等)。然后将计算的内容提交到GPU,G PU经过图层的变换、合成、渲染,随 后 GPU把渲染结果提交到帧缓冲区,等待下一次VSync信号到来再显示之前渲染好的结果。在垂直同步机制的情况下,如果在一个VSync时间周期内,CPU或 者
11、 G PU 没有完成内容的提交,就会造成该帧的丢弃,等待下一次机会再显示,这时候屏幕上还是之前渲染的图像,所以这就是CPU、GPU层面界面卡顿的原因。目 前 iO S设备有双缓存机制,也有三缓冲机制,Android现在主流是三缓冲机制,在早期是单缓冲机制。iO S三缓冲机制例子CPU和GPU资源消耗原因很多,比如对象的频繁创建、属性调整、文件读取、视图层级的调整、布 局 的 计 算(AutoLayout视图个数多了就是线性方程求解难度变大)、图片解码(大图的读取优化)、图像绘制、文本渲染、数据库读取(多读还是多写乐观锁、悲观锁的场景)、锁 的 使 用(举例:自旋锁使用不当会浪费CPU)等方面。
12、开发者根据自身经验寻找最优解(这里不是本文重点)。3.A P M 如何监控卡顿并上报CADisplayLink肯定不用了,这 个FPS仅作为参考。一般来讲,卡顿的监测有2种方案:监 听RunLoop状态回调、子 线 程p in g主线程3.1 RunLoop状态监听的方式RunLoop负责监听输入源进行调度处理。比如网络、输入设备、周期性或者延迟事件、异步回调等。RunLoop会接收2种类型的输入源:一种是来自另一个线程或者来自不同应用的异步消息(source。事件)、另一种是来自预定或者重复间隔的事件。RunLoop状态如下图RunLoopSourcel(port)Observ1.通 知 O
13、bserver:即将进入Loop2.通 知 Observer:将要处理TimerI ObservObserv4.处理 SourceO5.如果有Source1,跳到第9步Source6.通 知 Observer:线程即将休眠ObservT im er 7.休眠,等待唤醒外部手动唤醒3.通 知 Observer:将要处理SourceOObserv10.通知Observer:即将退出LoopObservTimerSource8.通 知 Observer:线程刚被唤醒9.处理唤醒时收到的消息,之后跳回2 1 Sourcei第一步:通 知Observers,RunLoop要开始进入lo o p,紧接着进
14、入loopif(curretMode-_obsevcrMask&kCFRu八LoopE八Wg)/通 知 Observers:RtmLoop 即 将 进 入 loop_CFR八curre八tMode,kCFRu八LoopE八trg);/进 入 loopresult=_CFR n LoopRu 八current Mode j seconds,小 仇(mAfte 丫SouKceHandlcd,previousMode);第二步:开 启 do w hile循环保活线程,通 知 Observers,RunLoop触 发 Timer回调、SourceO回调,接着执行被加入的blockif(rli-_obs
15、eKV Ma sk&kCF R 八 Lo o pBefo reT7nAed)/通 知 Observ ed:RcmLo o p即将触发T/m e r回调_ CF R 八 Lo o pDo Obscrv cd CMHkv b k.CF R.u L.oop8eforeTi e if(Hm-_ o feserv erMsk&kCF Ru 八 LoopBefosc S。乂 KCCS)/通知 Observ ers:Rt mLo o p 即将触发 Sourc e 回调_ CF R 八 Lo o pDo Obscrv cH(?L r/m,kCF R 八 Lo o pBeF o%So es);/执彳了被加入的
16、b/o ck_ CF R 八 L0o pDo B/o cks(H,r/m);第三步:RunLoop在触发SourceO回调后,如 果 Sourcel是 ready状态,就会跳转到handle_msg去处理消息。/如 果 有 So u rce(基于p or t)处 于re a d y状态,直接处理这个So u rce工然后跳转去处理消息if(MACH_PORT_NULL!=dispa tc hPoH&!didUispa tc hPortLa stTii e)DEPL。丫 MEN口 ARGE7LMACOSX|DEPLOY MEN匚TARGE匚EMBEDDED|DEPLOY MENTLTARGETL
17、EMBEDDED_ M/MMSg=(Kva c h_ g_hea der_tif(_CFR(A八LoopSeic eMa c hPoH(dispa tc hPort,&sg,sizeof(Msg_b(Affer),&/2ePo rt,Ot&evouc herSta te,NULL)goto ha d(e_ sg;#c狂 DEPLOY MEN口ARGETLWWDOWSif(_CFR.uLoopA/aitFoMultipleObjects(NUL-LJ&dispatchPort,O,O,&:live Port,NULL)(goto kadle_isg;#。八 Aif)第四步:回调触发后,通 知 O
18、bservers即将进入休眠状态Boolean poll=s oe H 八 山c d T ki s L。?|(OUL-L=tii.eout_co.text-terTSR;/通 知Observers:R u八L oop 的 线 程 即 将 进 入 休 眠(s/c c p)i F (。&(r/m-_observe rM ask&kCFRu八LoopBcfo-eWaitMg)_ C F R 八L o0 pD oO bs c rvc K S(”_,r/m,kC F R 八L oopB c fore W川 t/n g);_ C F R 八 L oopS c tS/e e 磔 八g(“);第五步:进入休眠
19、后,会等待mach_port消息,以便再次唤醒。只有以下4 种情况才可以被再次唤醒。基于 port的 source 事件 Tim er时间到 RunLoop 超时被调用者唤醒do if(kCFUseCollectableAllocator)/objc_clear_stack(C);/O,$izeof(isg_buffer);)Msg=(n/ch_FvsgJeWer_t*)ms_f euf f er;_CFR(xnLoopServiceMckPort(witSet,&nASg,sizeof(MSg_buffeC,&/2ePort,poll?O:TIMEOUTJNFIMITY,zvouckerSt
20、ate,&:vouckerCopy);if(kodcQeePort/=MACH_PORT_NULL&(ivePort=iodeQueuePort)/Pram the qaeue.If OM of the callout blocks sets the tiieFiredflag,break out avd service the tiller.while(_dispatch_r(Aialoop_root_queue_perfori._4-CF(d-_queuey);if(3-_母m0用*4)/Leave livePort as the queue port,aid service t/mers
21、 belowrim-tf merFrre=false;break;eke(if(msg&Msg!=(kvach_isg_keaderj:F%e(&sg);)eke(/Go ahead ad(eave the miaer loop.break;while(1);第六步:唤醒时通知Observer,RunLoop的线程刚刚被唤醒了/通 知 Observ ed:Rt mL。?的线程刚 刚 被 唤 醒 了 if(poll&kCF R 八Lo o pAft crW a浙 八g)_ CF R 八Lo o pD0Observ ed(K。Hm,kCFR认八LoopAfterWaiti八g);/处 理 消 息人
22、 八 山 c s g:;_CFRuLoopSettgMreA/al_tim erPo rt !=MACH_PORT_NULL&UvePort=rl-_tikveKPort)CFRUNLOOP_WAKEUP_FORIMER。;/。八 W/八dowSj we have obse rve d av issue where the tiie r port is se tbefore the tiie which we re que ste d it to be se t.For e xample,we set the fire time tobe TSR 16764676586(9,but it is
23、 actually observed firing at TSR 16764676414S,which is 工 7工S ticks e arly.The re sult is that,wk。_CFR,iAn.LoopDoTie rs che cks tose e if any of the run loop time rs should be fiHcg,it appe ars to be too e arly1 for the八ext t/mer,avd.八0 time rs are handle d./八 this case,the%MCK port has be e n automa
24、tically reset(s/Mce itwas returned from MsgWaitFoYModtiple ObjcctsEx),aiad if we do not re-rm it,tkc八八。time rs will e ve r be serviced agaiy unless sokctki八g adjusts the tille r list(e.g.adding ov redos八g t/mers).The fix for the issue,is to reset the t/mer Mere ifCFR.uLoopDoTikve rs did iot handle a
25、 tiMW itse lf.93O87S4if(!_CFR 八LoopD。丁沁c d。r/m,ach_absolute _tiie O),)/Re-arw the next t/merFArmA/extTimeHiMoeCr/m,rf);)#endif/如果有 de spatch 到 mm_ueue 的 block,执行 blocke lse if(live Port=dispatchPort)CFRUZLOOP_WAKEUP_FOR_D/SPATCH0;_CFR.LoopModeUMock(”m);_CFR,unLoopUnlock(rl);_CFSetTSD(_CFTSDKeglsMGCD
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 打造 一套 客户端 功能 APM 监控 系统
限制150内