stacksnoop.php 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <?php
  2. if ($argc < 2) {
  3. echo "USAGE: php stacksnoop.php [-p PID] [-s] [-v] function_name\n";
  4. exit(1);
  5. }
  6. $function = end($argv) ?? null;
  7. $pid = null;
  8. $offset = false;
  9. $verbose = false;
  10. for ($i = 1; $i < $argc; $i++) {
  11. $arg = $argv[$i];
  12. if ($arg === "-p" && isset($argv[$i + 1])) {
  13. $pid = $argv[++$i];
  14. } elseif ($arg === "-s") {
  15. $offset = true;
  16. } elseif ($arg === "-v") {
  17. $verbose = true;
  18. } else {
  19. $function = $arg;
  20. }
  21. }
  22. if (!$function) {
  23. echo "USAGE: php stacksnoop.php [-p PID] [-s] [-v] function_name\n";
  24. exit(1);
  25. }
  26. $filter = $pid ? "if (pid != $pid) { return; }" : "";
  27. $prog = <<<EOT
  28. #include <uapi/linux/ptrace.h>
  29. #include <linux/sched.h>
  30. struct data_t {
  31. u64 stack_id;
  32. u32 pid;
  33. char comm[TASK_COMM_LEN];
  34. };
  35. BPF_STACK_TRACE(stack_traces, 128);
  36. BPF_PERF_OUTPUT(events);
  37. void trace_stack(struct pt_regs *ctx) {
  38. u32 pid = bpf_get_current_pid_tgid() >> 32;
  39. $filter
  40. struct data_t data = {};
  41. data.stack_id = stack_traces.get_stackid(ctx, 0);
  42. data.pid = pid;
  43. bpf_get_current_comm(&data.comm, sizeof(data.comm));
  44. events.perf_submit(ctx, &data, sizeof(data));
  45. }
  46. EOT;
  47. $b = new Bpf(["text" => $prog]);
  48. $b->attach_kprobe($function, "trace_stack");
  49. $stack_traces = $b->get_table("stack_traces");
  50. $start_ts = microtime(true);
  51. if ($verbose) {
  52. printf("%-18s %-12s %-6s %-3s %s\n", "TIME(s)", "COMM", "PID", "CPU", "FUNCTION");
  53. } else {
  54. printf("%-18s %s\n", "TIME(s)", "FUNCTION");
  55. }
  56. function print_event($cpu, $data, $size) {
  57. global $b, $function, $offset, $verbose, $start_ts, $stack_traces;
  58. $event = unpack("Qstack_id/Lpid/A16comm", $data);
  59. $ts = microtime(true) - $start_ts;
  60. if ($verbose) {
  61. printf("%-18.9f %-12s %-6d %-3d %s\n", $ts, $event["comm"], $event["pid"], $cpu, $function);
  62. } else {
  63. printf("%-18.9f %s\n", $ts, $function);
  64. }
  65. foreach ($stack_traces->values($event['stack_id']) as $fn) {
  66. echo "\t$fn".PHP_EOL;
  67. }
  68. echo PHP_EOL;
  69. }
  70. $b->events->open_perf_buffer("print_event");
  71. while (true) {
  72. try {
  73. $b->perf_buffer_poll();
  74. } catch (Exception $e) {
  75. exit();
  76. }
  77. }