-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
XhprofCommands.php
164 lines (150 loc) · 5.07 KB
/
XhprofCommands.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<?php
namespace Drush\Commands\core;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\CommandData;
use Drush\Config\DrushConfig;
use Symfony\Component\Console\Input\InputInterface;
use Drush\Commands\DrushCommands;
/**
* Class XhprofCommands
* @package Drush\Commands\core
*
* Supports profiling Drush commands using either XHProf or Tideways XHProf.
*
* Note that XHProf is compatible with PHP 5.6 and PHP 7+, you could also use
* the Tideways XHProf fork. The Tideways XHProf extension recently underwent a
* major refactor; Drush is only compatible with the newer version.
*
* @see https://pecl.php.net/package/xhprof
* @see https://tideways.com/profiler/blog/releasing-new-tideways-xhprof-extension
*/
class XhprofCommands extends DrushCommands
{
const XH_PROFILE_MEMORY = false;
const XH_PROFILE_CPU = false;
const XH_PROFILE_BUILTINS = true;
// @todo Add a command for launching the built-in web server pointing to the HTML site of xhprof.
// @todo Write a topic explaining how to use this.
/**
* @hook option *
*
* @option xh-link URL to your XHProf report site.
*/
public function optionsetXhProf($options = ['xh-link' => self::REQ])
{
}
/**
* Finish profiling and emit a link.
*
* @hook post-command *
*/
public function xhprofPost($result, CommandData $commandData)
{
$config = $this->getConfig();
if (self::xhprofIsEnabled($config)) {
$namespace = 'Drush';
$run_id = self::xhprofFinishRun($namespace);
$url = $config->get('xh.link') . '/index.php?run=' . urlencode($run_id) . '&source=' . urlencode($namespace);
$this->logger()->notice(dt('XHProf run saved. View report at !url', ['!url' => $url]));
}
}
/**
* Enable profiling via XHProf
*
* @hook init *
*/
public function xhprofInitialize(InputInterface $input, AnnotationData $annotationData)
{
$config = $this->getConfig();
if (self::xhprofIsEnabled($config)) {
$flags = self::xhprofFlags($config);
self::xhprofEnable($flags);
}
}
/**
* Determines if any profiler could be enabled.
*
* @param \Drush\Config\DrushConfig $config
*
* @return bool
* TRUE when xh.link configured, FALSE otherwise.
*
* @throws \Exception
* When no available profiler extension enabled.
*/
public static function xhprofIsEnabled(DrushConfig $config)
{
if (!$config->get('xh.link')) {
return false;
}
if (!extension_loaded('xhprof') && !extension_loaded('tideways_xhprof')) {
if (extension_loaded('tideways')) {
throw new \Exception(dt('You are using an older incompatible version of the tideways extension. Please upgrade to the new tideways_xhprof extension.'));
} else {
throw new \Exception(dt('You must enable the xhprof or tideways_xhprof PHP extensions in your CLI PHP in order to profile.'));
}
}
return true;
}
/**
* Determines flags.
*/
public static function xhprofFlags(DrushConfig $config)
{
if (extension_loaded('tideways_xhprof')) {
$map = [
'no-builtins' => TIDEWAYS_XHPROF_FLAGS_NO_BUILTINS,
'cpu' => TIDEWAYS_XHPROF_FLAGS_CPU,
'memory' => TIDEWAYS_XHPROF_FLAGS_MEMORY,
];
} else {
$map = [
'no-builtins' => XHPROF_FLAGS_NO_BUILTINS,
'cpu' => XHPROF_FLAGS_CPU,
'memory' => XHPROF_FLAGS_MEMORY,
];
}
$flags = 0;
if (!$config->get('xh.profile-builtins', !self::XH_PROFILE_BUILTINS)) {
$flags |= $map['no-builtins'];
}
if ($config->get('xh.profile-cpu', self::XH_PROFILE_CPU)) {
$flags |= $map['cpu'];
}
if ($config->get('xh.profile-memory', self::XH_PROFILE_MEMORY)) {
$flags |= $map['memory'];
}
return $flags;
}
/**
* Enable profiling.
*/
public static function xhprofEnable($flags)
{
if (extension_loaded('tideways_xhprof')) {
\tideways_xhprof_enable($flags);
} else {
\xhprof_enable($flags);
}
}
/**
* Disable profiling and save results.
*/
public function xhprofFinishRun($namespace)
{
if (extension_loaded('tideways_xhprof')) {
$data = \tideways_xhprof_disable();
} else {
$data = \xhprof_disable();
if (class_exists('\XHProfRuns_Default')) {
$xhprof_runs = new \XHProfRuns_Default($this->getConfig()->get('xh.path'));
return $xhprof_runs->save_run($data, $namespace);
}
}
$config = $this->getConfig();
$dir = $config->get('xh.path', $config->tmp());
$run_id = uniqid();
file_put_contents($dir . DIRECTORY_SEPARATOR . $run_id . '.' . $namespace . '.xhprof', serialize($data));
return $run_id;
}
}