应用程序以查找诊断和加速运行缓慢的代码.docx
- 文档编号:29960306
- 上传时间:2023-08-03
- 格式:DOCX
- 页数:12
- 大小:23.24KB
应用程序以查找诊断和加速运行缓慢的代码.docx
《应用程序以查找诊断和加速运行缓慢的代码.docx》由会员分享,可在线阅读,更多相关《应用程序以查找诊断和加速运行缓慢的代码.docx(12页珍藏版)》请在冰豆网上搜索。
应用程序以查找诊断和加速运行缓慢的代码
PHP应用程序以查找、诊断和加速运行缓慢的代码
用Xdebug分析PHP应用程序以查找、诊断和加速运行缓慢的代码2011-06-2114:
26From:
如果PHP应用程序运行缓慢,可以使用分析器找出应用程序究竟在哪些方面浪费了时间。
可以将语句、循环、函数、类或者是运行缓慢的库作为分析目标。
如果不是时间而是内存使用出现了问题,那么一个优秀的分析器还可以显示组件的内存占用情况。
"为PHP应用提速、提速、再提速!
"系列文章的第1部分演示了如何使用XCache(PHP操作码缓存)加速整个站点。
XCache(仅是少数几种缓存包中的一种)保留了编译过程的输出,去掉了其他冗余的工作。
只要页面没有发生变化,缓存后的页面就能够胜任代理的作用。
当页面发生变化时,缓存后的页面就会变为无效并被替换掉。
操作码缓存--以及一个操作码优化器,通常由相同的包提供--是一种加快站点响应的低成本技术。
很多缓存包是免费的,并且是开源的,无需改变任何代码即可从中受益。
当然,在某些应用程序中,相比较实际的执行时间,将PHP源代码文件翻译为其相应的操作码所需的时间微不足道。
连接到远程数据库服务器,使用低效的SQL语句进行查询,以及其他大量解析和操作数据的工作都非常的繁琐,也因此增加了开销,甚至产生浪费。
良好的网络设计和灵巧的数据库结构可以使时间冗长和查询缓慢的情况有所改善,如果需要的话还可以向友好的专家请求帮助。
但是,如果代码运行缓慢,您可能更希望自己处理。
但是从何开始呢?
正如人们普遍认为的,在代码完成前调试代码的做法很不明智--因为代码的首次实现可能会非常的迅速。
当代码正确且能实现相应的功能时,不管其表面上看起来运行缓慢还是实际如此,首先要做的就是对其性能进行测试或基准测试。
不执行这样的诊断而尝试去优化代码无疑是在黑暗中摸索。
一个简单的性能指标是挂钟时间(wallclocktime),或测量页面请求与完成呈现之间的实际延迟。
对于某些情况--比如在您自己的工作站本地运行的Web服务器、数据库和浏览器--挂钟时间能够提供信息。
然而,挂钟时间对于其他大多数情况而言并无实际意义,比如网络延迟时间、活动的Web服务器或者活动的数据库。
一种更精确的测量--甚至可以测量运行单个源代码语句的时间--可以采用代码分析器。
分析器通常被实现为PHP运行时引擎的扩展,记录语句开始和结束的delta、记录程序开始和结束之间的delta并捕获对来到的请求形成响应的总时间。
有了这种垂直度,就可以将语句、循环、函数、类或者是运行缓慢的库作为分析目标。
如果不是时间而是内存使用出现了问题,那么一个优秀的分析器还可以显示组件的内存占用情况。
PHP的一个较流行的分析器是Xdebug,它还为交互地调试PHP应用程序提供了服务器挂钩(hook)。
(参见"调试的更好方法"以了解更多信息。
该系列的另一部分将探讨高级交互式调试。
)Xdebug很容易从源代码构建,将其作为Zend扩展进行安装也非常简单。
(现在已有针对某些平台的二进制文件。
)当就绪后,对基于PHP页面的每个请求都将生成可在KCacheGrind中查看的数据集。
如果具备了PHP实用工具phpize和php-config,而且具有对系统的php.ini配置文件的访问权,那么安装和设置Xdebug只需几分钟的时间。
下面给出的指导说明针对Linux,不过在MacOSX上的安装步骤实际上与此类似。
(您可以从XdebugWeb站点找到针对MicrosoftWindows的Xdebug预编译版本。
)
Xdebug的最新版本为V2.0.0RC3(最终版本V2.0.0在您阅读此文时也许已经可用)。
下载并解包tarball,然后切换到源代码的子目录。
确保phpize和php-config位于shell的PATH,准备使用phpize进行构建。
$wgettarxzfxdebug-2.0.0RC3.tgz
$cdxdebug-2.0.0RC3/xdebug-2.0.0RC3
$phpizeConfiguringfor:
PHPApiVersion:
20020918ZendModuleApiNo:
20020429ZendExtensionApiNo:
20050606phpize的产品是一个脚本--名为配置--它对余下的构建过程进行配置。
要构建Xdebug,在make后紧接着输入./configure即可。
$./configurecheckingbuildsystemtype.i686-apple-darwin8.8.1checkinghostsystemtype.i686-apple-darwin8.8.1checkingforegrep.grep-E
.
$make
.
Buildcomplete.
(Itissafetoignorewarningsabouttempnamandtmpnam).
make命令生成Xdebug扩展,xdebug.so。
剩下的工作就是使用sudomakeinstall进行安装。
$sudomakeinstallInstallingsharedextensions:
/usr/lib/php/extensions/no-debug-non-zts-20020429/
注:
如果在终端窗口中运行最后一个命令,请选择并复制最后一步中发出的目录。
在下一个步骤中将会用到它。
最后,要使配置数据可视化,必须使用KCacheGrind和GraphViz。
包含KDesktopEnvironment(KDE)的Linux发行版很可能已经含有了KCacheGrind和GraphViz。
如果没有包含,适合您所使用的Linux的那些版本也不难找到。
Debian用户可以使用AdvancedPackagingTool(APT)快速安装KCacheGrind和GraphViz以及所有包的依赖关系。
$apt-cachesearchkcachegrindvalgrind-callgrind-call-graphskinforvalgrindkcachegrind-visualisationtoolforvalgrindprofilingoutputkcachegrind-converters-formatconvertersforKCachegrindprofilingvisualisationtool
$apt-cachesearchgraphvizgraphviz-richsetofgraphdrawingtoolsgraphviz-dev-graphvizLibsandHeadersagainstwhichtobuildapplicationsgraphviz-doc-additionaldocumentationforgraphvizlibdeps-renderer-dot-perl-DEPSrendererpluginusingGraphViz/dot
.
$sudoapt-getinstallkcachegrindgraphviz
.
如果没有将KDE安装到系统中,KCacheGrind、GraphViz以及所有必要的内容将占用大约90MB的磁盘空间。
安装了Xdebug扩展后,就可以准备启用和配置该扩展了。
在文本编辑器中打开php.ini,并添加以下代码行。
zend_extension=/usr/lib/php/extensions/no-debug-non-zts-20020429/xdebug.soxdebug.profiler_output_dir="/tmp/xdebug/"
xdebug.profiler_enable=Offxdebug.profiler_enable_trigger=1
第一行zend_extension加载Xdebug扩展。
第二行命名放置分析器输出的目录。
如果需要的话,创建命名的目标并更改其模式以允许用户对Web服务器进行写访问。
第三行禁用了分析器。
然而,第四行将在设置HTTPGET或POST参数XDEBUG_PROFILE时启用分析器。
(如果您希望一直使用分析器,在第三行代码中将Off更改为On。
)
添加这几行代码并验证了输出目录是可写的,然后重新启动Web服务器。
对于其他PHP扩展,要验证Xdebug是否安装并可用,可以创建一个简单的骨架PHP程序来调用phpinfo()并查看结果。
应该能够看到类似于图1所示的内容。
(为简便起见,省略了完整输出的部分内容。
)
图1.Phpinfo指明Xdebug是否已安装
您还可以向下滚动到Zend徽标。
如果正确安装并配置了Xdebug,它将显示在徽标的旁边。
要分析代码,只需将浏览器指向PHP应用程序即可。
如果您将分析器设置为对每个触发逐个解决的方式,将XDEBUG_PROFILE=1追加到URL中,或者,像下面一样,将参数嵌入到表单中。
作为一个示例,我们来分析一下这个简单的ACMEFibonacciMaker,fibonacci.php,如清单5所示。
为方便起见,将XDEBUG_PROFILE参数设置在表单的隐藏变量内。
(当代码投入生产时,很可能将禁用Xdebug,呈现这个变量将不会造成什么损失。
)
?
phpfunctionfib($nth=1){
if($nth2){
return($nth);
}
return(fib($nth-1)+fib($nth-2));
}
?
htmlheadtitleACMEFibonacciMaker/title
/headbodyh2TrytheACMEFibonacciMaker!
/h2formaction="fibonacci.php"method="POST"
inputtype="hidden"name="XDEBUG_PROFILE"value="1"/
Enteranumber:
inputtype="text"name="n"/input
/formhr/
?
phpif(!
empty($_REQUEST['n'])){
$n=$_REQUEST['n']%10;
$suffix=array(1="st",2="nd",3="rd");
if($_REQUEST['n']4||$_REQUEST['n']20){
$suffix=$suffix[$n];
}
else{
$suffix='th';
}
echo'pThe'.$_REQUEST['n'].$suffix.'Fibonaccinumberis';
echofib($_REQUEST['n']).'/p';
}
?
/body
/html
将浏览器指向(或者合适的URL)并输入数字--比如,16。
其结果--Fibonacci系列的第16个元素--如图2所示。
图2.示例Fibonacci应用程序
如果将分析器输出目录中的内容(名为php.ini)列出来的话,应该能看到类似cachegrind.out.951917687这样名称的文件。
cachegrind.out.前缀是固定的。
默认情况下,数值后缀是目录路径到fibonacci.php文件的CRC32散列。
因此,如果每一个应用程序都位于自己的目录,那么每个程序的输出将根据文件名而被分隔。
(如果您更喜欢将输出与时间相关联,将下面这行代码:
xdebug.profiler_output_name=timestamp
添加到php.ini。
)
从终端窗口启动KCacheGrind并打开cachegrind.out.951917687。
将立即打开一个类似于图3的新窗口。
图3.KCacheGrind应用程序
单击Callees选项卡,双击源代码中突出显示的行,并从Grouping列表选择SourceFile。
所看到的视图应变为类似图4所示的内容。
图4.查看结果
正如您预期的一样,实际上全部的处理时间(70,989毫秒的99.87%)都花费在3193次对fib()函数的调用上了。
要加快该应用程序(随着进一步执行Fibonacci序列,程序会随之变慢),应该避免重新计算Fibonacci数字这样代价高昂的重复工作。
事实上,ACMEFibonacciMaker能够很好地进行计算重用。
下面展示了fib()函数的优化版本。
新的版本用内存换来了时间上的节省,因为它保留了中间的计算以便以后使用。
图5展示了分析结果:
与上次的3192次函数调用相比,这里仅需要30次调用(并且只有一半的调用需要计算结果),而时间则减少为只有20毫秒。
functionfib($nth=1){
static$fibs=array();
if(!
empty($fibs[$nth])){
return($fibs[$nth]);
}
if($nth2){
$fibs[$nth]=$nth;
}
else{
$fibs[$nth-1]=fib($nth-1);
$fibs[$nth-2]=fib($nth-2);
$fibs[$nth]=$fibs[$nth-1]+$fibs[$nth-2];
}
return($fibs[$nth]);
}
?
图5.加快了的Fibonacci函数
虽然单次运行应用程序能够指出一些问题(可以试试上面原始的应用程序中的Fibonacci序列的第50个元素),通常,还是需要通过几次调用收集统计信息以及查看模式。
如果保留默认的"crc32"命名模式,每次运行fibonacci.php时,将重写数据文件。
然而,可以通过在php.ini中设置xdebug.profiler_append=1改变这种行为并将后续运行追加到相同的文件。
更改之后重新启动Web服务器。
图6显示了三次运行FibonacciMaker之后数据合计的示例。
总时间稍大于两秒;其中99.97%的时间花费在了fib()上。
图6显示了CallGraph选项卡,它由GraphViz的dot工具生成。
关于KCacheGrind的具体用法不在本文讨论的范围之内,但是可以从网上获得其完整的文档。
KCacheGrind可以以很多种方法对数据进行交叉分析,根据您希望解决的问题选择合适的方法。
图6.合计分析数据
除了分析PHP应用程序,还可以在发生错误并进行交互式调试时,配置Xdebug扩展(如其名字暗示的一样)来提供详细的栈跟踪和错误消息。
栈跟踪和错误消息可以指出错误的原因,而交互式调试允许每次逐步调试代码中的一条指令,查看程序变量的类型和值,并检查所有的PHP超全局变量,包括进来的请求参数。
本系列的下一篇文章将具体介绍交互式调试。
同时,您可以启用几个Xdebug特性来说明应用程序在发生错误时的状态:
无论何时只要应用程序出现错误,设置xdebug.default_enable=On显示栈跟踪。
如果您已经花费时间安装了Xdebug,那么只要进行代码开发就启用这个特性。
还可以设置xdebug.show_local_vars=1来进一步显示最顶部范围内的所有变量。
xdebug.var_display_max_children、xdebug.var_display_max_data和xdebug.var_display_max_depth是相关的三个设置,分别用来控制因xdebug.show_local_vars的使用而显示的变量的属性数、字符串长度和嵌套深度。
可以在XdebugWeb站点找到更多信息。
如果没有具体的代码,那么很难演示具有意义的分析,下面这个示例是十分典型的代码,展示了从中所能获得的信息。
清单7显示了一个装配玩具火箭的应用程序(人为设计)。
这种玩具火箭由几个部分组成,生产每一个部分都需要一定的时间。
在PHP中,使用类代表每个组成部分,使用实例方法表示每个部分的构造时间。
您可以将这个玩具看作是一个应用程序,并把每个部分看作是该应用程序的功能。
?
phpdefine('BOOSTER',5);
define('CAPSULE',2);
define('MINUTE',60);
define('STAGE',3);
define('PRODUCTION',1000);
classPart{
functionPart(){
$this-build(MINUTE);
}
functionbuild($delay=0){
if($delay=0)
return;
while($delay--0){
}
}
}
classCapsuleextendsPart{
functionCapsule(){
parent:
Part();
$this-build(CAPSULE*MINUTE);
}
}
classBoosterextendsPart{
functionBooster(){
parent:
Part();
$this-build(BOOSTER*MINUTE);
}
}
classStageextendsPart{
functionStage(){
parent:
Part();
$this-build(STAGE*MINUTE);
}
}
classSpaceShip{
var$booster;
var$capsule;
var$stages;
functionSpaceShip($numberStages=3){
$this-booster=newBooster();
$this-capsule=newCapsule();
$this-stages=array();
while($numberStages--=0){
$stages[$numberStages]=newStage();
}
}
}
$toys=array();
$count=PRODUCTION;
while($count--=0){
$toys=newSpaceShip
(2);
}
?
htmlheadtitleToyFactoryOutput
/title
/headbodyh1ToyProduction/h1pBuilt?
echoPRODUCTION.'toys'?
/p
/body
/html
运行这些代码将生成一个新的数据文件。
同样,将数据加载到KCacheGrind。
如果切换到Source和CallGraph选项卡,将看到类似图7所示的视图。
图7.太空船应用程序的配置文件
FlatProfile窗格(左面)显示了应用程序调用的所有函数(方法)。
最左面的列展示了近似的累计总数,第二列展示了每种方法的单独测试,第三列列出了调用该方法的次数。
在调用图表中使用有颜色的方块反映图表内容,这非常方便,能够很容易地将事件序列与其花费的时间关联起来。
很明显,构建阶段所使用的时间代价最昂贵。
构建每一部分所需的系统开销(使用Part的构造器表示)次之。
再看一下PHP自身的define()函数,它只花费了很少的开销。
最后,还可以查看内存的使用情况。
从靠近顶部的下拉菜单中选择Memory和Class,然后切换到顶部以及底部的Types和CallerMap选项卡。
您看到的屏幕应该类似图8。
图8.太空船应用程序的内存使用情况
和其他众多PHP扩展一样,Xdebug容易构建、安装快捷且易于配置--所有这些工作10分钟内即可完成。
如果您已经优化了Apache安装并且对应用程序进行了缓存,但是性能仍然很差,那么可以考虑一下代码的运行。
算法是否有效?
代码是否过于复杂?
是否重复实现了PHP已提供的函数?
当然,如果不能判断出应用程序的瓶颈所在,那么就必须进行查找并加以修复。
不要只凭猜测--要进行分析!
您可能会惊讶于宝贵的计算周期是如何被轻意耗费掉的。
并且永远不要忘记:
要在生产服务器中禁用Xdebug,因为启用它总会增加系统开销。
学习
您可以参阅本文在developerWorks全球站点上的英文原文。
查看本系列完整的文章列表。
查看developerWorks的"。
"PHP.net是面向PHP开发人员的资源网站。
浏览developerWorks上的所有和PHP教程。
要学习关于PHP的更多内容,请访问IBMdeveloperWorks的PHP项目资源中心。
要收听针对软件开发人员的有趣访谈和讨论,请查看developerWorkspodcasts。
随时关注developerWorks的技术活动和网络广播。
查看最近将在全球范围举办的面向IBM开放源码开发人员的研讨会、商业展览、网络广播和其他活动。
访问developerWorksOpensource专区以获得大量的how-to信息、工具和项目更新,帮助您使用开源技术进行开发并与IBM产品结合使用。
访问SafariBooksOnline获得开源技术的大量参考资料。
获得产品和技术
下载Xdebug软件。
使用IBM试用软件改进您的下一个开源开发项目,这些软件可下载或从DVD获得。
讨论
通过参与developerWorksblog加入developerWorks社区。
参与developerWorksPHPDeveloper论坛。
MartinStreicher是LinuxMagazine的主编。
他从普度大学获得了计算机科学硕士学位,从1982年开始用Pascal、C、Perl、Java和(最近)Ruby编程语言编写类UNIX的系统。
特别声明:
1:
资料来源于互联网,版权归属原作者
2:
资料内容属于网络意见,与本账号立场无关
3:
如有侵权,请告知,立即删除。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 应用程序 查找 诊断 加速 运行 缓慢 代码