summaryrefslogtreecommitdiffstats
path: root/contrib/tools/flame-graph/stackcollapse-xdebug.php
diff options
context:
space:
mode:
authormfilitov <[email protected]>2024-08-23 13:23:47 +0300
committermfilitov <[email protected]>2024-08-23 13:38:30 +0300
commit5741cf990d59e786aee8074fc01db7655490bcfd (patch)
tree7161f63ec7c981a5547c63001dcb6c3fe66d9dcf /contrib/tools/flame-graph/stackcollapse-xdebug.php
parent10ac4b53185c5638e7dae756765beb5f60019451 (diff)
Try adding flamegraph with simple copy
6d3bfb2f6ddb8ad122ad37485ce2d0ac8346e0ee
Diffstat (limited to 'contrib/tools/flame-graph/stackcollapse-xdebug.php')
-rwxr-xr-xcontrib/tools/flame-graph/stackcollapse-xdebug.php197
1 files changed, 197 insertions, 0 deletions
diff --git a/contrib/tools/flame-graph/stackcollapse-xdebug.php b/contrib/tools/flame-graph/stackcollapse-xdebug.php
new file mode 100755
index 00000000000..6548903db97
--- /dev/null
+++ b/contrib/tools/flame-graph/stackcollapse-xdebug.php
@@ -0,0 +1,197 @@
+#!/usr/bin/php
+#
+# Copyright 2018 Miriam Lauter ([email protected]). All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# (http://www.gnu.org/copyleft/gpl.html)
+#
+# 13-Apr-2018 Miriam Lauter Created this.
+
+<?php
+ini_set('error_log', null);
+$optind = null;
+$args = getopt("htc", ["help"], $optind);
+if (isset($args['h']) || isset($args['help'])) {
+ usage();
+}
+
+function usage($exit = 0) {
+ echo <<<EOT
+stackcollapse-php.php collapse php function traces into single lines.
+
+Parses php samples generated by xdebug with xdebug.trace_format = 1
+and outputs stacks as single lines, with methods separated by semicolons,
+and then a space and an occurrence count. For use with flamegraph.pl.
+See https://github.com/brendangregg/FlameGraph.
+
+USAGE: ./stackcollapse-php.php [OPTIONS] infile > outfile
+ -h --help Show this message
+ -t Weight stack counts by duration using the time index in the trace (default)
+ -c Invocation counts only. Simply count stacks in the trace and sum duplicates, don't weight by duration.
+
+Example input:
+For more info on xdebug and generating traces see
+https://xdebug.org/docs/execution_trace.
+
+Version: 2.0.0RC4-dev
+TRACE START [2007-05-06 18:29:01]
+1 0 0 0.010870 114112 {main} 1 ../trace.php 0
+2 1 0 0.032009 114272 str_split 0 ../trace.php 8
+2 1 1 0.032073 116632
+2 2 0 0.033505 117424 ret_ord 1 ../trace.php 10
+3 3 0 0.033531 117584 ord 0 ../trace.php 5
+3 3 1 0.033551 117584
+...
+TRACE END [2007-05-06 18:29:01]
+
+Example output:
+
+- c
+{main};str_split 1
+{main};ret_ord;ord 6
+
+-t
+{main} 23381
+{main};str_split 64
+{main};ret_ord 215
+{main};ret_ord;ord 106
+
+EOT;
+
+ exit($exit);
+}
+
+function collapseStack(array $stack, string $func_name_key): string {
+ return implode(';', array_column($stack, $func_name_key));
+}
+
+function addCurrentStackToStacks(array $stack, float $dur, array &$stacks) {
+ $collapsed = implode(';', $stack);
+ $duration = SCALE_FACTOR * $dur;
+
+ if (array_key_exists($collapsed, $stacks)) {
+ $stacks[$collapsed] += $duration;
+ } else {
+ $stacks[$collapsed] = $duration;
+ }
+}
+
+function isEOTrace(string $l) {
+ $pattern = "/^(\\t|TRACE END)/";
+ return preg_match($pattern, $l);
+}
+
+$filename = $argv[$optind] ?? null;
+if ($filename === null) {
+ usage(1);
+}
+
+$do_time = !isset($args['c']);
+
+// First make sure our file is consistently formatted with only one \t delimiting each field
+$out = [];
+$retval = null;
+exec("sed -in 's/\t\+/\t/g' " . escapeshellarg($filename), $out, $retval);
+if ($retval !== 0) {
+ usage(1);
+}
+
+$handle = fopen($filename, 'r');
+
+if ($handle === false) {
+ echo "Unable to open $filename \n\n";
+ usage(1);
+}
+
+// Loop till we find TRACE START
+while ($l = fgets($handle)) {
+ if (strpos($l, "TRACE START") === 0) {
+ break;
+ }
+}
+
+const SCALE_FACTOR = 1000000;
+$stacks = [];
+$current_stack = [];
+$was_exit = false;
+$prev_start_time = 0;
+
+if ($do_time) {
+ // Weight counts by duration
+ // Xdebug trace time indices have 6 sigfigs of precision
+ // We have a perfect trace, but let's instead pretend that
+ // this was collected by sampling at 10^6 Hz
+ // then each millionth of a second this stack took to execute is 1 count
+ while ($l = fgets($handle)) {
+ if (isEOTrace($l)) {
+ break;
+ }
+
+ $parts = explode("\t", $l);
+ list($level, $fn_no, $is_exit, $time) = $parts;
+
+ if ($is_exit) {
+ if (empty($current_stack)) {
+ echo "[WARNING] Found function exit without corresponding entrance. Discarding line. Check your input.\n";
+ continue;
+ }
+
+ addCurrentStackToStacks($current_stack, $time - $prev_start_time, $stacks);
+ array_pop($current_stack);
+ } else {
+ $func_name = $parts[5];
+
+ if (!empty($current_stack)) {
+ addCurrentStackToStacks($current_stack, $time - $prev_start_time, $stacks);
+ }
+
+ $current_stack[] = $func_name;
+ }
+ $prev_start_time = $time;
+ }
+} else {
+ // Counts only
+ while ($l = fgets($handle)) {
+ if (isEOTrace($l)) {
+ break;
+ }
+
+ $parts = explode("\t", $l);
+ list($level, $fn_no, $is_exit) = $parts;
+
+ if ($is_exit === "1") {
+ if (!$was_exit) {
+ $collapsed = implode(";", $current_stack);
+ if (array_key_exists($collapsed, $stacks)) {
+ $stacks[$collapsed]++;
+ } else {
+ $stacks[$collapsed] = 1;
+ }
+ }
+
+ array_pop($current_stack);
+ $was_exit = true;
+ } else {
+ $func_name = $parts[5];
+ $current_stack[] = $func_name;
+ $was_exit = false;
+ }
+ }
+}
+
+foreach ($stacks as $stack => $count) {
+ echo "$stack $count\n";
+}