Select the types of activity you want to include in your feed.
@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
···11+22+ Apache License
33+ Version 2.0, January 2004
44+ http://www.apache.org/licenses/
55+66+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
77+88+ 1. Definitions.
99+1010+ "License" shall mean the terms and conditions for use, reproduction,
1111+ and distribution as defined by Sections 1 through 9 of this document.
1212+1313+ "Licensor" shall mean the copyright owner or entity authorized by
1414+ the copyright owner that is granting the License.
1515+1616+ "Legal Entity" shall mean the union of the acting entity and all
1717+ other entities that control, are controlled by, or are under common
1818+ control with that entity. For the purposes of this definition,
1919+ "control" means (i) the power, direct or indirect, to cause the
2020+ direction or management of such entity, whether by contract or
2121+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
2222+ outstanding shares, or (iii) beneficial ownership of such entity.
2323+2424+ "You" (or "Your") shall mean an individual or Legal Entity
2525+ exercising permissions granted by this License.
2626+2727+ "Source" form shall mean the preferred form for making modifications,
2828+ including but not limited to software source code, documentation
2929+ source, and configuration files.
3030+3131+ "Object" form shall mean any form resulting from mechanical
3232+ transformation or translation of a Source form, including but
3333+ not limited to compiled object code, generated documentation,
3434+ and conversions to other media types.
3535+3636+ "Work" shall mean the work of authorship, whether in Source or
3737+ Object form, made available under the License, as indicated by a
3838+ copyright notice that is included in or attached to the work
3939+ (an example is provided in the Appendix below).
4040+4141+ "Derivative Works" shall mean any work, whether in Source or Object
4242+ form, that is based on (or derived from) the Work and for which the
4343+ editorial revisions, annotations, elaborations, or other modifications
4444+ represent, as a whole, an original work of authorship. For the purposes
4545+ of this License, Derivative Works shall not include works that remain
4646+ separable from, or merely link (or bind by name) to the interfaces of,
4747+ the Work and Derivative Works thereof.
4848+4949+ "Contribution" shall mean any work of authorship, including
5050+ the original version of the Work and any modifications or additions
5151+ to that Work or Derivative Works thereof, that is intentionally
5252+ submitted to Licensor for inclusion in the Work by the copyright owner
5353+ or by an individual or Legal Entity authorized to submit on behalf of
5454+ the copyright owner. For the purposes of this definition, "submitted"
5555+ means any form of electronic, verbal, or written communication sent
5656+ to the Licensor or its representatives, including but not limited to
5757+ communication on electronic mailing lists, source code control systems,
5858+ and issue tracking systems that are managed by, or on behalf of, the
5959+ Licensor for the purpose of discussing and improving the Work, but
6060+ excluding communication that is conspicuously marked or otherwise
6161+ designated in writing by the copyright owner as "Not a Contribution."
6262+6363+ "Contributor" shall mean Licensor and any individual or Legal Entity
6464+ on behalf of whom a Contribution has been received by Licensor and
6565+ subsequently incorporated within the Work.
6666+6767+ 2. Grant of Copyright License. Subject to the terms and conditions of
6868+ this License, each Contributor hereby grants to You a perpetual,
6969+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
7070+ copyright license to reproduce, prepare Derivative Works of,
7171+ publicly display, publicly perform, sublicense, and distribute the
7272+ Work and such Derivative Works in Source or Object form.
7373+7474+ 3. Grant of Patent License. Subject to the terms and conditions of
7575+ this License, each Contributor hereby grants to You a perpetual,
7676+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
7777+ (except as stated in this section) patent license to make, have made,
7878+ use, offer to sell, sell, import, and otherwise transfer the Work,
7979+ where such license applies only to those patent claims licensable
8080+ by such Contributor that are necessarily infringed by their
8181+ Contribution(s) alone or by combination of their Contribution(s)
8282+ with the Work to which such Contribution(s) was submitted. If You
8383+ institute patent litigation against any entity (including a
8484+ cross-claim or counterclaim in a lawsuit) alleging that the Work
8585+ or a Contribution incorporated within the Work constitutes direct
8686+ or contributory patent infringement, then any patent licenses
8787+ granted to You under this License for that Work shall terminate
8888+ as of the date such litigation is filed.
8989+9090+ 4. Redistribution. You may reproduce and distribute copies of the
9191+ Work or Derivative Works thereof in any medium, with or without
9292+ modifications, and in Source or Object form, provided that You
9393+ meet the following conditions:
9494+9595+ (a) You must give any other recipients of the Work or
9696+ Derivative Works a copy of this License; and
9797+9898+ (b) You must cause any modified files to carry prominent notices
9999+ stating that You changed the files; and
100100+101101+ (c) You must retain, in the Source form of any Derivative Works
102102+ that You distribute, all copyright, patent, trademark, and
103103+ attribution notices from the Source form of the Work,
104104+ excluding those notices that do not pertain to any part of
105105+ the Derivative Works; and
106106+107107+ (d) If the Work includes a "NOTICE" text file as part of its
108108+ distribution, then any Derivative Works that You distribute must
109109+ include a readable copy of the attribution notices contained
110110+ within such NOTICE file, excluding those notices that do not
111111+ pertain to any part of the Derivative Works, in at least one
112112+ of the following places: within a NOTICE text file distributed
113113+ as part of the Derivative Works; within the Source form or
114114+ documentation, if provided along with the Derivative Works; or,
115115+ within a display generated by the Derivative Works, if and
116116+ wherever such third-party notices normally appear. The contents
117117+ of the NOTICE file are for informational purposes only and
118118+ do not modify the License. You may add Your own attribution
119119+ notices within Derivative Works that You distribute, alongside
120120+ or as an addendum to the NOTICE text from the Work, provided
121121+ that such additional attribution notices cannot be construed
122122+ as modifying the License.
123123+124124+ You may add Your own copyright statement to Your modifications and
125125+ may provide additional or different license terms and conditions
126126+ for use, reproduction, or distribution of Your modifications, or
127127+ for any such Derivative Works as a whole, provided Your use,
128128+ reproduction, and distribution of the Work otherwise complies with
129129+ the conditions stated in this License.
130130+131131+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132132+ any Contribution intentionally submitted for inclusion in the Work
133133+ by You to the Licensor shall be under the terms and conditions of
134134+ this License, without any additional terms or conditions.
135135+ Notwithstanding the above, nothing herein shall supersede or modify
136136+ the terms of any separate license agreement you may have executed
137137+ with Licensor regarding such Contributions.
138138+139139+ 6. Trademarks. This License does not grant permission to use the trade
140140+ names, trademarks, service marks, or product names of the Licensor,
141141+ except as required for reasonable and customary use in describing the
142142+ origin of the Work and reproducing the content of the NOTICE file.
143143+144144+ 7. Disclaimer of Warranty. Unless required by applicable law or
145145+ agreed to in writing, Licensor provides the Work (and each
146146+ Contributor provides its Contributions) on an "AS IS" BASIS,
147147+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148148+ implied, including, without limitation, any warranties or conditions
149149+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150150+ PARTICULAR PURPOSE. You are solely responsible for determining the
151151+ appropriateness of using or redistributing the Work and assume any
152152+ risks associated with Your exercise of permissions under this License.
153153+154154+ 8. Limitation of Liability. In no event and under no legal theory,
155155+ whether in tort (including negligence), contract, or otherwise,
156156+ unless required by applicable law (such as deliberate and grossly
157157+ negligent acts) or agreed to in writing, shall any Contributor be
158158+ liable to You for damages, including any direct, indirect, special,
159159+ incidental, or consequential damages of any character arising as a
160160+ result of this License or out of the use or inability to use the
161161+ Work (including but not limited to damages for loss of goodwill,
162162+ work stoppage, computer failure or malfunction, or any and all
163163+ other commercial damages or losses), even if such Contributor
164164+ has been advised of the possibility of such damages.
165165+166166+ 9. Accepting Warranty or Additional Liability. While redistributing
167167+ the Work or Derivative Works thereof, You may choose to offer,
168168+ and charge a fee for, acceptance of support, warranty, indemnity,
169169+ or other liability obligations and/or rights consistent with this
170170+ License. However, in accepting such obligations, You may act only
171171+ on Your own behalf and on Your sole responsibility, not on behalf
172172+ of any other Contributor, and only if You agree to indemnify,
173173+ defend, and hold each Contributor harmless for any liability
174174+ incurred by, or claims asserted against, such Contributor by reason
175175+ of your accepting any such warranty or additional liability.
176176+177177+ END OF TERMS AND CONDITIONS
+866
externals/xhprof/xhprof_lib.php
···11+<?php
22+// Copyright (c) 2009 Facebook
33+//
44+// Licensed under the Apache License, Version 2.0 (the "License");
55+// you may not use this file except in compliance with the License.
66+// You may obtain a copy of the License at
77+//
88+// http://www.apache.org/licenses/LICENSE-2.0
99+//
1010+// Unless required by applicable law or agreed to in writing, software
1111+// distributed under the License is distributed on an "AS IS" BASIS,
1212+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313+// See the License for the specific language governing permissions and
1414+// limitations under the License.
1515+//
1616+1717+//
1818+// This file contains various XHProf library (utility) functions.
1919+// Do not add any display specific code here.
2020+//
2121+2222+function xhprof_error($message) {
2323+ error_log($message);
2424+}
2525+2626+/*
2727+ * The list of possible metrics collected as part of XHProf that
2828+ * require inclusive/exclusive handling while reporting.
2929+ *
3030+ * @author Kannan
3131+ */
3232+function xhprof_get_possible_metrics() {
3333+ static $possible_metrics =
3434+ array("wt" => array("Wall", "microsecs", "walltime" ),
3535+ "ut" => array("User", "microsecs", "user cpu time" ),
3636+ "st" => array("Sys", "microsecs", "system cpu time"),
3737+ "cpu" => array("Cpu", "microsecs", "cpu time"),
3838+ "mu" => array("MUse", "bytes", "memory usage"),
3939+ "pmu" => array("PMUse", "bytes", "peak memory usage"),
4040+ "samples" => array("Samples", "samples", "cpu time"));
4141+ return $possible_metrics;
4242+}
4343+4444+/*
4545+ * Get the list of metrics present in $xhprof_data as an array.
4646+ *
4747+ * @author Kannan
4848+ */
4949+function xhprof_get_metrics($xhprof_data) {
5050+5151+ // get list of valid metrics
5252+ $possible_metrics = xhprof_get_possible_metrics();
5353+5454+ // return those that are present in the raw data.
5555+ // We'll just look at the root of the subtree for this.
5656+ $metrics = array();
5757+ foreach ($possible_metrics as $metric => $desc) {
5858+ if (isset($xhprof_data["main()"][$metric])) {
5959+ $metrics[] = $metric;
6060+ }
6161+ }
6262+6363+ return $metrics;
6464+}
6565+6666+/**
6767+ * Takes a parent/child function name encoded as
6868+ * "a==>b" and returns array("a", "b").
6969+ *
7070+ * @author Kannan
7171+ */
7272+function xhprof_parse_parent_child($parent_child) {
7373+ $ret = explode("==>", $parent_child);
7474+7575+ // Return if both parent and child are set
7676+ if (isset($ret[1])) {
7777+ return $ret;
7878+ }
7979+8080+ return array(null, $ret[0]);
8181+}
8282+8383+/**
8484+ * Given parent & child function name, composes the key
8585+ * in the format present in the raw data.
8686+ *
8787+ * @author Kannan
8888+ */
8989+function xhprof_build_parent_child_key($parent, $child) {
9090+ if ($parent) {
9191+ return $parent . "==>" . $child;
9292+ } else {
9393+ return $child;
9494+ }
9595+}
9696+9797+9898+/**
9999+ * Checks if XHProf raw data appears to be valid and not corrupted.
100100+ *
101101+ * @param int $run_id Run id of run to be pruned.
102102+ * [Used only for reporting errors.]
103103+ * @param array $raw_data XHProf raw data to be pruned
104104+ * & validated.
105105+ *
106106+ * @return bool true on success, false on failure
107107+ *
108108+ * @author Kannan
109109+ */
110110+function xhprof_valid_run($run_id, $raw_data) {
111111+112112+ $main_info = $raw_data["main()"];
113113+ if (empty($main_info)) {
114114+ xhprof_error("XHProf: main() missing in raw data for Run ID: $run_id");
115115+ return false;
116116+ }
117117+118118+ // raw data should contain either wall time or samples information...
119119+ if (isset($main_info["wt"])) {
120120+ $metric = "wt";
121121+ } else if (isset($main_info["samples"])) {
122122+ $metric = "samples";
123123+ } else {
124124+ xhprof_error("XHProf: Wall Time information missing from Run ID: $run_id");
125125+ return false;
126126+ }
127127+128128+ foreach ($raw_data as $info) {
129129+ $val = $info[$metric];
130130+131131+ // basic sanity checks...
132132+ if ($val < 0) {
133133+ xhprof_error("XHProf: $metric should not be negative: Run ID $run_id"
134134+ . serialize($info));
135135+ return false;
136136+ }
137137+ if ($val > (86400000000)) {
138138+ xhprof_error("XHProf: $metric > 1 day found in Run ID: $run_id "
139139+ . serialize($info));
140140+ return false;
141141+ }
142142+ }
143143+ return true;
144144+}
145145+146146+147147+/**
148148+ * Return a trimmed version of the XHProf raw data. Note that the raw
149149+ * data contains one entry for each unique parent/child function
150150+ * combination.The trimmed version of raw data will only contain
151151+ * entries where either the parent or child function is in the list
152152+ * of $functions_to_keep.
153153+ *
154154+ * Note: Function main() is also always kept so that overall totals
155155+ * can still be obtained from the trimmed version.
156156+ *
157157+ * @param array XHProf raw data
158158+ * @param array array of function names
159159+ *
160160+ * @return array Trimmed XHProf Report
161161+ *
162162+ * @author Kannan
163163+ */
164164+function xhprof_trim_run($raw_data, $functions_to_keep) {
165165+166166+ // convert list of functions to a hash with function as the key
167167+ $function_map = array_fill_keys($functions_to_keep, 1);
168168+169169+ // always keep main() as well so that overall totals can still
170170+ // be computed if need be.
171171+ $function_map['main()'] = 1;
172172+173173+ $new_raw_data = array();
174174+ foreach ($raw_data as $parent_child => $info) {
175175+ list($parent, $child) = xhprof_parse_parent_child($parent_child);
176176+177177+ if (isset($function_map[$parent]) || isset($function_map[$child])) {
178178+ $new_raw_data[$parent_child] = $info;
179179+ }
180180+ }
181181+182182+ return $new_raw_data;
183183+}
184184+185185+/**
186186+ * Takes raw XHProf data that was aggregated over "$num_runs" number
187187+ * of runs averages/nomalizes the data. Essentially the various metrics
188188+ * collected are divided by $num_runs.
189189+ *
190190+ * @author Kannan
191191+ */
192192+function xhprof_normalize_metrics($raw_data, $num_runs) {
193193+194194+ if (empty($raw_data) || ($num_runs == 0)) {
195195+ return $raw_data;
196196+ }
197197+198198+ $raw_data_total = array();
199199+200200+ if (isset($raw_data["==>main()"]) && isset($raw_data["main()"])) {
201201+ xhprof_error("XHProf Error: both ==>main() and main() set in raw data...");
202202+ }
203203+204204+ foreach ($raw_data as $parent_child => $info) {
205205+ foreach ($info as $metric => $value) {
206206+ $raw_data_total[$parent_child][$metric] = ($value / $num_runs);
207207+ }
208208+ }
209209+210210+ return $raw_data_total;
211211+}
212212+213213+214214+/**
215215+ * Get raw data corresponding to specified array of runs
216216+ * aggregated by certain weightage.
217217+ *
218218+ * Suppose you have run:5 corresponding to page1.php,
219219+ * run:6 corresponding to page2.php,
220220+ * and run:7 corresponding to page3.php
221221+ *
222222+ * and you want to accumulate these runs in a 2:4:1 ratio. You
223223+ * can do so by calling:
224224+ *
225225+ * xhprof_aggregate_runs(array(5, 6, 7), array(2, 4, 1));
226226+ *
227227+ * The above will return raw data for the runs aggregated
228228+ * in 2:4:1 ratio.
229229+ *
230230+ * @param object $xhprof_runs_impl An object that implements
231231+ * the iXHProfRuns interface
232232+ * @param array $runs run ids of the XHProf runs..
233233+ * @param array $wts integral (ideally) weights for $runs
234234+ * @param string $source source to fetch raw data for run from
235235+ * @param bool $use_script_name If true, a fake edge from main() to
236236+ * to __script::<scriptname> is introduced
237237+ * in the raw data so that after aggregations
238238+ * the script name is still preserved.
239239+ *
240240+ * @return array Return aggregated raw data
241241+ *
242242+ * @author Kannan
243243+ */
244244+function xhprof_aggregate_runs($xhprof_runs_impl, $runs,
245245+ $wts, $source="phprof",
246246+ $use_script_name=false) {
247247+248248+ $raw_data_total = null;
249249+ $raw_data = null;
250250+ $metrics = array();
251251+252252+ $run_count = count($runs);
253253+ $wts_count = count($wts);
254254+255255+ if (($run_count == 0) ||
256256+ (($wts_count > 0) && ($run_count != $wts_count))) {
257257+ return array('description' => 'Invalid input..',
258258+ 'raw' => null);
259259+ }
260260+261261+ $bad_runs = array();
262262+ foreach($runs as $idx => $run_id) {
263263+264264+ $raw_data = $xhprof_runs_impl->get_run($run_id, $source, $description);
265265+266266+ // use the first run to derive what metrics to aggregate on.
267267+ if ($idx == 0) {
268268+ foreach ($raw_data["main()"] as $metric => $val) {
269269+ if ($metric != "pmu") {
270270+ // for now, just to keep data size small, skip "peak" memory usage
271271+ // data while aggregating.
272272+ // The "regular" memory usage data will still be tracked.
273273+ if (isset($val)) {
274274+ $metrics[] = $metric;
275275+ }
276276+ }
277277+ }
278278+ }
279279+280280+ if (!xhprof_valid_run($run_id, $raw_data)) {
281281+ $bad_runs[] = $run_id;
282282+ continue;
283283+ }
284284+285285+ if ($use_script_name) {
286286+ $page = $description;
287287+288288+ // create a fake function '__script::$page', and have and edge from
289289+ // main() to '__script::$page'. We will also need edges to transfer
290290+ // all edges originating from main() to now originate from
291291+ // '__script::$page' to all function called from main().
292292+ //
293293+ // We also weight main() ever so slightly higher so that
294294+ // it shows up above the new entry in reports sorted by
295295+ // inclusive metrics or call counts.
296296+ if ($page) {
297297+ foreach($raw_data["main()"] as $metric => $val) {
298298+ $fake_edge[$metric] = $val;
299299+ $new_main[$metric] = $val + 0.00001;
300300+ }
301301+ $raw_data["main()"] = $new_main;
302302+ $raw_data[xhprof_build_parent_child_key("main()",
303303+ "__script::$page")]
304304+ = $fake_edge;
305305+ } else {
306306+ $use_script_name = false;
307307+ }
308308+ }
309309+310310+ // if no weights specified, use 1 as the default weightage..
311311+ $wt = ($wts_count == 0) ? 1 : $wts[$idx];
312312+313313+ // aggregate $raw_data into $raw_data_total with appropriate weight ($wt)
314314+ foreach ($raw_data as $parent_child => $info) {
315315+ if ($use_script_name) {
316316+ // if this is an old edge originating from main(), it now
317317+ // needs to be from '__script::$page'
318318+ if (substr($parent_child, 0, 9) == "main()==>") {
319319+ $child =substr($parent_child, 9);
320320+ // ignore the newly added edge from main()
321321+ if (substr($child, 0, 10) != "__script::") {
322322+ $parent_child = xhprof_build_parent_child_key("__script::$page",
323323+ $child);
324324+ }
325325+ }
326326+ }
327327+328328+ if (!isset($raw_data_total[$parent_child])) {
329329+ foreach ($metrics as $metric) {
330330+ $raw_data_total[$parent_child][$metric] = ($wt * $info[$metric]);
331331+ }
332332+ } else {
333333+ foreach ($metrics as $metric) {
334334+ $raw_data_total[$parent_child][$metric] += ($wt * $info[$metric]);
335335+ }
336336+ }
337337+ }
338338+ }
339339+340340+ $runs_string = implode(",", $runs);
341341+342342+ if (isset($wts)) {
343343+ $wts_string = "in the ratio (" . implode(":", $wts) . ")";
344344+ $normalization_count = array_sum($wts);
345345+ } else {
346346+ $wts_string = "";
347347+ $normalization_count = $run_count;
348348+ }
349349+350350+ $run_count = $run_count - count($bad_runs);
351351+352352+ $data['description'] = "Aggregated Report for $run_count runs: ".
353353+ "$runs_string $wts_string\n";
354354+ $data['raw'] = xhprof_normalize_metrics($raw_data_total,
355355+ $normalization_count);
356356+ $data['bad_runs'] = $bad_runs;
357357+358358+ return $data;
359359+}
360360+361361+362362+/**
363363+ * Analyze hierarchical raw data, and compute per-function (flat)
364364+ * inclusive and exclusive metrics.
365365+ *
366366+ * Also, store overall totals in the 2nd argument.
367367+ *
368368+ * @param array $raw_data XHProf format raw profiler data.
369369+ * @param array &$overall_totals OUT argument for returning
370370+ * overall totals for various
371371+ * metrics.
372372+ * @return array Returns a map from function name to its
373373+ * call count and inclusive & exclusive metrics
374374+ * (such as wall time, etc.).
375375+ *
376376+ * @author Kannan Muthukkaruppan
377377+ */
378378+function xhprof_compute_flat_info($raw_data, &$overall_totals) {
379379+380380+ global $display_calls;
381381+382382+ $metrics = xhprof_get_metrics($raw_data);
383383+384384+ $overall_totals = array( "ct" => 0,
385385+ "wt" => 0,
386386+ "ut" => 0,
387387+ "st" => 0,
388388+ "cpu" => 0,
389389+ "mu" => 0,
390390+ "pmu" => 0,
391391+ "samples" => 0
392392+ );
393393+394394+ // compute inclusive times for each function
395395+ $symbol_tab = xhprof_compute_inclusive_times($raw_data);
396396+397397+ /* total metric value is the metric value for "main()" */
398398+ foreach ($metrics as $metric) {
399399+ $overall_totals[$metric] = $symbol_tab["main()"][$metric];
400400+ }
401401+402402+ /*
403403+ * initialize exclusive (self) metric value to inclusive metric value
404404+ * to start with.
405405+ * In the same pass, also add up the total number of function calls.
406406+ */
407407+ foreach ($symbol_tab as $symbol => $info) {
408408+ foreach ($metrics as $metric) {
409409+ $symbol_tab[$symbol]["excl_" . $metric] = $symbol_tab[$symbol][$metric];
410410+ }
411411+ if ($display_calls) {
412412+ /* keep track of total number of calls */
413413+ $overall_totals["ct"] += $info["ct"];
414414+ }
415415+ }
416416+417417+ /* adjust exclusive times by deducting inclusive time of children */
418418+ foreach ($raw_data as $parent_child => $info) {
419419+ list($parent, $child) = xhprof_parse_parent_child($parent_child);
420420+421421+ if ($parent) {
422422+ foreach ($metrics as $metric) {
423423+ // make sure the parent exists hasn't been pruned.
424424+ if (isset($symbol_tab[$parent])) {
425425+ $symbol_tab[$parent]["excl_" . $metric] -= $info[$metric];
426426+ }
427427+ }
428428+ }
429429+ }
430430+431431+ return $symbol_tab;
432432+}
433433+434434+/**
435435+ * Hierarchical diff:
436436+ * Compute and return difference of two call graphs: Run2 - Run1.
437437+ *
438438+ * @author Kannan
439439+ */
440440+function xhprof_compute_diff($xhprof_data1, $xhprof_data2) {
441441+ global $display_calls;
442442+443443+ // use the second run to decide what metrics we will do the diff on
444444+ $metrics = xhprof_get_metrics($xhprof_data2);
445445+446446+ $xhprof_delta = $xhprof_data2;
447447+448448+ foreach ($xhprof_data1 as $parent_child => $info) {
449449+450450+ if (!isset($xhprof_delta[$parent_child])) {
451451+452452+ // this pc combination was not present in run1;
453453+ // initialize all values to zero.
454454+ if ($display_calls) {
455455+ $xhprof_delta[$parent_child] = array("ct" => 0);
456456+ } else {
457457+ $xhprof_delta[$parent_child] = array();
458458+ }
459459+ foreach ($metrics as $metric) {
460460+ $xhprof_delta[$parent_child][$metric] = 0;
461461+ }
462462+ }
463463+464464+ if ($display_calls) {
465465+ $xhprof_delta[$parent_child]["ct"] -= $info["ct"];
466466+ }
467467+468468+ foreach ($metrics as $metric) {
469469+ $xhprof_delta[$parent_child][$metric] -= $info[$metric];
470470+ }
471471+ }
472472+473473+ return $xhprof_delta;
474474+}
475475+476476+477477+/**
478478+ * Compute inclusive metrics for function. This code was factored out
479479+ * of xhprof_compute_flat_info().
480480+ *
481481+ * The raw data contains inclusive metrics of a function for each
482482+ * unique parent function it is called from. The total inclusive metrics
483483+ * for a function is therefore the sum of inclusive metrics for the
484484+ * function across all parents.
485485+ *
486486+ * @return array Returns a map of function name to total (across all parents)
487487+ * inclusive metrics for the function.
488488+ *
489489+ * @author Kannan
490490+ */
491491+function xhprof_compute_inclusive_times($raw_data) {
492492+ global $display_calls;
493493+494494+ $metrics = xhprof_get_metrics($raw_data);
495495+496496+ $symbol_tab = array();
497497+498498+ /*
499499+ * First compute inclusive time for each function and total
500500+ * call count for each function across all parents the
501501+ * function is called from.
502502+ */
503503+ foreach ($raw_data as $parent_child => $info) {
504504+505505+ list($parent, $child) = xhprof_parse_parent_child($parent_child);
506506+507507+ if ($parent == $child) {
508508+ /*
509509+ * XHProf PHP extension should never trigger this situation any more.
510510+ * Recursion is handled in the XHProf PHP extension by giving nested
511511+ * calls a unique recursion-depth appended name (for example, foo@1).
512512+ */
513513+ xhprof_error("Error in Raw Data: parent & child are both: $parent");
514514+ return;
515515+ }
516516+517517+ if (!isset($symbol_tab[$child])) {
518518+519519+ if ($display_calls) {
520520+ $symbol_tab[$child] = array("ct" => $info["ct"]);
521521+ } else {
522522+ $symbol_tab[$child] = array();
523523+ }
524524+ foreach ($metrics as $metric) {
525525+ $symbol_tab[$child][$metric] = $info[$metric];
526526+ }
527527+ } else {
528528+ if ($display_calls) {
529529+ /* increment call count for this child */
530530+ $symbol_tab[$child]["ct"] += $info["ct"];
531531+ }
532532+533533+ /* update inclusive times/metric for this child */
534534+ foreach ($metrics as $metric) {
535535+ $symbol_tab[$child][$metric] += $info[$metric];
536536+ }
537537+ }
538538+ }
539539+540540+ return $symbol_tab;
541541+}
542542+543543+544544+/*
545545+ * Prunes XHProf raw data:
546546+ *
547547+ * Any node whose inclusive walltime accounts for less than $prune_percent
548548+ * of total walltime is pruned. [It is possible that a child function isn't
549549+ * pruned, but one or more of its parents get pruned. In such cases, when
550550+ * viewing the child function's hierarchical information, the cost due to
551551+ * the pruned parent(s) will be attributed to a special function/symbol
552552+ * "__pruned__()".]
553553+ *
554554+ * @param array $raw_data XHProf raw data to be pruned & validated.
555555+ * @param double $prune_percent Any edges that account for less than
556556+ * $prune_percent of time will be pruned
557557+ * from the raw data.
558558+ *
559559+ * @return array Returns the pruned raw data.
560560+ *
561561+ * @author Kannan
562562+ */
563563+function xhprof_prune_run($raw_data, $prune_percent) {
564564+565565+ $main_info = $raw_data["main()"];
566566+ if (empty($main_info)) {
567567+ xhprof_error("XHProf: main() missing in raw data");
568568+ return false;
569569+ }
570570+571571+ // raw data should contain either wall time or samples information...
572572+ if (isset($main_info["wt"])) {
573573+ $prune_metric = "wt";
574574+ } else if (isset($main_info["samples"])) {
575575+ $prune_metric = "samples";
576576+ } else {
577577+ xhprof_error("XHProf: for main() we must have either wt "
578578+ ."or samples attribute set");
579579+ return false;
580580+ }
581581+582582+ // determine the metrics present in the raw data..
583583+ $metrics = array();
584584+ foreach ($main_info as $metric => $val) {
585585+ if (isset($val)) {
586586+ $metrics[] = $metric;
587587+ }
588588+ }
589589+590590+ $prune_threshold = (($main_info[$prune_metric] * $prune_percent) / 100.0);
591591+592592+ init_metrics($raw_data, null, null, false);
593593+ $flat_info = xhprof_compute_inclusive_times($raw_data);
594594+595595+ foreach ($raw_data as $parent_child => $info) {
596596+597597+ list($parent, $child) = xhprof_parse_parent_child($parent_child);
598598+599599+ // is this child's overall total from all parents less than threshold?
600600+ if ($flat_info[$child][$prune_metric] < $prune_threshold) {
601601+ unset($raw_data[$parent_child]); // prune the edge
602602+ } else if ($parent &&
603603+ ($parent != "__pruned__()") &&
604604+ ($flat_info[$parent][$prune_metric] < $prune_threshold)) {
605605+606606+ // Parent's overall inclusive metric is less than a threshold.
607607+ // All edges to the parent node will get nuked, and this child will
608608+ // be a dangling child.
609609+ // So instead change its parent to be a special function __pruned__().
610610+ $pruned_edge = xhprof_build_parent_child_key("__pruned__()", $child);
611611+612612+ if (isset($raw_data[$pruned_edge])) {
613613+ foreach ($metrics as $metric) {
614614+ $raw_data[$pruned_edge][$metric]+=$raw_data[$parent_child][$metric];
615615+ }
616616+ } else {
617617+ $raw_data[$pruned_edge] = $raw_data[$parent_child];
618618+ }
619619+620620+ unset($raw_data[$parent_child]); // prune the edge
621621+ }
622622+ }
623623+624624+ return $raw_data;
625625+}
626626+627627+628628+/**
629629+ * Set one key in an array and return the array
630630+ *
631631+ * @author Kannan
632632+ */
633633+function xhprof_array_set($arr, $k, $v) {
634634+ $arr[$k] = $v;
635635+ return $arr;
636636+}
637637+638638+/**
639639+ * Removes/unsets one key in an array and return the array
640640+ *
641641+ * @author Kannan
642642+ */
643643+function xhprof_array_unset($arr, $k) {
644644+ unset($arr[$k]);
645645+ return $arr;
646646+}
647647+648648+/**
649649+ * Type definitions for URL params
650650+ */
651651+define('XHPROF_STRING_PARAM', 1);
652652+define('XHPROF_UINT_PARAM', 2);
653653+define('XHPROF_FLOAT_PARAM', 3);
654654+define('XHPROF_BOOL_PARAM', 4);
655655+656656+657657+/**
658658+ * Internal helper function used by various
659659+ * xhprof_get_param* flavors for various
660660+ * types of parameters.
661661+ *
662662+ * @param string name of the URL query string param
663663+ *
664664+ * @author Kannan
665665+ */
666666+function xhprof_get_param_helper($param) {
667667+ $val = null;
668668+ if (isset($_GET[$param]))
669669+ $val = $_GET[$param];
670670+ else if (isset($_POST[$param])) {
671671+ $val = $_POST[$param];
672672+ }
673673+ return $val;
674674+}
675675+676676+/**
677677+ * Extracts value for string param $param from query
678678+ * string. If param is not specified, return the
679679+ * $default value.
680680+ *
681681+ * @author Kannan
682682+ */
683683+function xhprof_get_string_param($param, $default = '') {
684684+ $val = xhprof_get_param_helper($param);
685685+686686+ if ($val === null)
687687+ return $default;
688688+689689+ return $val;
690690+}
691691+692692+/**
693693+ * Extracts value for unsigned integer param $param from
694694+ * query string. If param is not specified, return the
695695+ * $default value.
696696+ *
697697+ * If value is not a valid unsigned integer, logs error
698698+ * and returns null.
699699+ *
700700+ * @author Kannan
701701+ */
702702+function xhprof_get_uint_param($param, $default = 0) {
703703+ $val = xhprof_get_param_helper($param);
704704+705705+ if ($val === null)
706706+ $val = $default;
707707+708708+ // trim leading/trailing whitespace
709709+ $val = trim($val);
710710+711711+ // if it only contains digits, then ok..
712712+ if (ctype_digit($val)) {
713713+ return $val;
714714+ }
715715+716716+ xhprof_error("$param is $val. It must be an unsigned integer.");
717717+ return null;
718718+}
719719+720720+721721+/**
722722+ * Extracts value for a float param $param from
723723+ * query string. If param is not specified, return
724724+ * the $default value.
725725+ *
726726+ * If value is not a valid unsigned integer, logs error
727727+ * and returns null.
728728+ *
729729+ * @author Kannan
730730+ */
731731+function xhprof_get_float_param($param, $default = 0) {
732732+ $val = xhprof_get_param_helper($param);
733733+734734+ if ($val === null)
735735+ $val = $default;
736736+737737+ // trim leading/trailing whitespace
738738+ $val = trim($val);
739739+740740+ // TBD: confirm the value is indeed a float.
741741+ if (true) // for now..
742742+ return (float)$val;
743743+744744+ xhprof_error("$param is $val. It must be a float.");
745745+ return null;
746746+}
747747+748748+/**
749749+ * Extracts value for a boolean param $param from
750750+ * query string. If param is not specified, return
751751+ * the $default value.
752752+ *
753753+ * If value is not a valid unsigned integer, logs error
754754+ * and returns null.
755755+ *
756756+ * @author Kannan
757757+ */
758758+function xhprof_get_bool_param($param, $default = false) {
759759+ $val = xhprof_get_param_helper($param);
760760+761761+ if ($val === null)
762762+ $val = $default;
763763+764764+ // trim leading/trailing whitespace
765765+ $val = trim($val);
766766+767767+ switch (strtolower($val)) {
768768+ case '0':
769769+ case '1':
770770+ $val = (bool)$val;
771771+ break;
772772+ case 'true':
773773+ case 'on':
774774+ case 'yes':
775775+ $val = true;
776776+ break;
777777+ case 'false':
778778+ case 'off':
779779+ case 'no':
780780+ $val = false;
781781+ break;
782782+ default:
783783+ xhprof_error("$param is $val. It must be a valid boolean string.");
784784+ return null;
785785+ }
786786+787787+ return $val;
788788+789789+}
790790+791791+/**
792792+ * Initialize params from URL query string. The function
793793+ * creates globals variables for each of the params
794794+ * and if the URL query string doesn't specify a particular
795795+ * param initializes them with the corresponding default
796796+ * value specified in the input.
797797+ *
798798+ * @params array $params An array whose keys are the names
799799+ * of URL params who value needs to
800800+ * be retrieved from the URL query
801801+ * string. PHP globals are created
802802+ * with these names. The value is
803803+ * itself an array with 2-elems (the
804804+ * param type, and its default value).
805805+ * If a param is not specified in the
806806+ * query string the default value is
807807+ * used.
808808+ * @author Kannan
809809+ */
810810+function xhprof_param_init($params) {
811811+ /* Create variables specified in $params keys, init defaults */
812812+ foreach ($params as $k => $v) {
813813+ switch ($v[0]) {
814814+ case XHPROF_STRING_PARAM:
815815+ $p = xhprof_get_string_param($k, $v[1]);
816816+ break;
817817+ case XHPROF_UINT_PARAM:
818818+ $p = xhprof_get_uint_param($k, $v[1]);
819819+ break;
820820+ case XHPROF_FLOAT_PARAM:
821821+ $p = xhprof_get_float_param($k, $v[1]);
822822+ break;
823823+ case XHPROF_BOOL_PARAM:
824824+ $p = xhprof_get_bool_param($k, $v[1]);
825825+ break;
826826+ default:
827827+ xhprof_error("Invalid param type passed to xhprof_param_init: "
828828+ . $v[0]);
829829+ exit();
830830+ }
831831+832832+ // create a global variable using the parameter name.
833833+ $GLOBALS[$k] = $p;
834834+ }
835835+}
836836+837837+838838+/**
839839+ * Given a partial query string $q return matching function names in
840840+ * specified XHProf run. This is used for the type ahead function
841841+ * selector.
842842+ *
843843+ * @author Kannan
844844+ */
845845+function xhprof_get_matching_functions($q, $xhprof_data) {
846846+847847+ $matches = array();
848848+849849+ foreach ($xhprof_data as $parent_child => $info) {
850850+ list($parent, $child) = xhprof_parse_parent_child($parent_child);
851851+ if (stripos($parent, $q) !== false) {
852852+ $matches[$parent] = 1;
853853+ }
854854+ if (stripos($child, $q) !== false) {
855855+ $matches[$child] = 1;
856856+ }
857857+ }
858858+859859+ $res = array_keys($matches);
860860+861861+ // sort it so the answers are in some reliable order...
862862+ asort($res);
863863+864864+ return ($res);
865865+}
866866+
···2424 private $request;
2525 private $host;
2626 private $path;
2727+ private $console;
27282829 abstract public function getApplicationName();
2930 abstract public function getURIMap();
···37383839 final public function getRequest() {
3940 return $this->request;
4141+ }
4242+4343+ final public function getConsole() {
4444+ return $this->console;
4045 }
41464247 final public function buildController() {
···72777378 final public function getPath() {
7479 return $this->path;
8080+ }
8181+8282+ final public function willBuildRequest() {
8383+ $this->console = new DarkConsoleCore();
7584 }
76857786}
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class DarkConsole {
2020+2121+}
+10
src/aphront/console/api/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+1010+phutil_require_source('DarkConsole.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class DarkConsoleController extends AliteController {
2020+2121+ protected $op;
2222+ protected $data;
2323+2424+ public function __construct(AliteRequest $request, array $params) {
2525+ parent::__construct($request);
2626+2727+ validate_parameter_list(
2828+ $params,
2929+ array(
3030+ ),
3131+ $ops = array(
3232+ 'tab' => true,
3333+ 'toggle' => true,
3434+ 'visible' => true,
3535+ 'plugin' => true,
3636+3737+ 'etc' => true,
3838+ ));
3939+4040+ foreach (array_keys($ops) as $op) {
4141+ if (isset($params[$op])) {
4242+ $this->op = $op;
4343+ break;
4444+ }
4545+ }
4646+ $this->data = $params;
4747+ }
4848+4949+ public function getShortControllerName() {
5050+ return 'DarkConsole';
5151+ }
5252+5353+ public function shouldPreflush() {
5454+ return false;
5555+ }
5656+5757+ public function process() {
5858+ $request = $this->getRequest();
5959+6060+ if (!$this->op) {
6161+ $this->op = 'toggle';
6262+ }
6363+6464+ $coredata = $request->getCoreData();
6565+ $console = $coredata->getConsole();
6666+6767+ if ($request->isAsync()) {
6868+ $return = null;
6969+ } else {
7070+ $return = '/';
7171+ }
7272+7373+7474+ switch ($this->op) {
7575+ case 'toggle':
7676+ $enabled = $coredata->didToggleDarkConsole();
7777+ if ($enabled) {
7878+ if (!$console) {
7979+ $console = new DarkConsoleCore($coredata);
8080+ }
8181+ $console->setConsoleSetting(
8282+ DarkConsoleCore::SETTING_VISIBLE,
8383+ true);
8484+ }
8585+ break;
8686+ case 'tab':
8787+ $console->setConsoleSetting(
8888+ DarkConsoleCore::SETTING_TAB,
8989+ $request->getStr('tab'));
9090+ break;
9191+ case 'visible':
9292+ $console->setConsoleSetting(
9393+ DarkConsoleCore::SETTING_VISIBLE,
9494+ !$console->getConsoleSetting(DarkConsoleCore::SETTING_VISIBLE));
9595+ break;
9696+ }
9797+// return <alite:redirect uri={$return} />;
9898+ }
9999+100100+}
+12
src/aphront/console/controller/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phabricator', 'aphront/console/core');
1010+1111+1212+phutil_require_source('DarkConsoleController.php');
+186
src/aphront/console/core/DarkConsoleCore.php
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+final class DarkConsoleCore {
2020+2121+ const PLUGIN_ERRORLOG = 'ErrorLog';
2222+ const PLUGIN_SERVICES = 'Services';
2323+ const PLUGIN_XHPROF = 'XHProf';
2424+ const PLUGIN_REQUEST = 'Request';
2525+2626+ public static function getPlugins() {
2727+ return array(
2828+ self::PLUGIN_ERRORLOG,
2929+ self::PLUGIN_REQUEST,
3030+ self::PLUGIN_SERVICES,
3131+ self::PLUGIN_XHPROF,
3232+ );
3333+ }
3434+3535+ private $plugins = array();
3636+ private $settings;
3737+ private $coredata;
3838+3939+ public function setConsoleSetting($key, $value) {
4040+/*
4141+ $guard = new WriteOnHttpGet();
4242+ $okay = user_set_pref(
4343+ $this->getCoreData()->getViewerContext()->getUserID(),
4444+ self::APPLICATION_ID,
4545+ $key,
4646+ $value);
4747+ $guard->release();
4848+ if (!$okay) {
4949+ throw new Exception('Failed to set preference setting.');
5050+ }
5151+*/
5252+ }
5353+5454+ public function getConsoleSetting($key) {
5555+// $viewer_id = $this->getCoreData()->getViewerContext()->getUserID();
5656+// return idx(idx($this->settings[$viewer_id], $key), 'value');
5757+ return true;
5858+ }
5959+6060+ public function getPlugin($plugin_name) {
6161+ return idx($this->plugins, $plugin_name);
6262+ }
6363+6464+ public function __construct() {
6565+6666+/*
6767+ $this->settings = users_multiget_prefs_info(
6868+ array($coredata->getViewerContext()->getUserID()),
6969+ self::APPLICATION_ID);
7070+7171+ $disabled = $this->getConsoleSetting(self::SETTING_PLUGINS);
7272+ $disabled = array_flip(explode(',', $disabled));
7373+*/
7474+ foreach (self::getPlugins() as $plugin_name) {
7575+ $plugin = self::newPlugin($plugin_name);
7676+ if ($plugin->isPermanent() || !isset($disabled[$plugin_name])) {
7777+ if ($plugin->shouldStartup()) {
7878+ $plugin->didStartup();
7979+ $plugin->setConsoleCore($this);
8080+ $this->plugins[$plugin_name] = $plugin;
8181+ }
8282+ }
8383+ }
8484+ }
8585+8686+ public static function newPlugin($plugin) {
8787+ $class = 'DarkConsole'.$plugin.'Plugin';
8888+ PhutilSymbolLoader::loadClass($class);
8989+ return newv($class, array());
9090+ }
9191+9292+ public function getEnabledPlugins() {
9393+ return $this->plugins;
9494+ }
9595+9696+ public function render(AphrontRequest $request) {
9797+9898+ $plugins = $this->getEnabledPlugins();
9999+100100+ foreach ($plugins as $plugin) {
101101+ $plugin->setRequest($request);
102102+ $plugin->willShutdown();
103103+ }
104104+105105+ foreach ($plugins as $plugin) {
106106+ $plugin->didShutdown();
107107+ }
108108+109109+ foreach ($plugins as $plugin) {
110110+ $plugin->setData($plugin->generateData());
111111+ }
112112+113113+ $selected = 'XHProf';//true;//$this->getConsoleSetting(DarkConsoleCore::SETTING_TAB);
114114+ $visible = true;//$this->getConsoleSetting(DarkConsoleCore::SETTING_VISIBLE);
115115+116116+ if (!isset($plugins[$selected])) {
117117+ $selected = key($plugins);
118118+ }
119119+120120+ $tabs = array();
121121+ foreach ($plugins as $key => $plugin) {
122122+ $tabs[$key] = array(
123123+ 'name' => $plugin->getName(),
124124+ 'panel' => $plugin->render(),
125125+ );
126126+ }
127127+128128+ $tabs_markup = array();
129129+ $panel_markup = array();
130130+ foreach ($tabs as $key => $data) {
131131+ $is_selected = ($key == $selected);
132132+ if ($is_selected) {
133133+ $style = null;
134134+ $tabclass = 'dark-console-tab-selected';
135135+ } else {
136136+ $style = 'display: none;';
137137+ $tabclass = null;
138138+ }
139139+140140+ $tabs_markup[] = javelin_render_tag(
141141+ 'a',
142142+ array(
143143+ 'class' => "dark-console-tab {$tabclass}",
144144+ 'sigil' => 'dark-console-tab',
145145+ 'meta' => array(
146146+ 'key' => $key,
147147+ ),
148148+ ),
149149+ (string)$data['name']);
150150+151151+ $panel_markup[] = javelin_render_tag(
152152+ 'div',
153153+ array(
154154+ 'class' => 'dark-console-panel',
155155+ 'style' => $style,
156156+ 'sigil' => 'dark-console-panel',
157157+ 'meta' => array(
158158+ 'key' => $key,
159159+ ),
160160+ ),
161161+ (string)$data['panel']);
162162+ }
163163+164164+ $console = javelin_render_tag(
165165+ 'table',
166166+ array(
167167+ 'class' => 'dark-console',
168168+ 'sigil' => 'dark-console',
169169+ 'meta' => array(
170170+ 'visible' => true,
171171+ ),
172172+ 'style' => '',
173173+ ),
174174+ '<tr>'.
175175+ '<th class="dark-console-tabs">'.
176176+ implode("\n", $tabs_markup).
177177+ '</th>'.
178178+ '<td>'.implode("\n", $panel_markup).'</td>'.
179179+ '</tr>');
180180+181181+ Javelin::initBehavior('dark-console');
182182+183183+ return "\n\n\n\n".$console."\n\n\n\n";
184184+ }
185185+}
186186+
+16
src/aphront/console/core/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phabricator', 'infrastructure/javelin/api');
1010+phutil_require_module('phabricator', 'infrastructure/javelin/markup');
1111+1212+phutil_require_module('phutil', 'symbols');
1313+phutil_require_module('phutil', 'utils');
1414+1515+1616+phutil_require_source('DarkConsoleCore.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+abstract class DarkConsolePlugin {
2020+2121+ private $data;
2222+ private $request;
2323+ private $core;
2424+2525+ abstract public function getName();
2626+ abstract public function getDescription();
2727+ abstract public function render();
2828+2929+ public function __construct() {
3030+3131+ }
3232+3333+ public function setConsoleCore(DarkConsoleCore $core) {
3434+ $this->core = $core;
3535+ return $this;
3636+ }
3737+3838+ public function getConsoleCore() {
3939+ return $this->core;
4040+ }
4141+4242+ public function generateData() {
4343+ return null;
4444+ }
4545+4646+ public function setData($data) {
4747+ $this->data = $data;
4848+ return $this;
4949+ }
5050+5151+ public function getData() {
5252+ return $this->data;
5353+ }
5454+5555+ public function setRequest($request) {
5656+ $this->request = $request;
5757+ return $this;
5858+ }
5959+6060+ public function getRequest() {
6161+ return $this->request;
6262+ }
6363+6464+ public function isPermanent() {
6565+ return false;
6666+ }
6767+6868+ public function shouldStartup() {
6969+ return true;
7070+ }
7171+7272+ public function didStartup() {
7373+ return null;
7474+ }
7575+7676+ public function willShutdown() {
7777+ return null;
7878+ }
7979+8080+ public function didShutdown() {
8181+ return null;
8282+ }
8383+8484+ public function processRequest() {
8585+ return null;
8686+ }
8787+8888+}
+10
src/aphront/console/plugin/base/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+1010+phutil_require_source('DarkConsolePlugin.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class DarkConsoleErrorLogPlugin extends DarkConsolePlugin {
2020+2121+ public function getName() {
2222+ $count = count($this->getData());
2323+2424+/*
2525+ if ($count) {
2626+ return
2727+ <x:frag>
2828+ <span style="color: #ff0000;">•</span> Error Log ({$count})
2929+ </x:frag>;
3030+ }
3131+3232+*/
3333+ return 'Error Log';
3434+ }
3535+3636+3737+ public function getDescription() {
3838+ return 'Shows errors and warnings.';
3939+ }
4040+4141+4242+ public function generateData() {
4343+/*
4444+ $stub = tabconsole();
4545+ if (!$stub) {
4646+ return array();
4747+ }
4848+4949+ $errors = $stub->getErrors();
5050+5151+ $data = array();
5252+ foreach ($errors as $error) {
5353+ if (is_array($error)) {
5454+ list($err, $trace) = $error;
5555+ $trace = implode("\n", $trace);
5656+ } else {
5757+ $err = $error->getMessage();
5858+ $trace = $error->getTraceAsString();
5959+ }
6060+ $data[] = array(
6161+ 'error' => $err,
6262+ 'trace' => $trace,
6363+ );
6464+ }
6565+ return $data;
6666+*/
6767+ }
6868+6969+7070+ public function render() {
7171+7272+ return '!!';
7373+/*
7474+ $data = $this->getData();
7575+ if (!$data) {
7676+ return
7777+ <x:frag>
7878+ <div class="mu">No errors.</div>
7979+ </x:frag>;
8080+ }
8181+8282+ $markup = <table class="LConsoleErrors" />;
8383+ $alt = false;
8484+ foreach ($data as $error) {
8585+ $row = <tr class={$alt ? 'alt' : null} />;
8686+8787+ $text = $error['error'];
8888+ $text = preg_replace('/\(in .* on line \d+\)$/', '', trim($text));
8989+9090+ $trace = $error['trace'];
9191+ $trace = explode("\n", $trace);
9292+ if (!$trace) {
9393+ $trace = array('unknown@0@unknown');
9494+ }
9595+9696+ foreach ($trace as $idx => $traceline) {
9797+ list($file, $line, $where) = array_merge(
9898+ explode('@', $traceline),
9999+ array('?', '?', '?'));
100100+ if ($where == 'DarkConsole->addError' ||
101101+ $where == 'debug_rlog') {
102102+ unset($trace[$idx]);
103103+ }
104104+ }
105105+106106+ $row->appendChild(<th rowspan={count($trace)}>{$text}</th>);
107107+108108+ foreach ($trace as $traceline) {
109109+ list($file, $line, $where) = array_merge(
110110+ explode('@', $traceline),
111111+ array('?', '?', '?'));
112112+ $row->appendChild(<td>{$file}:{$line}</td>);
113113+ $row->appendChild(<td>{$where}()</td>);
114114+ $markup->appendChild($row);
115115+ $row = <tr class={$alt ? 'alt' : null} />;
116116+ }
117117+118118+ $alt = !$alt;
119119+ }
120120+121121+ return
122122+ <x:frag>
123123+ <h1>Errors</h1>
124124+ <div class="LConsoleErrors">{$markup}</div>
125125+ </x:frag>;
126126+*/
127127+ }
128128+129129+}
+12
src/aphront/console/plugin/errorlog/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phabricator', 'aphront/console/plugin/base');
1010+1111+1212+phutil_require_source('DarkConsoleErrorLogPlugin.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class DarkConsoleRequestPlugin extends DarkConsolePlugin {
2020+2121+ public function getName() {
2222+ return 'Request';
2323+ }
2424+2525+ public function getDescription() {
2626+ return 'Information about $_REQUEST and $_SERVER.';
2727+ }
2828+2929+ public function generateData() {
3030+ return array(
3131+ 'Request' => $_REQUEST,
3232+ 'Server' => $_SERVER,
3333+ );
3434+ }
3535+3636+ public function render() {
3737+3838+ $data = $this->getData();
3939+4040+ $sections = array(
4141+ 'Basics' => array(
4242+ 'Host' => $data['Server']['SERVER_ADDR'],
4343+ 'Hostname' => gethostbyaddr($data['Server']['SERVER_ADDR']),
4444+ ),
4545+ );
4646+4747+ $sections = array_merge($sections, $data);
4848+4949+/*
5050+ $out = <x:frag />;
5151+ foreach ($sections as $header => $map) {
5252+ $list = <table class="LConsoleRequestDict" />;
5353+ foreach ($map as $key => $value) {
5454+ if (!is_scalar($value)) {
5555+ $value = fb_json_encode($value);
5656+ }
5757+ $value = <text wrap="80">{$value}</text>;
5858+ $list->appendChild(
5959+ <tr><th>{$key}</th><td>{$value}</td></tr>);
6060+ }
6161+ $out->appendChild(
6262+ <x:frag>
6363+ <h1>{$header}</h1>
6464+ {$list}
6565+ </x:frag>);
6666+ }
6767+6868+ return $out;
6969+*/
7070+ return "REQUEST";
7171+ }
7272+}
+12
src/aphront/console/plugin/request/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phabricator', 'aphront/console/plugin/base');
1010+1111+1212+phutil_require_source('DarkConsoleRequestPlugin.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class DarkConsoleServicesPlugin extends DarkConsolePlugin {
2020+2121+ protected $observations;
2222+2323+ public function getName() {
2424+ return 'Services';
2525+ }
2626+2727+ public function getDescription() {
2828+ return 'Information about services.';
2929+ }
3030+3131+ public function willShutdown() {
3232+// $this->observations = cacheobserver();
3333+ }
3434+3535+ public function render() {
3636+ return '!';
3737+ }
3838+}
3939+
+12
src/aphront/console/plugin/services/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phabricator', 'aphront/console/plugin/base');
1010+1111+1212+phutil_require_source('DarkConsoleServicesPlugin.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class DarkConsoleXHProfPlugin extends DarkConsolePlugin {
2020+2121+ protected $xhprofID;
2222+ protected $xhprofData;
2323+2424+ public function getName() {
2525+ $run = $this->getData();
2626+2727+ if ($run) {
2828+ return '<span style="color: #ff00ff;">•</span> XHProf';
2929+ }
3030+3131+ return 'XHProf';
3232+ }
3333+3434+ public function getDescription() {
3535+ return 'Provides detailed PHP profiling information through XHProf.';
3636+ }
3737+3838+ public function generateData() {
3939+ return $this->xhprofID;
4040+ }
4141+4242+ public function getXHProfRunID() {
4343+ return $this->xhprofID;
4444+ }
4545+4646+ public function render() {
4747+ if (!DarkConsoleXHProfPluginAPI::isProfilerAvailable()) {
4848+ return
4949+ '<p>The "xhprof" PHP extension is not available. Install xhprof '.
5050+ 'to enable the XHProf plugin.';
5151+ }
5252+5353+ return '...';
5454+ }
5555+5656+}
5757+/*
5858+5959+ public function render() {
6060+ $run = $this->getData();
6161+6262+ if ($run) {
6363+ $uri = 'http://www.intern.facebook.com/intern/phprof/?run='.$run;
6464+ return
6565+ <x:frag>
6666+ <h1>XHProf Results</h1>
6767+ <div class="XHProfPlugin">
6868+ <a href={$uri} target="_blank" class="XHProfPlugin">Permalink</a>
6969+ <iframe src={$uri} width="100%" height="600" />
7070+ </div>
7171+ </x:frag>;
7272+ }
7373+7474+ $uri = URI::getRequestURI();
7575+ return
7676+ <x:frag>
7777+ <h1>XHProf</h1>
7878+ <form action={$uri} method="get" class="EnableFeature">
7979+ <fieldset>
8080+ <legend>Enable Profiling</legend>
8181+ <p>Profiling was not enabled for this request. Click the button
8282+ below to rerun the request with profiling enabled.</p>
8383+ <button type="submit" name="_profile_" value="all"
8484+ style="margin: 2px 1em; width: 75%;">
8585+ Profile Page (With Includes)
8686+ </button>
8787+ <button type="submit" name="_profile_" value="exec"
8888+ style="margin: 2px 1em; width: 75%;">
8989+ Profile Page (No Includes)
9090+ </button>
9191+ </fieldset>
9292+ </form>
9393+ </x:frag>;
9494+ }
9595+9696+ public function willShutdown() {
9797+ if (empty($_REQUEST['_profile_']) ||
9898+ $_REQUEST['_profile_'] != 'complete') {
9999+ require_module('profiling/phprof/bootstrap');
100100+ $this->xhprofData = FB_HotProfiler::stop_hotprofiler();
101101+ }
102102+ }
103103+104104+ public function didShutdown() {
105105+ if ($this->xhprofData) {
106106+ require_module_lazy('profiling/phprof');
107107+ $this->xhprofID = phprof_save_run($this->xhprofData);
108108+ }
109109+ }
110110+111111+}
112112+*/
+13
src/aphront/console/plugin/xhprof/__init__.php
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phabricator', 'aphront/console/plugin/base');
1010+phutil_require_module('phabricator', 'aphront/console/plugin/xhprof/api');
1111+1212+1313+phutil_require_source('DarkConsoleXHProfPlugin.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+final class DarkConsoleXHProfPluginAPI {
2020+2121+ private static $profilerStarted;
2222+2323+ public static function isProfilerAvailable() {
2424+ return extension_loaded('xhprof');
2525+ }
2626+2727+ public static function includeXHProfLib() {
2828+ // TODO: this is incredibly stupid, but we may not have Phutil metamodule
2929+ // stuff loaded yet so we can't just phutil_get_library_root() our way
3030+ // to victory.
3131+ $root = __FILE__;
3232+ for ($ii = 0; $ii < 7; $ii++) {
3333+ $root = dirname($root);
3434+ }
3535+3636+ require_once $root.'/externals/xhprof/xhprof_lib.php';
3737+ }
3838+3939+ public static function hookProfiler($section) {
4040+ if (empty($_REQUEST['__profile__'])) {
4141+ return;
4242+ }
4343+4444+ if ($section != $_REQUEST['__profile__']) {
4545+ return;
4646+ }
4747+4848+ if (!self::isProfilerAvailable()) {
4949+ return;
5050+ }
5151+5252+ if (self::$profilerStarted) {
5353+ return;
5454+ }
5555+5656+ self::startProfiler();
5757+ self::$profilerStarted = true;
5858+ }
5959+6060+ public static function startProfiler() {
6161+ self::includeXHProfLib();
6262+ xhprof_enable();
6363+ }
6464+6565+ public static function stopProfiler() {
6666+ if (self::$profilerStarted) {
6767+ $data = xhprof_disable();
6868+ $data = serialize($data);
6969+ $file_class = 'PhabricatorFile';
7070+ PhutilSymbolLoader::loadClass($file_class);
7171+ $file = call_user_func(
7272+ array($file_class, 'newFromFileData'),
7373+ $data,
7474+ array(
7575+ 'mime-type' => 'application/xhprof',
7676+ 'name' => 'profile.xhprof',
7777+ ));
7878+ return $file->getPHID();
7979+ } else {
8080+ return null;
8181+ }
8282+ }
8383+8484+}
···11+<?php
22+/**
33+ * This file is automatically generated. Lint this module to rebuild it.
44+ * @generated
55+ */
66+77+88+99+phutil_require_module('phutil', 'symbols');
1010+1111+1212+phutil_require_source('DarkConsoleXHProfPluginAPI.php');
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+abstract class PhabricatorXHProfController extends PhabricatorController {
2020+2121+ public function buildStandardPageResponse($view, array $data) {
2222+ $page = $this->buildStandardPageView();
2323+2424+ $page->setApplicationName('XHProf');
2525+ $page->setBaseURI('/xhprof/');
2626+ $page->setTitle(idx($data, 'title'));
2727+ $page->setGlyph("\xE2\x98\x84");
2828+ $page->appendChild($view);
2929+3030+ $response = new AphrontWebpageResponse();
3131+ return $response->setContent($page->render());
3232+ }
3333+3434+}
···11+<?php
22+33+/*
44+ * Copyright 2011 Facebook, Inc.
55+ *
66+ * Licensed under the Apache License, Version 2.0 (the "License");
77+ * you may not use this file except in compliance with the License.
88+ * You may obtain a copy of the License at
99+ *
1010+ * http://www.apache.org/licenses/LICENSE-2.0
1111+ *
1212+ * Unless required by applicable law or agreed to in writing, software
1313+ * distributed under the License is distributed on an "AS IS" BASIS,
1414+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515+ * See the License for the specific language governing permissions and
1616+ * limitations under the License.
1717+ */
1818+1919+class PhabricatorXHProfProfileController
2020+ extends PhabricatorXHProfController {
2121+2222+ private $phid;
2323+2424+ public function willProcessRequest(array $data) {
2525+ $this->phid = $data['phid'];
2626+ }
2727+2828+ public function processRequest() {
2929+3030+ $file = id(new PhabricatorFile())->loadOneWhere(
3131+ 'phid = %s',
3232+ $this->phid);
3333+3434+ if (!$file) {
3535+ return new Aphront404Response();
3636+ }
3737+3838+ $data = $file->loadFileData();
3939+ $data = unserialize($data);
4040+ if (!$data) {
4141+ throw new Exception("Failed to unserialize XHProf profile!");
4242+ }
4343+4444+ $request = $this->getRequest();
4545+ $symbol = $request->getStr('symbol');
4646+4747+ if ($symbol) {
4848+ $view = new PhabricatorXHProfProfileSymbolView();
4949+ $view->setProfileData($data);
5050+ $view->setSymbol($symbol);
5151+ } else {
5252+ $view = new PhabricatorXHProfProfileTopLevelView();
5353+ $view->setProfileData($data);
5454+ $view->setLimit(100);
5555+ }
5656+5757+ return $this->buildStandardPageResponse(
5858+ $view,
5959+ array(
6060+ 'title' => 'Profile',
6161+ ));
6262+ }
6363+}