hists_filter.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include "perf.h"
  2. #include "util/debug.h"
  3. #include "util/symbol.h"
  4. #include "util/sort.h"
  5. #include "util/evsel.h"
  6. #include "util/evlist.h"
  7. #include "util/machine.h"
  8. #include "util/thread.h"
  9. #include "util/parse-events.h"
  10. #include "tests/tests.h"
  11. #include "tests/hists_common.h"
  12. struct sample {
  13. u32 pid;
  14. u64 ip;
  15. struct thread *thread;
  16. struct map *map;
  17. struct symbol *sym;
  18. int socket;
  19. };
  20. /* For the numbers, see hists_common.c */
  21. static struct sample fake_samples[] = {
  22. /* perf [kernel] schedule() */
  23. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, .socket = 0 },
  24. /* perf [perf] main() */
  25. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, .socket = 0 },
  26. /* perf [libc] malloc() */
  27. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, .socket = 0 },
  28. /* perf [perf] main() */
  29. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, .socket = 0 }, /* will be merged */
  30. /* perf [perf] cmd_record() */
  31. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, .socket = 1 },
  32. /* perf [kernel] page_fault() */
  33. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 1 },
  34. /* bash [bash] main() */
  35. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, .socket = 2 },
  36. /* bash [bash] xmalloc() */
  37. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, .socket = 2 },
  38. /* bash [libc] malloc() */
  39. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, .socket = 3 },
  40. /* bash [kernel] page_fault() */
  41. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 3 },
  42. };
  43. static int add_hist_entries(struct perf_evlist *evlist,
  44. struct machine *machine)
  45. {
  46. struct perf_evsel *evsel;
  47. struct addr_location al;
  48. struct perf_sample sample = { .period = 100, };
  49. size_t i;
  50. /*
  51. * each evsel will have 10 samples but the 4th sample
  52. * (perf [perf] main) will be collapsed to an existing entry
  53. * so total 9 entries will be in the tree.
  54. */
  55. evlist__for_each(evlist, evsel) {
  56. for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
  57. const union perf_event event = {
  58. .header = {
  59. .misc = PERF_RECORD_MISC_USER,
  60. },
  61. };
  62. struct hist_entry_iter iter = {
  63. .evsel = evsel,
  64. .sample = &sample,
  65. .ops = &hist_iter_normal,
  66. .hide_unresolved = false,
  67. };
  68. struct hists *hists = evsel__hists(evsel);
  69. /* make sure it has no filter at first */
  70. hists->thread_filter = NULL;
  71. hists->dso_filter = NULL;
  72. hists->symbol_filter_str = NULL;
  73. sample.pid = fake_samples[i].pid;
  74. sample.tid = fake_samples[i].pid;
  75. sample.ip = fake_samples[i].ip;
  76. if (perf_event__preprocess_sample(&event, machine, &al,
  77. &sample) < 0)
  78. goto out;
  79. al.socket = fake_samples[i].socket;
  80. if (hist_entry_iter__add(&iter, &al,
  81. PERF_MAX_STACK_DEPTH, NULL) < 0) {
  82. addr_location__put(&al);
  83. goto out;
  84. }
  85. fake_samples[i].thread = al.thread;
  86. fake_samples[i].map = al.map;
  87. fake_samples[i].sym = al.sym;
  88. }
  89. }
  90. return 0;
  91. out:
  92. pr_debug("Not enough memory for adding a hist entry\n");
  93. return TEST_FAIL;
  94. }
  95. int test__hists_filter(void)
  96. {
  97. int err = TEST_FAIL;
  98. struct machines machines;
  99. struct machine *machine;
  100. struct perf_evsel *evsel;
  101. struct perf_evlist *evlist = perf_evlist__new();
  102. TEST_ASSERT_VAL("No memory", evlist);
  103. err = parse_events(evlist, "cpu-clock", NULL);
  104. if (err)
  105. goto out;
  106. err = parse_events(evlist, "task-clock", NULL);
  107. if (err)
  108. goto out;
  109. /* default sort order (comm,dso,sym) will be used */
  110. if (setup_sorting() < 0)
  111. goto out;
  112. machines__init(&machines);
  113. /* setup threads/dso/map/symbols also */
  114. machine = setup_fake_machine(&machines);
  115. if (!machine)
  116. goto out;
  117. if (verbose > 1)
  118. machine__fprintf(machine, stderr);
  119. /* process sample events */
  120. err = add_hist_entries(evlist, machine);
  121. if (err < 0)
  122. goto out;
  123. evlist__for_each(evlist, evsel) {
  124. struct hists *hists = evsel__hists(evsel);
  125. hists__collapse_resort(hists, NULL);
  126. hists__output_resort(hists, NULL);
  127. if (verbose > 2) {
  128. pr_info("Normal histogram\n");
  129. print_hists_out(hists);
  130. }
  131. TEST_ASSERT_VAL("Invalid nr samples",
  132. hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
  133. TEST_ASSERT_VAL("Invalid nr hist entries",
  134. hists->nr_entries == 9);
  135. TEST_ASSERT_VAL("Invalid total period",
  136. hists->stats.total_period == 1000);
  137. TEST_ASSERT_VAL("Unmatched nr samples",
  138. hists->stats.nr_events[PERF_RECORD_SAMPLE] ==
  139. hists->stats.nr_non_filtered_samples);
  140. TEST_ASSERT_VAL("Unmatched nr hist entries",
  141. hists->nr_entries == hists->nr_non_filtered_entries);
  142. TEST_ASSERT_VAL("Unmatched total period",
  143. hists->stats.total_period ==
  144. hists->stats.total_non_filtered_period);
  145. /* now applying thread filter for 'bash' */
  146. hists->thread_filter = fake_samples[9].thread;
  147. hists__filter_by_thread(hists);
  148. if (verbose > 2) {
  149. pr_info("Histogram for thread filter\n");
  150. print_hists_out(hists);
  151. }
  152. /* normal stats should be invariant */
  153. TEST_ASSERT_VAL("Invalid nr samples",
  154. hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
  155. TEST_ASSERT_VAL("Invalid nr hist entries",
  156. hists->nr_entries == 9);
  157. TEST_ASSERT_VAL("Invalid total period",
  158. hists->stats.total_period == 1000);
  159. /* but filter stats are changed */
  160. TEST_ASSERT_VAL("Unmatched nr samples for thread filter",
  161. hists->stats.nr_non_filtered_samples == 4);
  162. TEST_ASSERT_VAL("Unmatched nr hist entries for thread filter",
  163. hists->nr_non_filtered_entries == 4);
  164. TEST_ASSERT_VAL("Unmatched total period for thread filter",
  165. hists->stats.total_non_filtered_period == 400);
  166. /* remove thread filter first */
  167. hists->thread_filter = NULL;
  168. hists__filter_by_thread(hists);
  169. /* now applying dso filter for 'kernel' */
  170. hists->dso_filter = fake_samples[0].map->dso;
  171. hists__filter_by_dso(hists);
  172. if (verbose > 2) {
  173. pr_info("Histogram for dso filter\n");
  174. print_hists_out(hists);
  175. }
  176. /* normal stats should be invariant */
  177. TEST_ASSERT_VAL("Invalid nr samples",
  178. hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
  179. TEST_ASSERT_VAL("Invalid nr hist entries",
  180. hists->nr_entries == 9);
  181. TEST_ASSERT_VAL("Invalid total period",
  182. hists->stats.total_period == 1000);
  183. /* but filter stats are changed */
  184. TEST_ASSERT_VAL("Unmatched nr samples for dso filter",
  185. hists->stats.nr_non_filtered_samples == 3);
  186. TEST_ASSERT_VAL("Unmatched nr hist entries for dso filter",
  187. hists->nr_non_filtered_entries == 3);
  188. TEST_ASSERT_VAL("Unmatched total period for dso filter",
  189. hists->stats.total_non_filtered_period == 300);
  190. /* remove dso filter first */
  191. hists->dso_filter = NULL;
  192. hists__filter_by_dso(hists);
  193. /*
  194. * now applying symbol filter for 'main'. Also note that
  195. * there's 3 samples that have 'main' symbol but the 4th
  196. * entry of fake_samples was collapsed already so it won't
  197. * be counted as a separate entry but the sample count and
  198. * total period will be remained.
  199. */
  200. hists->symbol_filter_str = "main";
  201. hists__filter_by_symbol(hists);
  202. if (verbose > 2) {
  203. pr_info("Histogram for symbol filter\n");
  204. print_hists_out(hists);
  205. }
  206. /* normal stats should be invariant */
  207. TEST_ASSERT_VAL("Invalid nr samples",
  208. hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
  209. TEST_ASSERT_VAL("Invalid nr hist entries",
  210. hists->nr_entries == 9);
  211. TEST_ASSERT_VAL("Invalid total period",
  212. hists->stats.total_period == 1000);
  213. /* but filter stats are changed */
  214. TEST_ASSERT_VAL("Unmatched nr samples for symbol filter",
  215. hists->stats.nr_non_filtered_samples == 3);
  216. TEST_ASSERT_VAL("Unmatched nr hist entries for symbol filter",
  217. hists->nr_non_filtered_entries == 2);
  218. TEST_ASSERT_VAL("Unmatched total period for symbol filter",
  219. hists->stats.total_non_filtered_period == 300);
  220. /* remove symbol filter first */
  221. hists->symbol_filter_str = NULL;
  222. hists__filter_by_symbol(hists);
  223. /* now applying socket filters */
  224. hists->socket_filter = 2;
  225. hists__filter_by_socket(hists);
  226. if (verbose > 2) {
  227. pr_info("Histogram for socket filters\n");
  228. print_hists_out(hists);
  229. }
  230. /* normal stats should be invariant */
  231. TEST_ASSERT_VAL("Invalid nr samples",
  232. hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
  233. TEST_ASSERT_VAL("Invalid nr hist entries",
  234. hists->nr_entries == 9);
  235. TEST_ASSERT_VAL("Invalid total period",
  236. hists->stats.total_period == 1000);
  237. /* but filter stats are changed */
  238. TEST_ASSERT_VAL("Unmatched nr samples for socket filter",
  239. hists->stats.nr_non_filtered_samples == 2);
  240. TEST_ASSERT_VAL("Unmatched nr hist entries for socket filter",
  241. hists->nr_non_filtered_entries == 2);
  242. TEST_ASSERT_VAL("Unmatched total period for socket filter",
  243. hists->stats.total_non_filtered_period == 200);
  244. /* remove socket filter first */
  245. hists->socket_filter = -1;
  246. hists__filter_by_socket(hists);
  247. /* now applying all filters at once. */
  248. hists->thread_filter = fake_samples[1].thread;
  249. hists->dso_filter = fake_samples[1].map->dso;
  250. hists__filter_by_thread(hists);
  251. hists__filter_by_dso(hists);
  252. if (verbose > 2) {
  253. pr_info("Histogram for all filters\n");
  254. print_hists_out(hists);
  255. }
  256. /* normal stats should be invariant */
  257. TEST_ASSERT_VAL("Invalid nr samples",
  258. hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
  259. TEST_ASSERT_VAL("Invalid nr hist entries",
  260. hists->nr_entries == 9);
  261. TEST_ASSERT_VAL("Invalid total period",
  262. hists->stats.total_period == 1000);
  263. /* but filter stats are changed */
  264. TEST_ASSERT_VAL("Unmatched nr samples for all filter",
  265. hists->stats.nr_non_filtered_samples == 2);
  266. TEST_ASSERT_VAL("Unmatched nr hist entries for all filter",
  267. hists->nr_non_filtered_entries == 1);
  268. TEST_ASSERT_VAL("Unmatched total period for all filter",
  269. hists->stats.total_non_filtered_period == 200);
  270. }
  271. err = TEST_OK;
  272. out:
  273. /* tear down everything */
  274. perf_evlist__delete(evlist);
  275. reset_output_field();
  276. machines__exit(&machines);
  277. return err;
  278. }