biolatpcts.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. $bpf_source = <<<EOT
  3. #include <linux/blkdev.h>
  4. #include <linux/time64.h>
  5. BPF_PERCPU_ARRAY(lat_100ms, u64, 100);
  6. BPF_PERCPU_ARRAY(lat_1ms, u64, 100);
  7. BPF_PERCPU_ARRAY(lat_10us, u64, 100);
  8. RAW_TRACEPOINT_PROBE(block_rq_complete)
  9. {
  10. // TP_PROTO(struct request *rq, blk_status_t error, unsigned int nr_bytes)
  11. struct request *rq = (void *)ctx->args[0];
  12. unsigned int cmd_flags;
  13. u64 dur;
  14. size_t base, slot;
  15. if (!rq->io_start_time_ns)
  16. return 0;
  17. dur = bpf_ktime_get_ns() - rq->io_start_time_ns;
  18. slot = min_t(size_t, div_u64(dur, 100 * NSEC_PER_MSEC), 99);
  19. lat_100ms.increment(slot);
  20. if (slot)
  21. return 0;
  22. slot = min_t(size_t, div_u64(dur, NSEC_PER_MSEC), 99);
  23. lat_1ms.increment(slot);
  24. if (slot)
  25. return 0;
  26. slot = min_t(size_t, div_u64(dur, 10 * NSEC_PER_USEC), 99);
  27. lat_10us.increment(slot);
  28. return 0;
  29. }
  30. EOT;
  31. $ebpf = new Ebpf($bpf_source);
  32. $cur_lat_100ms = $ebpf->lat_100ms;
  33. $cur_lat_1ms =$ebpf->lat_1ms;
  34. $cur_lat_10us = $ebpf->lat_10us;
  35. $last_lat_100ms = array_fill(0, 100, 0);
  36. $last_lat_1ms = array_fill(0, 100, 0);
  37. $last_lat_10us = array_fill(0, 100, 0);
  38. $lat_100ms = array_fill(0, 100, 0);
  39. $lat_1ms = array_fill(0, 100, 0);
  40. $lat_10us = array_fill(0, 100, 0);
  41. function find_pct($req, $total, &$slots, $idx, $counted) {
  42. while ($idx > 0) {
  43. $idx--;
  44. if ($slots[$idx] > 0) {
  45. $counted += $slots[$idx];
  46. if (($counted / $total) * 100 >= 100 - $req) {
  47. break;
  48. }
  49. }
  50. }
  51. return [$idx, $counted];
  52. }
  53. function calc_lat_pct($req_pcts, $total, &$lat_100ms, &$lat_1ms, &$lat_10us) {
  54. $pcts = array_fill(0, count($req_pcts), 0);
  55. if ($total == 0) {
  56. return $pcts;
  57. }
  58. $data = [[100 * 1000, &$lat_100ms], [1000, &$lat_1ms], [10, &$lat_10us]];
  59. $data_sel = 0;
  60. $idx = 100;
  61. $counted = 0;
  62. for ($pct_idx = count($req_pcts) - 1; $pct_idx >= 0; $pct_idx--) {
  63. $req = floatval($req_pcts[$pct_idx]);
  64. while (true) {
  65. $last_counted = $counted;
  66. [$gran, $slots] = $data[$data_sel];
  67. [$idx, $counted] = find_pct($req, $total, $slots, $idx, $counted);
  68. if ($idx > 0 || $data_sel == count($data) - 1) {
  69. break;
  70. }
  71. $counted = $last_counted;
  72. $data_sel++;
  73. $idx = 100;
  74. }
  75. $pcts[$pct_idx] = $gran * $idx + $gran / 2;
  76. }
  77. return $pcts;
  78. }
  79. echo "Block I/O latency percentile example.\n";
  80. while (true) {
  81. sleep(3);
  82. $lat_total = 0;
  83. for ($i = 0; $i < 100; $i++) {
  84. $v = $cur_lat_100ms->sum_value($i);
  85. $lat_100ms[$i] = max($v - $last_lat_100ms[$i], 0);
  86. $last_lat_100ms[$i] = $v;
  87. $v = $cur_lat_1ms->sum_value($i);
  88. $lat_1ms[$i] = max($v - $last_lat_1ms[$i], 0);
  89. $last_lat_1ms[$i] = $v;
  90. $v = $cur_lat_10us->sum_value($i);
  91. $lat_10us[$i] = max($v - $last_lat_10us[$i], 0);
  92. $last_lat_10us[$i] = $v;
  93. $lat_total += $lat_100ms[$i];
  94. }
  95. $target_pcts = [50, 75, 90, 99];
  96. $pcts = calc_lat_pct($target_pcts, $lat_total, $lat_100ms, $lat_1ms, $lat_10us);
  97. for ($i = 0; $i < count($target_pcts); $i++) {
  98. echo "p" . $target_pcts[$i] . "=" . intval($pcts[$i]) . "us ";
  99. }
  100. echo PHP_EOL;
  101. }