profiler.bpf.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. // Copyright (c) 2020 Facebook
  3. #include <vmlinux.h>
  4. #include <bpf/bpf_helpers.h>
  5. #include <bpf/bpf_tracing.h>
  6. struct bpf_perf_event_value___local {
  7. __u64 counter;
  8. __u64 enabled;
  9. __u64 running;
  10. } __attribute__((preserve_access_index));
  11. /* map of perf event fds, num_cpu * num_metric entries */
  12. struct {
  13. __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
  14. __uint(key_size, sizeof(u32));
  15. __uint(value_size, sizeof(int));
  16. } events SEC(".maps");
  17. /* readings at fentry */
  18. struct {
  19. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  20. __uint(key_size, sizeof(u32));
  21. __uint(value_size, sizeof(struct bpf_perf_event_value___local));
  22. } fentry_readings SEC(".maps");
  23. /* accumulated readings */
  24. struct {
  25. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  26. __uint(key_size, sizeof(u32));
  27. __uint(value_size, sizeof(struct bpf_perf_event_value___local));
  28. } accum_readings SEC(".maps");
  29. /* sample counts, one per cpu */
  30. struct {
  31. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  32. __uint(key_size, sizeof(u32));
  33. __uint(value_size, sizeof(u64));
  34. } counts SEC(".maps");
  35. const volatile __u32 num_cpu = 1;
  36. const volatile __u32 num_metric = 1;
  37. #define MAX_NUM_MATRICS 4
  38. SEC("fentry/XXX")
  39. int BPF_PROG(fentry_XXX)
  40. {
  41. struct bpf_perf_event_value___local *ptrs[MAX_NUM_MATRICS];
  42. u32 key = bpf_get_smp_processor_id();
  43. u32 i;
  44. /* look up before reading, to reduce error */
  45. for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) {
  46. u32 flag = i;
  47. ptrs[i] = bpf_map_lookup_elem(&fentry_readings, &flag);
  48. if (!ptrs[i])
  49. return 0;
  50. }
  51. for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) {
  52. struct bpf_perf_event_value___local reading;
  53. int err;
  54. err = bpf_perf_event_read_value(&events, key, (void *)&reading,
  55. sizeof(reading));
  56. if (err)
  57. return 0;
  58. *(ptrs[i]) = reading;
  59. key += num_cpu;
  60. }
  61. return 0;
  62. }
  63. static inline void
  64. fexit_update_maps(u32 id, struct bpf_perf_event_value___local *after)
  65. {
  66. struct bpf_perf_event_value___local *before, diff;
  67. before = bpf_map_lookup_elem(&fentry_readings, &id);
  68. /* only account samples with a valid fentry_reading */
  69. if (before && before->counter) {
  70. struct bpf_perf_event_value___local *accum;
  71. diff.counter = after->counter - before->counter;
  72. diff.enabled = after->enabled - before->enabled;
  73. diff.running = after->running - before->running;
  74. accum = bpf_map_lookup_elem(&accum_readings, &id);
  75. if (accum) {
  76. accum->counter += diff.counter;
  77. accum->enabled += diff.enabled;
  78. accum->running += diff.running;
  79. }
  80. }
  81. }
  82. SEC("fexit/XXX")
  83. int BPF_PROG(fexit_XXX)
  84. {
  85. struct bpf_perf_event_value___local readings[MAX_NUM_MATRICS];
  86. u32 cpu = bpf_get_smp_processor_id();
  87. u32 i, zero = 0;
  88. int err;
  89. u64 *count;
  90. /* read all events before updating the maps, to reduce error */
  91. for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) {
  92. err = bpf_perf_event_read_value(&events, cpu + i * num_cpu,
  93. (void *)(readings + i),
  94. sizeof(*readings));
  95. if (err)
  96. return 0;
  97. }
  98. count = bpf_map_lookup_elem(&counts, &zero);
  99. if (count) {
  100. *count += 1;
  101. for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++)
  102. fexit_update_maps(i, &readings[i]);
  103. }
  104. return 0;
  105. }
  106. char LICENSE[] SEC("license") = "Dual BSD/GPL";