[wp-trac] [WordPress Trac] #21320: Speed up WP_Object_Cache::_exists()

WordPress Trac wp-trac at lists.automattic.com
Fri Jul 20 04:26:59 UTC 2012


#21320: Speed up WP_Object_Cache::_exists()
-------------------------+---------------------
 Reporter:  nacin        |       Owner:  nacin
     Type:  enhancement  |      Status:  closed
 Priority:  normal       |   Milestone:  3.5
Component:  Cache        |     Version:  3.4
 Severity:  normal       |  Resolution:  fixed
 Keywords:               |
-------------------------+---------------------

Old description:

> Both kurtpayne and I have noticed that the _exists() method is way slower
> than it should be. It only contains three PHP functions: isset(),
> is_array(), and array_key_exists(). Yet frequently, I see 5-10% of a
> pageload spent in cache.php, and somewhere around 30-40% of that spent in
> _exists() (so > 2% overall).
>
> In this one example, _exists() was called 2507 times, so every little bit
> counts. 2295 of them came from get(), 212 from add(). It is therefore
> quite obvious that we rely heavily on our local cache.
>
> Based on that assumption, we can make some changes to speed up this
> conditional:
> {{{
> isset( $this->cache[$group] ) && is_array( $this->cache[$group] ) &&
> array_key_exists( $key, $this->cache[$group] );
> }}}
>
> First, the is_array() can go. Never would the $group key exist with the
> value of anything other than an array, and cache.php makes this
> assumption elsewhere.
>
> isset() is mighty fast for a language construct, while arrays in PHP are
> generally slow. The next step would be to remove array_key_exists(), but
> we need to do so without regressing #20004.
>
> So, we can pre-empty array_key_exists() with an isset() check first. If
> the key is set (and not null), then we can return true immediately.
> Otherwise, we call array_key_exists() to see if the key is actually null.
>
> Technically slower for null or not-at-all-set keys, but faster when the
> key is set. And it is only slower by a simple isset(), which is fast.
>
> End result:
> {{{
> isset( $this->cache[ $group ] )
>     && ( isset( $this->cache[ $group ][ $key ] )
>         || array_key_exists( $key, $this->cache[ $group ] ) );
> }}}
>
> array_key_exists() went from being called all 2500 times, to only 192
> times, and the time cost of _exists() goes from 93ms to 9ms. Total time
> spent in cache.php falls by a third.

New description:

 Both kurtpayne and I have noticed that the _exists() method is way slower
 than it should be. It only contains three PHP functions: isset(),
 is_array(), and array_key_exists(). Yet frequently, I see 5-10% of a
 pageload spent in cache.php, and somewhere around 30-40% of that spent in
 _exists() (so > 2% overall).

 In this one example, _exists() was called 2507 times, so every little bit
 counts. 2295 of them came from get(), 212 from add(). It is therefore
 quite obvious that we rely heavily on our local cache.

 Based on that assumption, we can make some changes to speed up this
 conditional:
 {{{
 isset( $this->cache[$group] ) && is_array( $this->cache[$group] ) &&
 array_key_exists( $key, $this->cache[$group] );
 }}}

 First, the is_array() can go. Never would the $group key exist with the
 value of anything other than an array, and cache.php makes this assumption
 elsewhere.

 isset() is mighty fast for a language construct, while arrays in PHP are
 generally slow. The next step would be to remove array_key_exists(), but
 we need to do so without regressing #20004.

 So, we can pre-empty array_key_exists() with an isset() check first. If
 the key is set (and not null), then we can return true immediately.
 Otherwise, we call array_key_exists() to see if the key is actually null.

 Technically slower for null or not-at-all-set keys, but faster when the
 key is set. And it is only slower by a simple isset(), which is fast.

 End result:
 {{{
 isset( $this->cache[ $group ] )
     && ( isset( $this->cache[ $group ][ $key ] )
         || array_key_exists( $key, $this->cache[ $group ] ) );
 }}}

 array_key_exists() went from being called all 2500 times, to only 192
 times, and the time cost of _exists() drops to 10% of what it was. (Time
 cost 97000 to 9300.) Total time spent in cache.php falls by a third.

--

Comment (by nacin):

 Worth noting that I shouldn't have used an absolute unit in [21285] —
 profiling obviously slows down a page (the page does *not* take 4.5
 seconds to compute normally), so these numbers are, of course, only good
 for relative comparisons.

-- 
Ticket URL: <http://core.trac.wordpress.org/ticket/21320#comment:2>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list