3 namespace Drush\Commands\core;
5 use Consolidation\AnnotatedCommand\AnnotationData;
6 use Consolidation\AnnotatedCommand\CommandData;
8 use Symfony\Component\Console\Input\InputInterface;
9 use Drush\Commands\DrushCommands;
12 * Class XhprofCommands
13 * @package Drush\Commands\core
15 * Supports profiling Drush commands using either XHProf or Tideways XHProf.
17 * Note that XHProf is only compatible with PHP 5.6. For PHP 7+, you must use
18 * the Tideways XHProf fork. The Tideways XHProf extension recently underwent a
19 * major refactor; Drush is only compatible with the newer version.
20 * @see https://tideways.com/profiler/blog/releasing-new-tideways-xhprof-extension
22 * @todo Remove support for XHProf extension once PHP 5.6 is EOL.
24 class XhprofCommands extends DrushCommands
27 const XH_PROFILE_MEMORY = false;
28 const XH_PROFILE_CPU = false;
29 const XH_PROFILE_BUILTINS = true;
32 // @todo Add a command for launching the built-in web server pointing to the HTML site of xhprof.
33 // @todo Write a topic explaining how to use this.
38 * @option xh-link URL to your XHProf report site.
40 public function optionsetXhProf($options = ['xh-link' => self::REQ])
45 * Enable profiling via XHProf
47 * @hook post-command *
49 public function xhprofPost($result, CommandData $commandData)
51 if (self::xhprofIsEnabled()) {
53 $run_id = self::xhprofFinishRun($namespace);
54 $url = Drush::config()->get('xh.link') . '/index.php?run=' . urlencode($run_id) . '&source=' . urlencode($namespace);
55 $this->logger()->notice(dt('XHProf run saved. View report at !url', ['!url' => $url]));
60 * Enable profiling via XHProf
64 public function xhprofInitialize(InputInterface $input, AnnotationData $annotationData)
66 if (self::xhprofIsEnabled()) {
67 $config = Drush::config()->get('xh');
68 $flags = self::xhprofFlags($config);
69 self::xhprofEnable($flags);
73 public static function xhprofIsEnabled()
75 if (Drush::config()->get('xh.link')) {
76 if (!extension_loaded('xhprof') && !extension_loaded('tideways_xhprof')) {
77 if (extension_loaded('tideways')) {
78 throw new \Exception(dt('You are using an older incompatible version of the tideways extension. Please upgrade to the new tideways_xhprof extension.'));
80 throw new \Exception(dt('You must enable the xhprof or tideways_xhprof PHP extensions in your CLI PHP in order to profile.'));
91 * TODO: Make these work for Tideways as well.
93 public static function xhprofFlags(array $config)
96 if (!(isset($config['profile-builtins']) ? $config['profile-builtins']: self::XH_PROFILE_BUILTINS)) {
97 $flags |= XHPROF_FLAGS_NO_BUILTINS;
99 if (isset($config['profile-cpu']) ? $config['profile-cpu'] : self::XH_PROFILE_CPU) {
100 $flags |= XHPROF_FLAGS_CPU;
102 if (isset($config['profile-memory']) ? $config['profile-memory'] : self::XH_PROFILE_MEMORY) {
103 $flags |= XHPROF_FLAGS_MEMORY;
111 public static function xhprofEnable($flags)
113 if (extension_loaded('tideways_xhprof')) {
114 \tideways_xhprof_enable(TIDEWAYS_XHPROF_FLAGS_MEMORY | TIDEWAYS_XHPROF_FLAGS_CPU);
116 \xhprof_enable($flags);
121 * Disable profiling and save results.
123 public function xhprofFinishRun($namespace)
125 if (extension_loaded('tideways_xhprof')) {
126 $data = \tideways_xhprof_disable();
127 $dir = $this->getConfig()->tmp();
129 file_put_contents($dir . DIRECTORY_SEPARATOR . $run_id . '.' . $namespace . '.xhprof', serialize($data));
132 $xhprof_data = \xhprof_disable();
133 $xhprof_runs = new \XHProfRuns_Default();
134 return $xhprof_runs->save_run($xhprof_data, $namespace);