<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>devel.kostdoktorn.se &#187; performance</title>
	<atom:link href="http://devel.kostdoktorn.se/category/performance/feed" rel="self" type="application/rss+xml" />
	<link>http://devel.kostdoktorn.se</link>
	<description>Wordpress odds and ends</description>
	<lastBuildDate>Thu, 17 Feb 2011 15:33:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Plugin for simpler performance profiling</title>
		<link>http://devel.kostdoktorn.se/wp-profile-plugin</link>
		<comments>http://devel.kostdoktorn.se/wp-profile-plugin#comments</comments>
		<pubDate>Sat, 24 Oct 2009 18:22:51 +0000</pubDate>
		<dc:creator>Johan Eenfeldt</dc:creator>
				<category><![CDATA[performance]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://devel.kostdoktorn.se/?p=44</guid>
		<description><![CDATA[The two areas where performance problems with WordPress plugins are most common are custom filters/actions and database queries. WP-Profile is a plugin that helps you find such problems. Actions and filters WordPress has an intricate system of actions and filters which is used all over the place: to convert : ) into , to make [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_45" class="wp-caption alignright" style="width: 260px"><img class="size-full wp-image-45 " title="Filters vs the rest" src="http://devel.kostdoktorn.se/wp-content/uploads/2009/10/profiling-filters1.gif" alt="Filters vs the rest" width="250" height="264" /><p class="wp-caption-text">How time is spent on a compex page</p></div>
<p>The two areas where performance problems with WordPress plugins are most common are custom filters/actions and database queries. WP-Profile is a plugin that helps you find such problems.</p>
<h3>Actions and filters</h3>
<p>WordPress has an intricate system of <a href="http://codex.wordpress.org/Plugin_API/Action_Reference">actions</a> and <a href="http://codex.wordpress.org/Plugin_API/Filter_Reference">filters</a> which is used all over the place: to convert : ) into <img src='http://devel.kostdoktorn.se/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> , to make links clickable and to handle the login procedure are just some examples.</p>
<p>Every action and filter is a hook that allows plugins to call custom functions and easily change or override default behavior. That is very useful.</p>
<p>It also makes it easy to really ruin performance as some common filters are called a hundred times or more for more complex pages, making small inefficiencies add up really quickly.<span id="more-44"></span></p>
<p>Unfortunately there are no good ways to keep track of the performance impact of individual filters. It is possible to profile the whole system using for example <a href="http://xdebug.org/">XDebug</a> and *Cachegrind like I did in an <a href="http://devel.kostdoktorn.se/profiling-wordpress-performance-regression">earlier post</a> but it is a lot of work and often overkill during plugin development.</p>
<h3>Database queries</h3>
<p>Database queries in stock WordPress are highly optimized. So much so that they usually only takes a few percent of total time. It is, however, very easy to change this and even seemingly simple queries can take surprisingly long time. By defining SAVEQUERIES in wp-config.php WordPress will record all queries and how long they took to execute in <code>$wpdb-&gt;queries</code>.</p>
<h3>WP-Profile</h3>
<p>WP-Profile is a small plugin I&#8217;ve written to use when developing plugins and modifying WordPress. It keeps track of all calls to actions/filters and presents it in an accessible fashion together with  query information collected through SAVEQUERIES. <strong>It requires that you are comfortable making minor changes to core WordPress files</strong> to set up. It is for testing only. You can <a href="http://devel.kostdoktorn.se/wp-content/uploads/wp-profile.0.1.zip">download it here</a>.</p>
<p>This is the result on stock WordPress for a rather complex page with a lot of comments. Sort tables by clicking on table header (thanks to <a href="http://tablesorter.com/">JQuery TableSorter</a>):</p>
<link rel='stylesheet' id='wp-profile-css'  href='http://devel.kostdoktorn.se/wp-content/plugins/wp-profile/css/style.css' type='text/css' media='all' />
<script type='text/javascript' src='http://devel.kostdoktorn.se/wp-includes/js/jquery/jquery.js?ver=1.3.2'></script><br />
<script type='text/javascript' src='http://devel.kostdoktorn.se/wp-content/plugins/wp-profile/js/jquery.tablesorter.min.js'></script></p>
<div class="profile"><script type="text/javascript"> jQuery(document).ready(function(){ jQuery("#profile_table").tablesorter(); }); </script><br />
<table id="profile_table" class="tablesorter">
<thead>
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Calls</th>
<th scope=col>Function</th>
<th scope=col>Actions / Filters</th>
</tr>
</thead>
<tbody>
<tr>
<td>0.042</td>
<td>12.3%</td>
<td>246</td>
<td>wptexturize</td>
<td>
<table class="profile-inner">
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Calls</th>
<th scope=col>Action / Filter</th>
</tr>
<tbody>
<tr>
<td>0.022</td>
<td>6.3%</td>
<td>1</td>
<td>the_content</td>
</tr>
<tr>
<td>0.008</td>
<td>2.2%</td>
<td>115</td>
<td>the_title</td>
</tr>
<tr>
<td>0.007</td>
<td>2.1%</td>
<td>37</td>
<td>comment_text</td>
</tr>
<tr>
<td>0.005</td>
<td>1.4%</td>
<td>79</td>
<td>list_cats</td>
</tr>
<tr>
<td><0.001</td>
<td>0.3%</td>
<td>14</td>
<td>bloginfo, link_name, link_description</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>0.023</td>
<td>6.5%</td>
<td>38</td>
<td>wpautop</td>
<td>
<table class="profile-inner">
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Calls</th>
<th scope=col>Action / Filter</th>
</tr>
<tbody>
<tr>
<td>0.013</td>
<td>3.7%</td>
<td>1</td>
<td>the_content</td>
</tr>
<tr>
<td>0.01</td>
<td>2.9%</td>
<td>37</td>
<td>comment_text</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>0.017</td>
<td>4.9%</td>
<td>38</td>
<td>convert_smilies</td>
<td>
<table class="profile-inner">
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Calls</th>
<th scope=col>Action / Filter</th>
</tr>
<tbody>
<tr>
<td>0.009</td>
<td>2.6%</td>
<td>1</td>
<td>the_content</td>
</tr>
<tr>
<td>0.008</td>
<td>2.3%</td>
<td>37</td>
<td>comment_text</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>0.01</td>
<td>3%</td>
<td>167</td>
<td>convert_chars</td>
<td>
<table class="profile-inner">
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Calls</th>
<th scope=col>Action / Filter</th>
</tr>
<tbody>
<tr>
<td>0.004</td>
<td>1.2%</td>
<td>115</td>
<td>the_title</td>
</tr>
<tr>
<td>0.003</td>
<td>0.8%</td>
<td>37</td>
<td>comment_text</td>
</tr>
<tr>
<td>0.003</td>
<td>0.8%</td>
<td>1</td>
<td>the_content</td>
</tr>
<tr>
<td><0.001</td>
<td>0.1%</td>
<td>14</td>
<td>link_name, link_description, bloginfo</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>0.007</td>
<td>2%</td>
<td>1</td>
<td>do_shortcode</td>
<td>the_content</td>
</tr>
<tr>
<td>0.007</td>
<td>2%</td>
<td>37</td>
<td>make_clickable</td>
<td>comment_text</td>
</tr>
<tr>
<td>0.006</td>
<td>1.8%</td>
<td>1</td>
<td>WP_Embed :: run_shortcode</td>
<td>the_content</td>
</tr>
<tr>
<td>0.004</td>
<td>1.2%</td>
<td>1</td>
<td>wp_cron</td>
<td>sanitize_comment_cookies</td>
</tr>
<tr>
<td>0.002</td>
<td>0.7%</td>
<td>1</td>
<td>wp_widgets_init</td>
<td>init</td>
</tr>
<tr>
<td>0.002</td>
<td>0.6%</td>
<td>1</td>
<td>profile_enqueue_requirements</td>
<td>init</td>
</tr>
<tr>
<td>0.002</td>
<td>0.5%</td>
<td>10</td>
<td>wp_filter_kses</td>
<td>
<table class="profile-inner">
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Calls</th>
<th scope=col>Action / Filter</th>
</tr>
<tbody>
<tr>
<td>0.001</td>
<td>0.3%</td>
<td>5</td>
<td>link_description</td>
</tr>
<tr>
<td>0.001</td>
<td>0.3%</td>
<td>5</td>
<td>link_name</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>0.002</td>
<td>0.5%</td>
<td>1</td>
<td>WP_Widget_Factory :: _register_widgets</td>
<td>widgets_init</td>
</tr>
<tr>
<td>0.001</td>
<td>0.4%</td>
<td>37</td>
<td>force_balance_tags</td>
<td>comment_text</td>
</tr>
<tr>
<td>0.001</td>
<td>0.4%</td>
<td>204</td>
<td>_config_wp_home</td>
<td>option_home</td>
</tr>
<tr>
<td>0.001</td>
<td>0.4%</td>
<td>1</td>
<td>wp_default_scripts</td>
<td>wp_default_scripts</td>
</tr>
<tr>
<td>0.001</td>
<td>0.2%</td>
<td>1</td>
<td>wp_print_head_scripts</td>
<td>wp_head</td>
</tr>
<tr>
<td>0.001</td>
<td>0.2%</td>
<td>1</td>
<td>feed_links_extra</td>
<td>wp_head</td>
</tr>
<tr>
<td>0.001</td>
<td>0.2%</td>
<td>37</td>
<td>kb_filter_avatar</td>
<td>get_avatar</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>0.135s</th>
<th>39.2%</th>
<th>1071</th>
</tr>
</tfoot>
</table>
<p><script type="text/javascript"> jQuery(document).ready(function(){ jQuery("#profile_db_table").tablesorter(); }); </script><br />
<table id="profile_db_table" class="tablesorter">
<thead>
<tr>
<th scope=col>Time (seconds)</th>
<th scope=col>% of Total</th>
<th scope=col>Function</th>
<th scope=col>Query</th>
</tr>
</thead>
<tbody>
<tr>
<td>0.002</td>
<td>0.6%</td>
<td>comments_template</td>
<td>SELECT * FROM wp_comments WHERE comment_post_ID = 144 AND (comment_approved = &#8217;1&#8242; OR ( user_id = 111 AND comment_approved = &#8217;0&#8242; ) )  ORDER BY comment_date_gmt</td>
</tr>
<tr>
<td>0.001</td>
<td>0.4%</td>
<td>get_pages</td>
<td>SELECT * FROM wp_posts  WHERE (post_type = &#8216;page&#8217; AND post_status = &#8216;publish&#8217;)     ORDER BY menu_order, post_title ASC</td>
</tr>
<tr>
<td>0.001</td>
<td>0.4%</td>
<td>update_meta_cache</td>
<td>SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (144)</td>
</tr>
<tr>
<td>0.001</td>
<td>0.2%</td>
<td>_fill_user</td>
<td>SELECT meta_key, meta_value FROM wp_usermeta WHERE user_id = 111</td>
</tr>
<tr>
<td>0.001</td>
<td>0.2%</td>
<td>get_bookmarks</td>
<td>SELECT *  , IF (DATE_ADD(link_updated, INTERVAL 120 MINUTE) >= NOW(), 1,0) as recently_updated   FROM wp_links  INNER JOIN wp_term_relationships AS tr ON (wp_links.link_id = tr.object_id) INNER JOIN wp_term_taxonomy as tt ON tt.term_taxonomy_id = tr.term_taxonomy_id WHERE 1=1 AND link_visible = &#8216;Y&#8217;  AND ( tt.term_id = 2 ) AND taxonomy = &#8216;link_category&#8217;    ORDER BY link_name ASC</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>0.01s</th>
<th>2.9%</th>
</tr>
</tfoot>
</table>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://devel.kostdoktorn.se/wp-profile-plugin/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Fix Performance Regression</title>
		<link>http://devel.kostdoktorn.se/fix-performance-regression</link>
		<comments>http://devel.kostdoktorn.se/fix-performance-regression#comments</comments>
		<pubDate>Tue, 20 Oct 2009 19:45:16 +0000</pubDate>
		<dc:creator>Johan Eenfeldt</dc:creator>
				<category><![CDATA[performance]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://devel.kostdoktorn.se/?p=38</guid>
		<description><![CDATA[A simple tool to benchmark web performance is Apachebench &#8212; which comes bundled with the Apache web server. To understand how a system as a whole performs you&#8217;ll need something more advanced but to just test how long it takes a page to load it works fine. The graph above[1] expands on where I started [...]]]></description>
			<content:encoded><![CDATA[<p><img class="aligncenter size-full wp-image-40" title="Pageload regression fixes" src="http://devel.kostdoktorn.se/wp-content/uploads/2009/10/pageload-fixes.gif" alt="Pageload regression fixes" width="529" height="465" /></p>
<p>A simple tool to benchmark web performance is <a href="http://httpd.apache.org/docs/2.0/programs/ab.html">Apachebench</a> &#8212; which comes bundled with the Apache web server. To understand how a system as a whole performs you&#8217;ll need something more advanced but to just test how long it takes a page to load it works fine.</p>
<p>The graph above[<a href="http://devel.kostdoktorn.se/fix-performance-regression#note-1">1</a>] expands on where I started <a href="http://devel.kostdoktorn.se/profiling-wordpress-performance-regression">profiling the WordPress regression</a>. I&#8217;ve added the full 10 post frontpage and a single larger page &#8212; with rather lousy performance &#8212; and the work so far to remedy it which looks alot better.<span id="more-38"></span></p>
<p>Most of the performance back in just a handful of patches:</p>
<ul>
<li><a href="http://core.trac.wordpress.org/ticket/10972">#10972</a>: no need to sanitize a post more than once (merged in <a href="http://core.trac.wordpress.org/changeset/12062">12062</a>)</li>
<li><a href="http://core.trac.wordpress.org/ticket/10971">#10971</a>: translation performance when doing nothing (similar patch merged in <a href="http://core.trac.wordpress.org/changeset/12080">12080</a>)</li>
<li><a href="http://core.trac.wordpress.org/ticket/10987">#10987</a>: improve <code>wptexturize()</code> performance (merged in <a href="http://core.trac.wordpress.org/changeset/12084">12084</a>)</li>
</ul>
<p>Still on list of suspects: <code>wp_filter_kses()</code> (though <a href="http://core.trac.wordpress.org/ticket/10751">#10751</a>), <code>wp_widget_init()</code></p>
<p><strong>[<a name="note-1"></a>1]</strong> Numbers are total page load time average of 100 single threaded connections with a clean WordPress install, time is in milliseconds.</p>
]]></content:encoded>
			<wfw:commentRss>http://devel.kostdoktorn.se/fix-performance-regression/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Profiling WordPress Performance Regression</title>
		<link>http://devel.kostdoktorn.se/profiling-wordpress-performance-regression</link>
		<comments>http://devel.kostdoktorn.se/profiling-wordpress-performance-regression#comments</comments>
		<pubDate>Sun, 18 Oct 2009 02:05:54 +0000</pubDate>
		<dc:creator>Johan Eenfeldt</dc:creator>
				<category><![CDATA[performance]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://devel.kostdoktorn.se/?p=27</guid>
		<description><![CDATA[I&#8217;ve been benchmarking stock WordPress today to get performance numbers for the Cache Translation Object plugin. As I had things set up for it I also tested  the latest major releases &#8211; unmodified, clean installations &#8211; and found a 40% regression when going from 2.7 to 2.8. Update: what I measure here is basically the [...]]]></description>
			<content:encoded><![CDATA[<p><img class="aligncenter size-full wp-image-28" title="Pageload regression" src="http://devel.kostdoktorn.se/wp-content/uploads/2009/10/pageload-regression.gif" alt="Pageload regression" width="529" height="261" /></p>
<p>I&#8217;ve been benchmarking stock WordPress today to get performance numbers for the <a href="http://devel.kostdoktorn.se/cache-translation-object">Cache Translation Object</a> plugin. As I had things set up for it I also tested  the latest major releases &#8211; unmodified, clean installations &#8211; and found a <strong>40% regression</strong> when going from 2.7 to 2.8.</p>
<p><strong>Update:</strong> what I measure here is basically the clean startup time, which doesn&#8217;t say what the final effect will be on your site with a real theme, plugins and, you know, actual content.</p>
<p>There is often a battle between features, complexity and performance. This unfortunately natural tendency prevalent among programmers should however not result in such a drastic regression.</p>
<p><strong>Update 2:</strong> More on this <a href="http://devel.kostdoktorn.se/fix-performance-regression">here</a>.</p>
<p><span id="more-27"></span></p>
<h3>Profiling Performance Regressions</h3>
<p>There are <strong>a lot</strong> of changes in any major release of  a project the size of WordPress so finding the actual culprits in these cases are not always easy &#8212; though in this case some of it turned out to be surprisingly simple.</p>
<p>One way to find performance problems is to <a href="http://codex.wordpress.org/Testing_WordPress_Performance">profile</a> the two versions and compare. Here you can see lists of the cumulatively most expensive functions with 2.7 to the left and 2.8 to the right:</p>
<div id="attachment_34" class="wp-caption aligncenter" style="width: 561px"><img class="size-full wp-image-34" title="WordPress 2.7 vs 2.8 Profile" src="http://devel.kostdoktorn.se/wp-content/uploads/2009/10/profile-27-vs-28.gif" alt="WordPress 2.7 vs 2.8 Profile" width="551" height="413" /><p class="wp-caption-text">WordPress 2.7 vs 2.8 Profile</p></div>
<p>I&#8217;ve marked some interesting parts in the 2.8 profile. What you want to look for are functions that takes proportionally longer to execute and figure out why. <a href="http://kcachegrind.sourceforge.net/html/Home.html">KCachegrind</a> (or WinCachegrind) gives many helpful views of call-chains and such things.</p>
<p>In this case the yellow-marked functions are calling the red-marked translation functions which suddenly consumes major resources. Doing nothing, it should be noted as the stock install doesn&#8217;t need anything translated.</p>
<h3>A victim of Abstraction</h3>
<p>So the first, and largest, culprit turns out to be this piece of code:</p>
<pre>function &amp;get_translations_for_domain( $domain ) {
	global $l10n;
	$empty = &amp;new Translations;
	if ( isset($l10n[$domain]) )
		return $l10n[$domain];
	else
		return $empty;
}</pre>
<p><img class="alignright size-full wp-image-36" title="Pageload regression fix1" src="http://devel.kostdoktorn.se/wp-content/uploads/2009/10/pageload-regression-fix1.gif" alt="Pageload regression fix1" width="293" height="226" />Not setting up and calling an calling an empty Translations object <strong>increases performance again by 17%</strong>.</p>
<p>The rest of the regression seems to be mostly caused by changes in <code>sanitize_post()</code>, wp_widgets_init and <code>sanitize_bookmark_field(),</code> which I&#8217;ll look at next &#8212; tomorrow.</p>
<p>Anyone testing WordPress performance?</p>
<p><strong>Update:</strong> With two patches we get back half of the lost performance.</p>
<p><strong>Update 2:</strong> More on this <a href="../fix-performance-regression">here</a> as noted above.</p>
]]></content:encoded>
			<wfw:commentRss>http://devel.kostdoktorn.se/profiling-wordpress-performance-regression/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The WordPress Localization Performance Battle</title>
		<link>http://devel.kostdoktorn.se/the-wordpress-localization-performance-battle</link>
		<comments>http://devel.kostdoktorn.se/the-wordpress-localization-performance-battle#comments</comments>
		<pubDate>Fri, 16 Oct 2009 11:22:27 +0000</pubDate>
		<dc:creator>Johan Eenfeldt</dc:creator>
				<category><![CDATA[performance]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://devel.kostdoktorn.se/?p=19</guid>
		<description><![CDATA[Using WordPress translated to your own language results in a surprisingly large performance cost. In my tests it took twice (or four times!) as long for an unmodified WordPress 2.8.4 start page to load when using a localized WordPress. Translating a lot of text in an user friendly fashion is hard to do efficiently. But [...]]]></description>
			<content:encoded><![CDATA[<p><img class="aligncenter size-full wp-image-20" title="graph-1-284" src="http://devel.kostdoktorn.se/wp-content/uploads/2009/10/graph-1-284.gif" alt="graph-1-284" width="528" height="274" /></p>
<p>Using WordPress translated to your own language results in a surprisingly large performance cost. In my tests it took twice (or four times!) as long for an unmodified WordPress 2.8.4 start page to load when using a localized WordPress.</p>
<p>Translating a lot of text in an user friendly fashion <strong>is</strong> hard to do efficiently.</p>
<p>But there are things we can do to make it a lot less painful.<span id="more-19"></span> Most of the time is actually spent when WordPress reads the MO files containing all text to translate and structures it into the l10n object to prepare for the translations to come. On each page load.</p>
<p>The obvious solution is to cache the resulting object. <a href="http://devel.kostdoktorn.se/cache-translation-object">So I did</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://devel.kostdoktorn.se/the-wordpress-localization-performance-battle/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

