Tài liệu Advanced PHP Programming- P10 docx

50 319 0
Tài liệu Advanced PHP Programming- P10 docx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 18 Profiling IF YOU PROGRAM PHP PROFESSIONALLY,THERE is little doubt that at some point you will need to improve the performance of an application. If you work on a high-traffic site, this might be a daily or weekly endeavor for you; if your projects are mainly intranet ones, the need may arise less frequently. At some point, though, most applications need to be retuned in order to perform as you want them to. When I’m giving presentations on performance tuning PHP applications, I like to make the distinction between tuning tools and diagnostic techniques. Until now, this book has largely focused on tuning tools: caching methodologies, system-level tunings, database query optimization, and improved algorithm design. I like to think of these techniques as elements of a toolbox, like a hammer, a torque wrench, or a screwdriver are elements of a handyman’s toolbox. Just as you can’t change a tire with a hammer, you can’t address a database issue by improving a set of regular expressions.Without a good toolset, it’s impossible to fix problems; without the ability to apply the right tool to the job, the tools are equally worthless. In automobile maintenance, choosing the right tool is a combination of experience and diagnostic insight. Even simple problems benefit from diagnostic techniques. If I have a flat tire, I may be able to patch it, but I need to know where to apply the patch. More complex problems require deeper diagnostics. If my acceleration is sluggish, I could simply guess at the problem and swap out engine parts until performance is acceptable.That method is costly in both time and materials. A much better solution is to run an engine diagnostic test to determine the malfunctioning part. Software applications are in general much more complex than a car’s engine, yet I often see even experienced developers choosing to make “educated” guesses about the location of performance deficiencies. In spring 2003 the php.net Web sites experienced some extreme slowdowns. Inspection of the Apache Web server logs quickly indicated that the search pages were to blame for the slowdown. However, instead of profiling to find the specific source of the slowdown within those pages, random guessing was used Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 430 Chapter 18 Profiling to try to solve the issue.The result was that a problem that should have had a one-hour fix dragged on for days as “solutions” were implemented but did nothing to address the core problem. Thinking that you can spot the critical inefficiency in a large application by intuition alone is almost always pure hubris. Much as I would not trust a mechanic who claims to know what is wrong with my car without running diagnostic tests or a doctor who claims to know the source of my illness without performing tests, I am inherently skepti- cal of any programmer who claims to know the source of an application slowdown but does not profile the code. What Is Needed in a PHP Profiler A profiler needs to satisfy certain requirements to be acceptable for use: n Transparency—Enabling the profiler should not require any code change. Having to change your application to accommodate a profiler is both highly inconvenient (and thus prone to being ignored) and intrinsically dishonest because it would by definition alter the control flow of the script. n Minimal overhead—A profiler needs to impose minimal execution overhead on your scripts. Ideally, the engine should run with no slowdown when a script is not being profiled and almost no slowdown when profiling is enabled.A high over- head means that the profiler cannot be run for production debugging, and it is a large source of internal bias (for example, you need to make sure the profiler is not measuring itself). n Ease of use—This probably goes without saying, but the profiler output needs to be easy to understand. Preferably there should be multiple output formats that you can review offline at your leisure.Tuning often involves a long cycle of introspec- tion and code change. Being able to review old profiles and keep them for later cross-comparison is essential. A Smorgasbord of Profilers As with most features of PHP, a few choices are available for script profilers: n Userspace profilers—An interesting yet fundamentally flawed category of profil- er is the userspace profilers.This is a profiler written in PHP.These profilers are interesting because it is always neat to see utilities for working with PHP written in PHP itself. Unfortunately, userspace profilers are heavily flawed because they require code change (every function call to be profiled needs to be modified to hook the profiler calls), and because the profiler code is PHP, there is a heavy bias generated from the profiler running. I can’t recommend userspace profilers for any operations except timing specific functions on a live application where you cannot install an extension-based profiler. Benchmark_Profiler is an example of a Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 431 Installing and Using APD userspace profiler in PEAR, and is available at http://pear.php.net/package/ Benchmark. n Advanced PHP Debugger (APD)—APD was developed by Daniel Cowgill and me. APD is a PHP extension-based profiler that overrides the execution calls in the Zend Engine to provide high-accuracy timings. Naturally, I am a little biased in its favor, but I think that APD provides the most robust and configurable profiling capabilities of any of the candidates. It creates trace files that are machine readable so they can be postprocessed in a number of different ways. It also pro- vides user-level hooks for output formatting so that you can send profiling results to the browser, to XML, or using any format you wanted. It also provides a step- ping, interactive debugger, which us not covered here. APD is available from PEAR’s PECL repository at http://pecl.php.net/apd. n DBG—DBG is a Zend extension-based debugger and profiler that is available both in a free version and as a commercial product bundled with the commercial PHPEd code editor. DBG has good debugger support but lacks the robust profil- ing support of APD. DBG is available at http://dd.cron.ru/dbg. n Xdebug—Xdebug is a Zend extension-based profiler debugger written by Derick Rethans. Xdebug is currently the best debugger of the three extension-based solu- tions, featuring multiple debugger interfaces and a robust feature set. Its profiling capabilities are still behind APD’s, however, especially in the ability to reprocess an existing trace in multiple ways. Xdebug is available from http://xdebug.org. The rest of this chapter focuses on using APD to profile scripts. If you are attached to another profiler (and by all means, you should always try out all the options), you should be able to apply these lessons to any of the other profilers.The strategies covered here are independent of any particular profiler; only the output examples differ from one pro- filer to another. Installing and Using APD APD is part of PECL and can thus be installed with the PEAR installer: # pear install apd After ADP is installed, you should enable it by setting the following in your php.ini file: zend_extension=/path/to/apd.so apd.dumpdir=/tmp/traces APD works by dumping trace files that can be postprocessed with the bundled pprofp trace-processing tool.These traces are dumped into apd.dumpdir, under the name pprof.pid, where pid is the process ID of the process that dumped the trace. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 432 Chapter 18 Profiling To cause a script to be traced, you simply need to call this when you want tracing to start (usually at the top of the script): apd_set_pprof_trace(); APD works by logging the following events while a script runs: n When a function is entered. n When a function is exited. n When a file is included or required. Also, whenever a function return is registered,APD checkpoints a set of internal coun- ters and notes how much they have advanced since the previous checkpoint.Three counters are tracked: n Real Time (a.k.a. wall-clock time)—The actual amount of real time passed. n User Time—The amount of time spent executing user code on the CPU. n System Time—The amount of time spent in operating system kernel-level calls. Accuracy of Internal Timers APD’s profiling is only as accurate as the systems-level resource measurement tools it has available to it. On FreeBSD, all three of the counters are measured with microsecond accuracy. On Linux (at least as of version 2.4), the User Time and System Time counters are only accurate to the centisecond. After a trace file has been generated, you analyze it with the pprofp script. pprofp implements a number of sorting and display options that allow you to look at a script’s behavior in a number of different ways through a single trace file. Here is the list of options to pprofp: pprofp <flags> <trace file> Sort options -a Sort by alphabetic names of subroutines. -l Sort by number of calls to subroutines -r Sort by real time spent in subroutines. -R Sort by real time spent in subroutines (inclusive of child calls). -s Sort by system time spent in subroutines. -S Sort by system time spent in subroutines (inclusive of child calls). -u Sort by user time spent in subroutines. -U Sort by user time spent in subroutines (inclusive of child calls). -v Sort by average amount of time spent in subroutines. -z Sort by user+system time spent in subroutines. (default) Display options -c Display Real time elapsed alongside call tree. -i Suppress reporting for php built-in functions Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 433 A Tracing Example -m Display file/line locations in traces. -O <cnt>Specifies maximum number of subroutines to display. (default 15) -t Display compressed call tree. -T Display uncompressed call tree. Of particular interest are the -t and -T options, which allow you to display a call tree for the script and the entire field of sort options. As indicated, the sort options allow for functions to be sorted either based on the time spent in that function exclusively (that is, not including any time spent in any child function calls) or on time spent, inclusive of function calls. In general, sorting on real elapsed time (using -r and -R) is most useful because it is the amount of time a visitor to the page actually experiences.This measurement includes time spent idling in database access calls waiting for responses and time spent in any other blocking operations.Although identifying these bottlenecks is useful, you might also want to evaluate the performance of your raw code without counting time spent in input/output (I/O) waiting. For this, the -z and -Z options are useful because they sort only on time spent on the CPU. A Tracing Example To see exactly what APD generates, you can run it on the following simple script: <?php apd_set_pprof_trace(); hello(“George”); goodbye(“George”); function hello($name) { echo “Hello $name\n”; sleep(1); } function goodbye($name) { echo “Goodbye $name\n”; } ?> Figure 18.1 shows the results of running this profiling with -r.The results are not sur- prising of course: sleep(1); takes roughly 1 second to complete. (Actually slightly longer than 1 second, this inaccuracy is typical of the sleep function in many languages; you should use usleep() if you need finer-grain accuracy.) hello() and goodbye() are both quite fast. All the functions were executed a single time, and the total script execu- tion time was 1.0214 seconds. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 434 Chapter 18 Profiling Figure 18.1 Profiling results for a simple script. To generate a full call tree, you can run pprofp with the -Tcm options.This generates a full call tree, with cumulative times and file/line locations for each function call. Figure 18.2 shows the output from running this script. Note that in the call tree, sleep is indented because it is a child call of hello(). Figure 18.2 A full call tree for a simple script. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 435 Profiling a Larger Application Profiling a Larger Application Now that you understand the basics of using APD, let’s employ it on a larger project. Serendipity is open-source Web log software written entirely in PHP.Although it is most commonly used for private individuals’Web logs, Serendipity was designed with large, multiuser environments in mind, and it supports an unlimited number of authors. In this sense, Serendipity is an ideal starting point for a community-based Web site to offer Web logs to its users. As far as features go, Serendipity is ready for that sort of high- volume environment, but the code should first be audited to make sure it will be able to scale well. A profiler is perfect for this sort of analysis. One of the great things about profiling tools is that they give you easy insight into any code base, even one you might be unfamiliar with. By identifying bottlenecks and pinpointing their locations in code, APD allows you to quickly focus your attention on trouble spots. A good place to start is profiling the front page of the Web log.To do this, the index.php file is changed to a dump trace. Because the Web log is live, you do not gen- erate a slew of trace files by profiling every page hit, so you can wrap the profile call to make sure it is called only if you manually pass PROFILE=1 on the URL line: <?php if($_GET[‘PROFILE’] == 1) { apd_set_pprof_trace(); } /* regular serendipity code starts here */ Figure 18.3 shows the profile results for the Serendipity index page, sorted by inclusive real times (using -R). I prefer to start my profiling efforts with -R because it helps give me a good idea which macro-level functions in an application are slow. Because the inclusive timing includes all child calls as well,“top-level” functions tend to be promi- nent in the listing. The total time for this page was 0.1231 seconds, which isn’t bad if you are running your own personal site, but it might be too slow if you are trying to implement Serendipity for a large user base or a high-traffic site. include_once() is the top-ranked time-consumer, which is not uncommon in larger applications where a significant por- tion of the logic is implemented in include files. Note, though, that include_once() not only dominates the inclusive listing, but it seems to dominate the exclusive listing as well. Figure 18.4 verifies this: Rerunning the profile with pprofp -r shows that include_once() takes 29.7% of the runtime, without counting any child function calls. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 436 Chapter 18 Profiling Figure 18.3 Initial profiling results for the Serendipity index page. Figure 18.4 An exclusive call summary for the Serendipity index page. What you are seeing here is the cost of compiling all the Serendipity includes. Remember the discussion of compiler caches in Chapter 9,“External Performance Tunings,” that one of the major costs associated with executing PHP scripts is the time spent parsing and compiling them into intermediate code. Because include files are all parsed and compiled at runtime, you can directly see this cost in the example shown in Figure 18.4.You can immediately optimize away this overhead by using a compiler cache. Figure 18.5 shows the effect of installing APC and rerunning the profiles. include_once() is still at the top of inclusive times (which is normal because it includes a large amount of the page logic), but its exclusive time has dropped completely out of the top five calls.Also, script execution time has almost been cut in half. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 437 Profiling a Larger Application Figure 18.5 A Serendipity index profile running with an APC compiler cache. If you look at the calls that remain, you can see that these are the three biggest offenders: n serendipity_plugin_api::generate_plugins n serendipity_db_query n mysql_db_query You might expect database queries to be slow. Database accesses are commonly the bot- tleneck in many applications. Spotting and tuning slow SQL queries is covered in Chapter 12,“Interacting with Databases,” so this chapter does not go into detail about that. As predicted earlier, the high real-time cost of the database queries is matched with no user and system time costs because the time that is spent in these queries is exclusive- ly spent on waiting for a response from the database server. The generate_plugins() function is a different story. Serendipity allows custom user plug-ins for side navigation bar items and comes with a few bundled examples, including a calendar, referrer tracking, and archive search plug-ins. It seems unnecessary for this plug-in generation to be so expensive. To investigate further, you can generate a complete call tree with this: > pprofp -tcm /tmp/pprof.28986 Figure 18.6 shows a segment of the call tree that is focused on the beginning of the first call to serendipity_plugin_api::generate_plugins().The first 20 lines or so show what seems to be normal lead-up work. A database query is run (via serendipity_db_query()), and some string formatting is performed. About midway down the page, in the serendipity_drawcalendar() function, the trace starts to look Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. [...]... for code written in PHP. With more than 2,000 internal functions in PHP s standard library, it is not hard to imagine failing to find base64_encode() when you are looking for a built-in hex-encoding function n The code base was huge—With nearly a million lines of PHP code, the application code base was so large that a manual inspection of all the code was impossible.Worse still, with PHP lacking a hexencode()... when written in PHP When I was testing APD, I discovered to my dismay that these two functions consumed almost 30% of the execution time of every page on the site.The problem was that the user cookies were not small—they were about 1KB on average—and looping through an array of that size, appending to a string, is extremely slow in PHP Because the functions were relatively optimal from a PHP perspective,... profiling tools in PHP. The individual profilers mentioned in this chapter all have some information on their respective Web sites but there is no comprehensive discussion on the art of profiling In addition to PHP- level profilers, there are a plethora of lower-level profilers you can use to profile a system.These tools are extremely useful if you are trying to improve the performance of the PHP language... and providing accessors for getting summary information on the results To start, you need to install the Benchmark libraries Prior to PHP 4.3, the Benchmark class suite was packaged with PHP After version 4.3, you need to either download the classes from http://pear .php. net or use the PEAR installer for a one-step installation: # pear install Benchmark To benchmark the performance of the function foo()... looking at what happened with parse_url between PHP 4.2.3 and 4.3.0 parse_url is a built-in function that takes a URL and breaks it into its primitive components: service type, URI, query string, and so on Prior to PHP 4.3.0 a number of bug reports said that the parse_url function’s performance was abysmally poor For perspective, you can roll back the clocks to PHP 4.2.3 and benchmark parse_url against a... preg_match, which is smart enough to cache the compiled regular expression in case it wants to use it later In PHP 4.3.0, the parse_url function was fixed not by adding caching to the regular expression but by hand-coding a URL parser Here is the same code as before, executed under PHP 4.3.0 PHP 4.3.0 preg_parse_url parse_url System + User Time: 0.000210 System + User Time: 0.000150 The built-in function... releases of the language Nor does this happen only on major releases —the open-source development model behind PHP means that many problems are addressed when they itch someone enough to need scratching.These are just two examples of code patterns that reversed themselves: In every version of PHP until version 4.3, interpolated variables in strings were much slower than concatenating strings (Refer to... question “Is it relevant?” Benchmarking can be a useful exercise in and of itself to help familiarize you with the nuances of PHP and the Zend Engine Although it might not be useful to optimize array iteration in a seldomused script, having a general knowledge of the performance idioms of PHP can help you develop a coding style that needs less optimization down the road n n Benchmarking Basics When comparing... reset on every request and used to ensure that the session was still valid This code had been in use for three years and was authored in the days of PHP3 , when non-binary-safe data (for example, data containing nulls) was not correctly handled in the PHP cookie handling code—and before rawurlencode() was binary safe The functions looked something like this: function hexencode($data) { $ascii = unpack(“C*”,... iterations, and report the average runtime: require ‘Benchmark/Iterate .php ; $benchmark = new Benchmark_Iterate; $benchmark->run(1000, foo); $result = $benchmark->get(); print “Mean execution time for foo: $result[mean]\n”; A simple example of this is to use the suite to compare the speed of the built-in function max() with the PHP userspace implementation my_max().This is a simple example of how iterating . available at http://pear .php. net/package/ Benchmark. n Advanced PHP Debugger (APD)—APD was developed by Daniel Cowgill and me. APD is a PHP extension-based. profiler written in PHP. These profilers are interesting because it is always neat to see utilities for working with PHP written in PHP itself. Unfortunately,

Ngày đăng: 26/01/2014, 09:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan