Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php
13409 views
1
<?php
2
3
/**
4
* @phutil-external-symbol function xhprof_enable
5
* @phutil-external-symbol function xhprof_disable
6
*/
7
final class DarkConsoleXHProfPluginAPI extends Phobject {
8
9
private static $profilerStarted;
10
private static $profilerRunning;
11
private static $profileFilePHID;
12
13
public static function isProfilerAvailable() {
14
return extension_loaded('xhprof');
15
}
16
17
public static function getProfilerHeader() {
18
return 'X-Phabricator-Profiler';
19
}
20
21
public static function isProfilerRequested() {
22
if (!empty($_REQUEST['__profile__'])) {
23
return $_REQUEST['__profile__'];
24
}
25
26
$header = AphrontRequest::getHTTPHeader(self::getProfilerHeader());
27
if ($header) {
28
return $header;
29
}
30
31
return false;
32
}
33
34
private static function shouldStartProfiler() {
35
if (self::isProfilerRequested()) {
36
return true;
37
}
38
39
static $sample_request = null;
40
41
if ($sample_request === null) {
42
if (PhabricatorEnv::getEnvConfig('debug.profile-rate')) {
43
$rate = PhabricatorEnv::getEnvConfig('debug.profile-rate');
44
if (mt_rand(1, $rate) == 1) {
45
$sample_request = true;
46
} else {
47
$sample_request = false;
48
}
49
}
50
}
51
52
return $sample_request;
53
}
54
55
public static function isProfilerStarted() {
56
return self::$profilerStarted;
57
}
58
59
private static function isProfilerRunning() {
60
return self::$profilerRunning;
61
}
62
63
public static function includeXHProfLib() {
64
// TODO: this is incredibly stupid, but we may not have Phutil metamodule
65
// stuff loaded yet so we can't just phutil_get_library_root() our way
66
// to victory.
67
$root = __FILE__;
68
for ($ii = 0; $ii < 6; $ii++) {
69
$root = dirname($root);
70
}
71
72
require_once $root.'/externals/xhprof/xhprof_lib.php';
73
}
74
75
76
public static function saveProfilerSample(PhutilDeferredLog $access_log) {
77
$file_phid = self::getProfileFilePHID();
78
if (!$file_phid) {
79
return;
80
}
81
82
if (self::isProfilerRequested()) {
83
$sample_rate = 0;
84
} else {
85
$sample_rate = PhabricatorEnv::getEnvConfig('debug.profile-rate');
86
}
87
88
$profile_sample = id(new PhabricatorXHProfSample())
89
->setFilePHID($file_phid)
90
->setSampleRate($sample_rate)
91
->setUsTotal($access_log->getData('T'))
92
->setHostname($access_log->getData('h'))
93
->setRequestPath($access_log->getData('U'))
94
->setController($access_log->getData('C'))
95
->setUserPHID($access_log->getData('P'));
96
97
AphrontWriteGuard::allowDangerousUnguardedWrites(true);
98
$caught = null;
99
try {
100
$profile_sample->save();
101
} catch (Exception $ex) {
102
$caught = $ex;
103
}
104
AphrontWriteGuard::allowDangerousUnguardedWrites(false);
105
106
if ($caught) {
107
throw $caught;
108
}
109
}
110
111
public static function hookProfiler() {
112
if (!self::shouldStartProfiler()) {
113
return;
114
}
115
116
if (!self::isProfilerAvailable()) {
117
return;
118
}
119
120
if (self::$profilerStarted) {
121
return;
122
}
123
124
self::startProfiler();
125
}
126
127
128
/**
129
* @phutil-external-symbol class PhabricatorStartup
130
*/
131
private static function startProfiler() {
132
PhabricatorStartup::beginStartupPhase('profiler.init');
133
134
self::includeXHProfLib();
135
xhprof_enable();
136
137
self::$profilerStarted = true;
138
self::$profilerRunning = true;
139
}
140
141
142
/**
143
* @phutil-external-symbol class PhabricatorStartup
144
*/
145
public static function getProfileFilePHID() {
146
if (!self::isProfilerRunning()) {
147
return;
148
}
149
150
PhabricatorStartup::beginStartupPhase('profiler.stop');
151
self::stopProfiler();
152
PhabricatorStartup::beginStartupPhase('profiler.done');
153
154
return self::$profileFilePHID;
155
}
156
157
private static function stopProfiler() {
158
159
$data = xhprof_disable();
160
$data = @json_encode($data);
161
self::$profilerRunning = false;
162
163
// Since these happen on GET we can't do guarded writes. These also
164
// sometimes happen after we've disposed of the write guard; in this
165
// case we need to disable the whole mechanism.
166
167
$use_scope = AphrontWriteGuard::isGuardActive();
168
if ($use_scope) {
169
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
170
} else {
171
AphrontWriteGuard::allowDangerousUnguardedWrites(true);
172
}
173
174
$caught = null;
175
try {
176
$file = call_user_func(
177
array('PhabricatorFile', 'newFromFileData'),
178
$data,
179
array(
180
'mime-type' => 'application/xhprof',
181
'name' => 'profile.xhprof',
182
));
183
} catch (Exception $ex) {
184
$caught = $ex;
185
}
186
187
if ($use_scope) {
188
unset($unguarded);
189
} else {
190
AphrontWriteGuard::allowDangerousUnguardedWrites(false);
191
}
192
193
if ($caught) {
194
throw $caught;
195
}
196
197
self::$profileFilePHID = $file->getPHID();
198
}
199
200
}
201
202