stacksnoop.php 1.9 KB

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