sampleip_user.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * sampleip: sample instruction pointer and frequency count in a BPF map.
  4. *
  5. * Copyright 2016 Netflix, Inc.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <signal.h>
  12. #include <string.h>
  13. #include <linux/perf_event.h>
  14. #include <linux/ptrace.h>
  15. #include <linux/bpf.h>
  16. #include <bpf/bpf.h>
  17. #include <bpf/libbpf.h>
  18. #include "perf-sys.h"
  19. #include "trace_helpers.h"
  20. #define DEFAULT_FREQ 99
  21. #define DEFAULT_SECS 5
  22. #define MAX_IPS 8192
  23. #define PAGE_OFFSET 0xffff880000000000
  24. static int map_fd;
  25. static int nr_cpus;
  26. static void usage(void)
  27. {
  28. printf("USAGE: sampleip [-F freq] [duration]\n");
  29. printf(" -F freq # sample frequency (Hertz), default 99\n");
  30. printf(" duration # sampling duration (seconds), default 5\n");
  31. }
  32. static int sampling_start(int freq, struct bpf_program *prog,
  33. struct bpf_link *links[])
  34. {
  35. int i, pmu_fd;
  36. struct perf_event_attr pe_sample_attr = {
  37. .type = PERF_TYPE_SOFTWARE,
  38. .freq = 1,
  39. .sample_period = freq,
  40. .config = PERF_COUNT_SW_CPU_CLOCK,
  41. .inherit = 1,
  42. };
  43. for (i = 0; i < nr_cpus; i++) {
  44. pmu_fd = sys_perf_event_open(&pe_sample_attr, -1 /* pid */, i,
  45. -1 /* group_fd */, 0 /* flags */);
  46. if (pmu_fd < 0) {
  47. fprintf(stderr, "ERROR: Initializing perf sampling\n");
  48. return 1;
  49. }
  50. links[i] = bpf_program__attach_perf_event(prog, pmu_fd);
  51. if (libbpf_get_error(links[i])) {
  52. fprintf(stderr, "ERROR: Attach perf event\n");
  53. links[i] = NULL;
  54. close(pmu_fd);
  55. return 1;
  56. }
  57. }
  58. return 0;
  59. }
  60. static void sampling_end(struct bpf_link *links[])
  61. {
  62. int i;
  63. for (i = 0; i < nr_cpus; i++)
  64. bpf_link__destroy(links[i]);
  65. }
  66. struct ipcount {
  67. __u64 ip;
  68. __u32 count;
  69. };
  70. /* used for sorting */
  71. struct ipcount counts[MAX_IPS];
  72. static int count_cmp(const void *p1, const void *p2)
  73. {
  74. return ((struct ipcount *)p1)->count - ((struct ipcount *)p2)->count;
  75. }
  76. static void print_ip_map(int fd)
  77. {
  78. struct ksym *sym;
  79. __u64 key, next_key;
  80. __u32 value;
  81. int i, max;
  82. printf("%-19s %-32s %s\n", "ADDR", "KSYM", "COUNT");
  83. /* fetch IPs and counts */
  84. key = 0, i = 0;
  85. while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
  86. bpf_map_lookup_elem(fd, &next_key, &value);
  87. counts[i].ip = next_key;
  88. counts[i++].count = value;
  89. key = next_key;
  90. }
  91. max = i;
  92. /* sort and print */
  93. qsort(counts, max, sizeof(struct ipcount), count_cmp);
  94. for (i = 0; i < max; i++) {
  95. if (counts[i].ip > PAGE_OFFSET) {
  96. sym = ksym_search(counts[i].ip);
  97. if (!sym) {
  98. printf("ksym not found. Is kallsyms loaded?\n");
  99. continue;
  100. }
  101. printf("0x%-17llx %-32s %u\n", counts[i].ip, sym->name,
  102. counts[i].count);
  103. } else {
  104. printf("0x%-17llx %-32s %u\n", counts[i].ip, "(user)",
  105. counts[i].count);
  106. }
  107. }
  108. if (max == MAX_IPS) {
  109. printf("WARNING: IP hash was full (max %d entries); ", max);
  110. printf("may have dropped samples\n");
  111. }
  112. }
  113. static void int_exit(int sig)
  114. {
  115. printf("\n");
  116. print_ip_map(map_fd);
  117. exit(0);
  118. }
  119. int main(int argc, char **argv)
  120. {
  121. int opt, freq = DEFAULT_FREQ, secs = DEFAULT_SECS, error = 1;
  122. struct bpf_object *obj = NULL;
  123. struct bpf_program *prog;
  124. struct bpf_link **links;
  125. char filename[256];
  126. /* process arguments */
  127. while ((opt = getopt(argc, argv, "F:h")) != -1) {
  128. switch (opt) {
  129. case 'F':
  130. freq = atoi(optarg);
  131. break;
  132. case 'h':
  133. default:
  134. usage();
  135. return 0;
  136. }
  137. }
  138. if (argc - optind == 1)
  139. secs = atoi(argv[optind]);
  140. if (freq == 0 || secs == 0) {
  141. usage();
  142. return 1;
  143. }
  144. /* initialize kernel symbol translation */
  145. if (load_kallsyms()) {
  146. fprintf(stderr, "ERROR: loading /proc/kallsyms\n");
  147. return 2;
  148. }
  149. /* create perf FDs for each CPU */
  150. nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  151. links = calloc(nr_cpus, sizeof(struct bpf_link *));
  152. if (!links) {
  153. fprintf(stderr, "ERROR: malloc of links\n");
  154. goto cleanup;
  155. }
  156. snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
  157. obj = bpf_object__open_file(filename, NULL);
  158. if (libbpf_get_error(obj)) {
  159. fprintf(stderr, "ERROR: opening BPF object file failed\n");
  160. obj = NULL;
  161. goto cleanup;
  162. }
  163. prog = bpf_object__find_program_by_name(obj, "do_sample");
  164. if (!prog) {
  165. fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
  166. goto cleanup;
  167. }
  168. /* load BPF program */
  169. if (bpf_object__load(obj)) {
  170. fprintf(stderr, "ERROR: loading BPF object file failed\n");
  171. goto cleanup;
  172. }
  173. map_fd = bpf_object__find_map_fd_by_name(obj, "ip_map");
  174. if (map_fd < 0) {
  175. fprintf(stderr, "ERROR: finding a map in obj file failed\n");
  176. goto cleanup;
  177. }
  178. signal(SIGINT, int_exit);
  179. signal(SIGTERM, int_exit);
  180. /* do sampling */
  181. printf("Sampling at %d Hertz for %d seconds. Ctrl-C also ends.\n",
  182. freq, secs);
  183. if (sampling_start(freq, prog, links) != 0)
  184. goto cleanup;
  185. sleep(secs);
  186. error = 0;
  187. cleanup:
  188. sampling_end(links);
  189. /* output sample counts */
  190. if (!error)
  191. print_ip_map(map_fd);
  192. free(links);
  193. bpf_object__close(obj);
  194. return error;
  195. }