~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/tests/hists_link.c

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include "perf.h"
  3 #include "tests.h"
  4 #include "debug.h"
  5 #include "symbol.h"
  6 #include "sort.h"
  7 #include "evsel.h"
  8 #include "evlist.h"
  9 #include "machine.h"
 10 #include "thread.h"
 11 #include "parse-events.h"
 12 #include "hists_common.h"
 13 #include <errno.h>
 14 #include <linux/kernel.h>
 15 
 16 struct sample {
 17         u32 pid;
 18         u64 ip;
 19         struct thread *thread;
 20         struct map *map;
 21         struct symbol *sym;
 22 };
 23 
 24 /* For the numbers, see hists_common.c */
 25 static struct sample fake_common_samples[] = {
 26         /* perf [kernel] schedule() */
 27         { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
 28         /* perf [perf]   main() */
 29         { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
 30         /* perf [perf]   cmd_record() */
 31         { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
 32         /* bash [bash]   xmalloc() */
 33         { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_XMALLOC, },
 34         /* bash [libc]   malloc() */
 35         { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_LIBC_MALLOC, },
 36 };
 37 
 38 static struct sample fake_samples[][5] = {
 39         {
 40                 /* perf [perf]   run_command() */
 41                 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_RUN_COMMAND, },
 42                 /* perf [libc]   malloc() */
 43                 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
 44                 /* perf [kernel] page_fault() */
 45                 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
 46                 /* perf [kernel] sys_perf_event_open() */
 47                 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN, },
 48                 /* bash [libc]   free() */
 49                 { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_LIBC_FREE, },
 50         },
 51         {
 52                 /* perf [libc]   free() */
 53                 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_LIBC_FREE, },
 54                 /* bash [libc]   malloc() */
 55                 { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_LIBC_MALLOC, }, /* will be merged */
 56                 /* bash [bash]   xfee() */
 57                 { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_XFREE, },
 58                 /* bash [libc]   realloc() */
 59                 { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_LIBC_REALLOC, },
 60                 /* bash [kernel] page_fault() */
 61                 { .pid = FAKE_PID_BASH,  .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
 62         },
 63 };
 64 
 65 static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
 66 {
 67         struct perf_evsel *evsel;
 68         struct addr_location al;
 69         struct hist_entry *he;
 70         struct perf_sample sample = { .period = 1, .weight = 1, };
 71         size_t i = 0, k;
 72 
 73         /*
 74          * each evsel will have 10 samples - 5 common and 5 distinct.
 75          * However the second evsel also has a collapsed entry for
 76          * "bash [libc] malloc" so total 9 entries will be in the tree.
 77          */
 78         evlist__for_each_entry(evlist, evsel) {
 79                 struct hists *hists = evsel__hists(evsel);
 80 
 81                 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
 82                         sample.cpumode = PERF_RECORD_MISC_USER;
 83                         sample.pid = fake_common_samples[k].pid;
 84                         sample.tid = fake_common_samples[k].pid;
 85                         sample.ip = fake_common_samples[k].ip;
 86 
 87                         if (machine__resolve(machine, &al, &sample) < 0)
 88                                 goto out;
 89 
 90                         he = hists__add_entry(hists, &al, NULL,
 91                                                 NULL, NULL, &sample, true);
 92                         if (he == NULL) {
 93                                 addr_location__put(&al);
 94                                 goto out;
 95                         }
 96 
 97                         fake_common_samples[k].thread = al.thread;
 98                         fake_common_samples[k].map = al.map;
 99                         fake_common_samples[k].sym = al.sym;
100                 }
101 
102                 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
103                         sample.pid = fake_samples[i][k].pid;
104                         sample.tid = fake_samples[i][k].pid;
105                         sample.ip = fake_samples[i][k].ip;
106                         if (machine__resolve(machine, &al, &sample) < 0)
107                                 goto out;
108 
109                         he = hists__add_entry(hists, &al, NULL,
110                                                 NULL, NULL, &sample, true);
111                         if (he == NULL) {
112                                 addr_location__put(&al);
113                                 goto out;
114                         }
115 
116                         fake_samples[i][k].thread = al.thread;
117                         fake_samples[i][k].map = al.map;
118                         fake_samples[i][k].sym = al.sym;
119                 }
120                 i++;
121         }
122 
123         return 0;
124 
125 out:
126         pr_debug("Not enough memory for adding a hist entry\n");
127         return -1;
128 }
129 
130 static int find_sample(struct sample *samples, size_t nr_samples,
131                        struct thread *t, struct map *m, struct symbol *s)
132 {
133         while (nr_samples--) {
134                 if (samples->thread == t && samples->map == m &&
135                     samples->sym == s)
136                         return 1;
137                 samples++;
138         }
139         return 0;
140 }
141 
142 static int __validate_match(struct hists *hists)
143 {
144         size_t count = 0;
145         struct rb_root *root;
146         struct rb_node *node;
147 
148         /*
149          * Only entries from fake_common_samples should have a pair.
150          */
151         if (hists__has(hists, need_collapse))
152                 root = &hists->entries_collapsed;
153         else
154                 root = hists->entries_in;
155 
156         node = rb_first(root);
157         while (node) {
158                 struct hist_entry *he;
159 
160                 he = rb_entry(node, struct hist_entry, rb_node_in);
161 
162                 if (hist_entry__has_pairs(he)) {
163                         if (find_sample(fake_common_samples,
164                                         ARRAY_SIZE(fake_common_samples),
165                                         he->thread, he->ms.map, he->ms.sym)) {
166                                 count++;
167                         } else {
168                                 pr_debug("Can't find the matched entry\n");
169                                 return -1;
170                         }
171                 }
172 
173                 node = rb_next(node);
174         }
175 
176         if (count != ARRAY_SIZE(fake_common_samples)) {
177                 pr_debug("Invalid count for matched entries: %zd of %zd\n",
178                          count, ARRAY_SIZE(fake_common_samples));
179                 return -1;
180         }
181 
182         return 0;
183 }
184 
185 static int validate_match(struct hists *leader, struct hists *other)
186 {
187         return __validate_match(leader) || __validate_match(other);
188 }
189 
190 static int __validate_link(struct hists *hists, int idx)
191 {
192         size_t count = 0;
193         size_t count_pair = 0;
194         size_t count_dummy = 0;
195         struct rb_root *root;
196         struct rb_node *node;
197 
198         /*
199          * Leader hists (idx = 0) will have dummy entries from other,
200          * and some entries will have no pair.  However every entry
201          * in other hists should have (dummy) pair.
202          */
203         if (hists__has(hists, need_collapse))
204                 root = &hists->entries_collapsed;
205         else
206                 root = hists->entries_in;
207 
208         node = rb_first(root);
209         while (node) {
210                 struct hist_entry *he;
211 
212                 he = rb_entry(node, struct hist_entry, rb_node_in);
213 
214                 if (hist_entry__has_pairs(he)) {
215                         if (!find_sample(fake_common_samples,
216                                          ARRAY_SIZE(fake_common_samples),
217                                          he->thread, he->ms.map, he->ms.sym) &&
218                             !find_sample(fake_samples[idx],
219                                          ARRAY_SIZE(fake_samples[idx]),
220                                          he->thread, he->ms.map, he->ms.sym)) {
221                                 count_dummy++;
222                         }
223                         count_pair++;
224                 } else if (idx) {
225                         pr_debug("A entry from the other hists should have pair\n");
226                         return -1;
227                 }
228 
229                 count++;
230                 node = rb_next(node);
231         }
232 
233         /*
234          * Note that we have a entry collapsed in the other (idx = 1) hists.
235          */
236         if (idx == 0) {
237                 if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
238                         pr_debug("Invalid count of dummy entries: %zd of %zd\n",
239                                  count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
240                         return -1;
241                 }
242                 if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
243                         pr_debug("Invalid count of total leader entries: %zd of %zd\n",
244                                  count, count_pair + ARRAY_SIZE(fake_samples[0]));
245                         return -1;
246                 }
247         } else {
248                 if (count != count_pair) {
249                         pr_debug("Invalid count of total other entries: %zd of %zd\n",
250                                  count, count_pair);
251                         return -1;
252                 }
253                 if (count_dummy > 0) {
254                         pr_debug("Other hists should not have dummy entries: %zd\n",
255                                  count_dummy);
256                         return -1;
257                 }
258         }
259 
260         return 0;
261 }
262 
263 static int validate_link(struct hists *leader, struct hists *other)
264 {
265         return __validate_link(leader, 0) || __validate_link(other, 1);
266 }
267 
268 int test__hists_link(struct test *test __maybe_unused, int subtest __maybe_unused)
269 {
270         int err = -1;
271         struct hists *hists, *first_hists;
272         struct machines machines;
273         struct machine *machine = NULL;
274         struct perf_evsel *evsel, *first;
275         struct perf_evlist *evlist = perf_evlist__new();
276 
277         if (evlist == NULL)
278                 return -ENOMEM;
279 
280         err = parse_events(evlist, "cpu-clock", NULL);
281         if (err)
282                 goto out;
283         err = parse_events(evlist, "task-clock", NULL);
284         if (err)
285                 goto out;
286 
287         err = TEST_FAIL;
288         /* default sort order (comm,dso,sym) will be used */
289         if (setup_sorting(NULL) < 0)
290                 goto out;
291 
292         machines__init(&machines);
293 
294         /* setup threads/dso/map/symbols also */
295         machine = setup_fake_machine(&machines);
296         if (!machine)
297                 goto out;
298 
299         if (verbose > 1)
300                 machine__fprintf(machine, stderr);
301 
302         /* process sample events */
303         err = add_hist_entries(evlist, machine);
304         if (err < 0)
305                 goto out;
306 
307         evlist__for_each_entry(evlist, evsel) {
308                 hists = evsel__hists(evsel);
309                 hists__collapse_resort(hists, NULL);
310 
311                 if (verbose > 2)
312                         print_hists_in(hists);
313         }
314 
315         first = perf_evlist__first(evlist);
316         evsel = perf_evlist__last(evlist);
317 
318         first_hists = evsel__hists(first);
319         hists = evsel__hists(evsel);
320 
321         /* match common entries */
322         hists__match(first_hists, hists);
323         err = validate_match(first_hists, hists);
324         if (err)
325                 goto out;
326 
327         /* link common and/or dummy entries */
328         hists__link(first_hists, hists);
329         err = validate_link(first_hists, hists);
330         if (err)
331                 goto out;
332 
333         err = 0;
334 
335 out:
336         /* tear down everything */
337         perf_evlist__delete(evlist);
338         reset_output_field();
339         machines__exit(&machines);
340 
341         return err;
342 }
343 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp