Merge pull request #124 from runcommand/61-eval-hook

Use `--hook[=<hook>]` to profile all hooks, or callbacks to spec hook
This commit is contained in:
Daniel Bachhuber 2016-11-14 06:50:41 -08:00 committed by GitHub
commit b18a3eabbb
6 changed files with 93 additions and 37 deletions

View file

@ -144,7 +144,7 @@ will need to execute during the course of the request.
Profile arbitrary code execution. Profile arbitrary code execution.
~~~ ~~~
wp profile eval <php-code> [--fields=<fields>] [--format=<format>] wp profile eval <php-code> [--hook[=<hook>]] [--fields=<fields>] [--format=<format>]
~~~ ~~~
Code execution happens after WordPress has loaded entirely, which means Code execution happens after WordPress has loaded entirely, which means
@ -156,6 +156,9 @@ current theme.
<php-code> <php-code>
The code to execute, as a string. The code to execute, as a string.
[--hook[=<hook>]]
Focus on key metrics for all hooks, or callbacks on a specific hook.
[--fields=<fields>] [--fields=<fields>]
Display one or more fields. Display one or more fields.
@ -177,7 +180,7 @@ current theme.
Profile execution of an arbitrary file. Profile execution of an arbitrary file.
~~~ ~~~
wp profile eval-file <file> [--fields=<fields>] [--format=<format>] wp profile eval-file <file> [--hook[=<hook>]] [--fields=<fields>] [--format=<format>]
~~~ ~~~
File execution happens after WordPress has loaded entirely, which means File execution happens after WordPress has loaded entirely, which means
@ -189,6 +192,9 @@ current theme.
<file> <file>
The path to the PHP file to execute and profile. The path to the PHP file to execute and profile.
[--hook[=<hook>]]
Focus on key metrics for all hooks, or callbacks on a specific hook.
[--fields=<fields>] [--fields=<fields>]
Display one or more fields. Display one or more fields.

View file

@ -53,3 +53,22 @@ Feature: Profile arbitary file execution
Then STDOUT should be a table containing rows: Then STDOUT should be a table containing rows:
| cache_hits | cache_misses | | cache_hits | cache_misses |
| 2 | 0 | | 2 | 0 |
Scenario: Profile a function calling a hook
Given a WP install
And a calls-hook.php file:
"""
<?php
add_filter( 'logout_url', function( $url ) { wp_cache_get( 'foo' ); return $url; });
wp_logout_url();
"""
When I run `wp profile eval-file calls-hook.php --hook --fields=hook,cache_hits,cache_misses`
Then STDOUT should be a table containing rows:
| hook | cache_hits | cache_misses |
| logout_url | 0 | 1 |
When I run `wp profile eval-file calls-hook.php --hook=logout_url --fields=callback,cache_hits,cache_misses`
Then STDOUT should be a table containing rows:
| callback | cache_hits | cache_misses |
| function(){} | 0 | 1 |

View file

@ -35,3 +35,16 @@ Feature: Profile arbitary code execution
Then STDOUT should be a table containing rows: Then STDOUT should be a table containing rows:
| cache_hits | cache_misses | | cache_hits | cache_misses |
| 2 | 0 | | 2 | 0 |
Scenario: Profile a function calling a hook
Given a WP install
When I run `wp profile eval "add_filter( 'logout_url', function( $url ) { wp_cache_get( 'foo' ); return $url; }); wp_logout_url();" --hook --fields=hook,cache_hits,cache_misses`
Then STDOUT should be a table containing rows:
| hook | cache_hits | cache_misses |
| logout_url | 0 | 1 |
When I run `wp profile eval "add_filter( 'logout_url', function( $url ) { wp_cache_get( 'foo' ); return $url; }); wp_logout_url();" --hook=logout_url --fields=callback,cache_hits,cache_misses`
Then STDOUT should be a table containing rows:
| callback | cache_hits | cache_misses |
| function(){} | 0 | 1 |

View file

@ -6,8 +6,8 @@ Feature: Basic profile usage
When I run `wp profile` When I run `wp profile`
Then STDOUT should be: Then STDOUT should be:
""" """
usage: wp profile eval <php-code> [--fields=<fields>] [--format=<format>] usage: wp profile eval <php-code> [--hook[=<hook>]] [--fields=<fields>] [--format=<format>]
or: wp profile eval-file <file> [--fields=<fields>] [--format=<format>] or: wp profile eval-file <file> [--hook[=<hook>]] [--fields=<fields>] [--format=<format>]
or: wp profile hook [<hook>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] or: wp profile hook [<hook>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>]
or: wp profile stage [<stage>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] or: wp profile stage [<stage>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>]

View file

@ -221,6 +221,9 @@ class Command {
* <php-code> * <php-code>
* : The code to execute, as a string. * : The code to execute, as a string.
* *
* [--hook[=<hook>]]
* : Focus on key metrics for all hooks, or callbacks on a specific hook.
*
* [--fields=<fields>] * [--fields=<fields>]
* : Display one or more fields. * : Display one or more fields.
* *
@ -235,31 +238,13 @@ class Command {
* - csv * - csv
* --- * ---
* *
* @when before_wp_load
* @subcommand eval * @subcommand eval
*/ */
public function eval_( $args, $assoc_args ) { public function eval_( $args, $assoc_args ) {
$statement = $args[0];
$profiler = new Profiler( false, false ); self::profile_eval_ish( $assoc_args, function() use ( $statement ) {
$profiler->run(); eval( $statement );
});
$logger = new Logger();
$logger->start();
eval( $args[0] );
$logger->stop();
$fields = array(
'time',
'query_time',
'query_count',
'cache_ratio',
'cache_hits',
'cache_misses',
'request_time',
'request_count',
);
$formatter = new Formatter( $assoc_args, $fields );
$formatter->display_items( array( $logger ), false );
} }
/** /**
@ -274,6 +259,9 @@ class Command {
* <file> * <file>
* : The path to the PHP file to execute and profile. * : The path to the PHP file to execute and profile.
* *
* [--hook[=<hook>]]
* : Focus on key metrics for all hooks, or callbacks on a specific hook.
*
* [--fields=<fields>] * [--fields=<fields>]
* : Display one or more fields. * : Display one or more fields.
* *
@ -288,7 +276,6 @@ class Command {
* - csv * - csv
* --- * ---
* *
* @when before_wp_load
* @subcommand eval-file * @subcommand eval-file
*/ */
public function eval_file( $args, $assoc_args ) { public function eval_file( $args, $assoc_args ) {
@ -298,15 +285,41 @@ class Command {
WP_CLI::error( "'$file' does not exist." ); WP_CLI::error( "'$file' does not exist." );
} }
$profiler = new Profiler( false, false ); self::profile_eval_ish( $assoc_args, function() use ( $file ) {
self::include_file( $file );
});
}
/**
* Profile an eval or eval-file statement.
*/
private static function profile_eval_ish( $assoc_args, $profile_callback ) {
$hook = Utils\get_flag_value( $assoc_args, 'hook' );
$type = $focus = false;
$fields = array();
if ( $hook ) {
$type = 'hook';
if ( true !== $hook ) {
$focus = $hook;
$fields[] = 'callback';
$fields[] = 'location';
} else {
$fields[] = 'hook';
}
}
$profiler = new Profiler( $type, $focus );
$profiler->run(); $profiler->run();
if ( $hook ) {
$logger = new Logger(); $profile_callback();
$logger->start(); $loggers = $profiler->get_loggers();
self::include_file( $file ); } else {
$logger->stop(); $logger = new Logger();
$logger->start();
$fields = array( $profile_callback();
$logger->stop();
$loggers = array( $logger );
}
$fields = array_merge( $fields, array(
'time', 'time',
'query_time', 'query_time',
'query_count', 'query_count',
@ -315,9 +328,9 @@ class Command {
'cache_misses', 'cache_misses',
'request_time', 'request_time',
'request_count', 'request_count',
); ) );
$formatter = new Formatter( $assoc_args, $fields ); $formatter = new Formatter( $assoc_args, $fields );
$formatter->display_items( array( $logger ), false ); $formatter->display_items( $loggers, false );
} }
/** /**

View file

@ -370,6 +370,11 @@ class Profiler {
*/ */
private function load_wordpress_with_template() { private function load_wordpress_with_template() {
// WordPress already ran once.
if ( function_exists( 'add_filter' ) ) {
return;
}
if ( 'stage' === $this->type && true === $this->focus ) { if ( 'stage' === $this->type && true === $this->focus ) {
$hooks = array(); $hooks = array();
foreach( $this->stage_hooks as $stage_hook ) { foreach( $this->stage_hooks as $stage_hook ) {