.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | #include "builtin.h" |
---|
3 | 3 | #include "perf.h" |
---|
| 4 | +#include "perf-sys.h" |
---|
4 | 5 | |
---|
5 | | -#include "util/util.h" |
---|
| 6 | +#include "util/cpumap.h" |
---|
6 | 7 | #include "util/evlist.h" |
---|
7 | | -#include "util/cache.h" |
---|
8 | 8 | #include "util/evsel.h" |
---|
| 9 | +#include "util/evsel_fprintf.h" |
---|
9 | 10 | #include "util/symbol.h" |
---|
10 | 11 | #include "util/thread.h" |
---|
11 | 12 | #include "util/header.h" |
---|
.. | .. |
---|
15 | 16 | #include "util/thread_map.h" |
---|
16 | 17 | #include "util/color.h" |
---|
17 | 18 | #include "util/stat.h" |
---|
| 19 | +#include "util/string2.h" |
---|
18 | 20 | #include "util/callchain.h" |
---|
19 | 21 | #include "util/time-utils.h" |
---|
20 | 22 | |
---|
| 23 | +#include <subcmd/pager.h> |
---|
21 | 24 | #include <subcmd/parse-options.h> |
---|
22 | 25 | #include "util/trace-event.h" |
---|
23 | 26 | |
---|
24 | 27 | #include "util/debug.h" |
---|
| 28 | +#include "util/event.h" |
---|
25 | 29 | |
---|
26 | 30 | #include <linux/kernel.h> |
---|
27 | 31 | #include <linux/log2.h> |
---|
| 32 | +#include <linux/zalloc.h> |
---|
28 | 33 | #include <sys/prctl.h> |
---|
29 | 34 | #include <sys/resource.h> |
---|
30 | 35 | #include <inttypes.h> |
---|
.. | .. |
---|
34 | 39 | #include <pthread.h> |
---|
35 | 40 | #include <math.h> |
---|
36 | 41 | #include <api/fs/fs.h> |
---|
| 42 | +#include <perf/cpumap.h> |
---|
37 | 43 | #include <linux/time64.h> |
---|
| 44 | +#include <linux/err.h> |
---|
38 | 45 | |
---|
39 | | -#include "sane_ctype.h" |
---|
| 46 | +#include <linux/ctype.h> |
---|
40 | 47 | |
---|
41 | 48 | #define PR_SET_NAME 15 /* Set process name */ |
---|
42 | 49 | #define MAX_CPUS 4096 |
---|
43 | 50 | #define COMM_LEN 20 |
---|
44 | 51 | #define SYM_LEN 129 |
---|
45 | 52 | #define MAX_PID 1024000 |
---|
| 53 | + |
---|
| 54 | +static const char *cpu_list; |
---|
| 55 | +static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
---|
46 | 56 | |
---|
47 | 57 | struct sched_atom; |
---|
48 | 58 | |
---|
.. | .. |
---|
120 | 130 | struct thread *thread; |
---|
121 | 131 | struct rb_node node; |
---|
122 | 132 | u64 max_lat; |
---|
123 | | - u64 max_lat_at; |
---|
| 133 | + u64 max_lat_start; |
---|
| 134 | + u64 max_lat_end; |
---|
124 | 135 | u64 total_lat; |
---|
125 | 136 | u64 nb_atoms; |
---|
126 | 137 | u64 total_runtime; |
---|
.. | .. |
---|
132 | 143 | struct perf_sched; |
---|
133 | 144 | |
---|
134 | 145 | struct trace_sched_handler { |
---|
135 | | - int (*switch_event)(struct perf_sched *sched, struct perf_evsel *evsel, |
---|
| 146 | + int (*switch_event)(struct perf_sched *sched, struct evsel *evsel, |
---|
136 | 147 | struct perf_sample *sample, struct machine *machine); |
---|
137 | 148 | |
---|
138 | | - int (*runtime_event)(struct perf_sched *sched, struct perf_evsel *evsel, |
---|
| 149 | + int (*runtime_event)(struct perf_sched *sched, struct evsel *evsel, |
---|
139 | 150 | struct perf_sample *sample, struct machine *machine); |
---|
140 | 151 | |
---|
141 | | - int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, |
---|
| 152 | + int (*wakeup_event)(struct perf_sched *sched, struct evsel *evsel, |
---|
142 | 153 | struct perf_sample *sample, struct machine *machine); |
---|
143 | 154 | |
---|
144 | 155 | /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */ |
---|
.. | .. |
---|
146 | 157 | struct machine *machine); |
---|
147 | 158 | |
---|
148 | 159 | int (*migrate_task_event)(struct perf_sched *sched, |
---|
149 | | - struct perf_evsel *evsel, |
---|
| 160 | + struct evsel *evsel, |
---|
150 | 161 | struct perf_sample *sample, |
---|
151 | 162 | struct machine *machine); |
---|
152 | 163 | }; |
---|
.. | .. |
---|
158 | 169 | DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS); |
---|
159 | 170 | int *comp_cpus; |
---|
160 | 171 | bool comp; |
---|
161 | | - struct thread_map *color_pids; |
---|
| 172 | + struct perf_thread_map *color_pids; |
---|
162 | 173 | const char *color_pids_str; |
---|
163 | | - struct cpu_map *color_cpus; |
---|
| 174 | + struct perf_cpu_map *color_cpus; |
---|
164 | 175 | const char *color_cpus_str; |
---|
165 | | - struct cpu_map *cpus; |
---|
| 176 | + struct perf_cpu_map *cpus; |
---|
166 | 177 | const char *cpus_str; |
---|
167 | 178 | }; |
---|
168 | 179 | |
---|
.. | .. |
---|
213 | 224 | u64 all_runtime; |
---|
214 | 225 | u64 all_count; |
---|
215 | 226 | u64 cpu_last_switched[MAX_CPUS]; |
---|
216 | | - struct rb_root atom_root, sorted_atom_root, merged_atom_root; |
---|
| 227 | + struct rb_root_cached atom_root, sorted_atom_root, merged_atom_root; |
---|
217 | 228 | struct list_head sort_list, cmp_pid; |
---|
218 | 229 | bool force; |
---|
219 | 230 | bool skip_merge; |
---|
.. | .. |
---|
271 | 282 | struct idle_thread_runtime { |
---|
272 | 283 | struct thread_runtime tr; |
---|
273 | 284 | struct thread *last_thread; |
---|
274 | | - struct rb_root sorted_root; |
---|
| 285 | + struct rb_root_cached sorted_root; |
---|
275 | 286 | struct callchain_root callchain; |
---|
276 | 287 | struct callchain_cursor cursor; |
---|
277 | 288 | }; |
---|
.. | .. |
---|
798 | 809 | |
---|
799 | 810 | static int |
---|
800 | 811 | replay_wakeup_event(struct perf_sched *sched, |
---|
801 | | - struct perf_evsel *evsel, struct perf_sample *sample, |
---|
| 812 | + struct evsel *evsel, struct perf_sample *sample, |
---|
802 | 813 | struct machine *machine __maybe_unused) |
---|
803 | 814 | { |
---|
804 | | - const char *comm = perf_evsel__strval(evsel, sample, "comm"); |
---|
805 | | - const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
---|
| 815 | + const char *comm = evsel__strval(evsel, sample, "comm"); |
---|
| 816 | + const u32 pid = evsel__intval(evsel, sample, "pid"); |
---|
806 | 817 | struct task_desc *waker, *wakee; |
---|
807 | 818 | |
---|
808 | 819 | if (verbose > 0) { |
---|
.. | .. |
---|
819 | 830 | } |
---|
820 | 831 | |
---|
821 | 832 | static int replay_switch_event(struct perf_sched *sched, |
---|
822 | | - struct perf_evsel *evsel, |
---|
| 833 | + struct evsel *evsel, |
---|
823 | 834 | struct perf_sample *sample, |
---|
824 | 835 | struct machine *machine __maybe_unused) |
---|
825 | 836 | { |
---|
826 | | - const char *prev_comm = perf_evsel__strval(evsel, sample, "prev_comm"), |
---|
827 | | - *next_comm = perf_evsel__strval(evsel, sample, "next_comm"); |
---|
828 | | - const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), |
---|
829 | | - next_pid = perf_evsel__intval(evsel, sample, "next_pid"); |
---|
830 | | - const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state"); |
---|
| 837 | + const char *prev_comm = evsel__strval(evsel, sample, "prev_comm"), |
---|
| 838 | + *next_comm = evsel__strval(evsel, sample, "next_comm"); |
---|
| 839 | + const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), |
---|
| 840 | + next_pid = evsel__intval(evsel, sample, "next_pid"); |
---|
| 841 | + const u64 prev_state = evsel__intval(evsel, sample, "prev_state"); |
---|
831 | 842 | struct task_desc *prev, __maybe_unused *next; |
---|
832 | 843 | u64 timestamp0, timestamp = sample->time; |
---|
833 | 844 | int cpu = sample->cpu; |
---|
.. | .. |
---|
950 | 961 | } |
---|
951 | 962 | |
---|
952 | 963 | static struct work_atoms * |
---|
953 | | -thread_atoms_search(struct rb_root *root, struct thread *thread, |
---|
| 964 | +thread_atoms_search(struct rb_root_cached *root, struct thread *thread, |
---|
954 | 965 | struct list_head *sort_list) |
---|
955 | 966 | { |
---|
956 | | - struct rb_node *node = root->rb_node; |
---|
| 967 | + struct rb_node *node = root->rb_root.rb_node; |
---|
957 | 968 | struct work_atoms key = { .thread = thread }; |
---|
958 | 969 | |
---|
959 | 970 | while (node) { |
---|
.. | .. |
---|
976 | 987 | } |
---|
977 | 988 | |
---|
978 | 989 | static void |
---|
979 | | -__thread_latency_insert(struct rb_root *root, struct work_atoms *data, |
---|
| 990 | +__thread_latency_insert(struct rb_root_cached *root, struct work_atoms *data, |
---|
980 | 991 | struct list_head *sort_list) |
---|
981 | 992 | { |
---|
982 | | - struct rb_node **new = &(root->rb_node), *parent = NULL; |
---|
| 993 | + struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL; |
---|
| 994 | + bool leftmost = true; |
---|
983 | 995 | |
---|
984 | 996 | while (*new) { |
---|
985 | 997 | struct work_atoms *this; |
---|
.. | .. |
---|
992 | 1004 | |
---|
993 | 1005 | if (cmp > 0) |
---|
994 | 1006 | new = &((*new)->rb_left); |
---|
995 | | - else |
---|
| 1007 | + else { |
---|
996 | 1008 | new = &((*new)->rb_right); |
---|
| 1009 | + leftmost = false; |
---|
| 1010 | + } |
---|
997 | 1011 | } |
---|
998 | 1012 | |
---|
999 | 1013 | rb_link_node(&data->node, parent, new); |
---|
1000 | | - rb_insert_color(&data->node, root); |
---|
| 1014 | + rb_insert_color_cached(&data->node, root, leftmost); |
---|
1001 | 1015 | } |
---|
1002 | 1016 | |
---|
1003 | 1017 | static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) |
---|
.. | .. |
---|
1083 | 1097 | atoms->total_lat += delta; |
---|
1084 | 1098 | if (delta > atoms->max_lat) { |
---|
1085 | 1099 | atoms->max_lat = delta; |
---|
1086 | | - atoms->max_lat_at = timestamp; |
---|
| 1100 | + atoms->max_lat_start = atom->wake_up_time; |
---|
| 1101 | + atoms->max_lat_end = timestamp; |
---|
1087 | 1102 | } |
---|
1088 | 1103 | atoms->nb_atoms++; |
---|
1089 | 1104 | } |
---|
1090 | 1105 | |
---|
1091 | 1106 | static int latency_switch_event(struct perf_sched *sched, |
---|
1092 | | - struct perf_evsel *evsel, |
---|
| 1107 | + struct evsel *evsel, |
---|
1093 | 1108 | struct perf_sample *sample, |
---|
1094 | 1109 | struct machine *machine) |
---|
1095 | 1110 | { |
---|
1096 | | - const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), |
---|
1097 | | - next_pid = perf_evsel__intval(evsel, sample, "next_pid"); |
---|
1098 | | - const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state"); |
---|
| 1111 | + const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), |
---|
| 1112 | + next_pid = evsel__intval(evsel, sample, "next_pid"); |
---|
| 1113 | + const u64 prev_state = evsel__intval(evsel, sample, "prev_state"); |
---|
1099 | 1114 | struct work_atoms *out_events, *in_events; |
---|
1100 | 1115 | struct thread *sched_out, *sched_in; |
---|
1101 | 1116 | u64 timestamp0, timestamp = sample->time; |
---|
.. | .. |
---|
1159 | 1174 | } |
---|
1160 | 1175 | |
---|
1161 | 1176 | static int latency_runtime_event(struct perf_sched *sched, |
---|
1162 | | - struct perf_evsel *evsel, |
---|
| 1177 | + struct evsel *evsel, |
---|
1163 | 1178 | struct perf_sample *sample, |
---|
1164 | 1179 | struct machine *machine) |
---|
1165 | 1180 | { |
---|
1166 | | - const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
---|
1167 | | - const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); |
---|
| 1181 | + const u32 pid = evsel__intval(evsel, sample, "pid"); |
---|
| 1182 | + const u64 runtime = evsel__intval(evsel, sample, "runtime"); |
---|
1168 | 1183 | struct thread *thread = machine__findnew_thread(machine, -1, pid); |
---|
1169 | 1184 | struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); |
---|
1170 | 1185 | u64 timestamp = sample->time; |
---|
.. | .. |
---|
1194 | 1209 | } |
---|
1195 | 1210 | |
---|
1196 | 1211 | static int latency_wakeup_event(struct perf_sched *sched, |
---|
1197 | | - struct perf_evsel *evsel, |
---|
| 1212 | + struct evsel *evsel, |
---|
1198 | 1213 | struct perf_sample *sample, |
---|
1199 | 1214 | struct machine *machine) |
---|
1200 | 1215 | { |
---|
1201 | | - const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
---|
| 1216 | + const u32 pid = evsel__intval(evsel, sample, "pid"); |
---|
1202 | 1217 | struct work_atoms *atoms; |
---|
1203 | 1218 | struct work_atom *atom; |
---|
1204 | 1219 | struct thread *wakee; |
---|
.. | .. |
---|
1255 | 1270 | } |
---|
1256 | 1271 | |
---|
1257 | 1272 | static int latency_migrate_task_event(struct perf_sched *sched, |
---|
1258 | | - struct perf_evsel *evsel, |
---|
| 1273 | + struct evsel *evsel, |
---|
1259 | 1274 | struct perf_sample *sample, |
---|
1260 | 1275 | struct machine *machine) |
---|
1261 | 1276 | { |
---|
1262 | | - const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
---|
| 1277 | + const u32 pid = evsel__intval(evsel, sample, "pid"); |
---|
1263 | 1278 | u64 timestamp = sample->time; |
---|
1264 | 1279 | struct work_atoms *atoms; |
---|
1265 | 1280 | struct work_atom *atom; |
---|
.. | .. |
---|
1309 | 1324 | int i; |
---|
1310 | 1325 | int ret; |
---|
1311 | 1326 | u64 avg; |
---|
1312 | | - char max_lat_at[32]; |
---|
| 1327 | + char max_lat_start[32], max_lat_end[32]; |
---|
1313 | 1328 | |
---|
1314 | 1329 | if (!work_list->nb_atoms) |
---|
1315 | 1330 | return; |
---|
.. | .. |
---|
1331 | 1346 | printf(" "); |
---|
1332 | 1347 | |
---|
1333 | 1348 | avg = work_list->total_lat / work_list->nb_atoms; |
---|
1334 | | - timestamp__scnprintf_usec(work_list->max_lat_at, max_lat_at, sizeof(max_lat_at)); |
---|
| 1349 | + timestamp__scnprintf_usec(work_list->max_lat_start, max_lat_start, sizeof(max_lat_start)); |
---|
| 1350 | + timestamp__scnprintf_usec(work_list->max_lat_end, max_lat_end, sizeof(max_lat_end)); |
---|
1335 | 1351 | |
---|
1336 | | - printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %13s s\n", |
---|
| 1352 | + printf("|%11.3f ms |%9" PRIu64 " | avg:%8.3f ms | max:%8.3f ms | max start: %12s s | max end: %12s s\n", |
---|
1337 | 1353 | (double)work_list->total_runtime / NSEC_PER_MSEC, |
---|
1338 | 1354 | work_list->nb_atoms, (double)avg / NSEC_PER_MSEC, |
---|
1339 | 1355 | (double)work_list->max_lat / NSEC_PER_MSEC, |
---|
1340 | | - max_lat_at); |
---|
| 1356 | + max_lat_start, max_lat_end); |
---|
1341 | 1357 | } |
---|
1342 | 1358 | |
---|
1343 | 1359 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
---|
.. | .. |
---|
1447 | 1463 | static void perf_sched__sort_lat(struct perf_sched *sched) |
---|
1448 | 1464 | { |
---|
1449 | 1465 | struct rb_node *node; |
---|
1450 | | - struct rb_root *root = &sched->atom_root; |
---|
| 1466 | + struct rb_root_cached *root = &sched->atom_root; |
---|
1451 | 1467 | again: |
---|
1452 | 1468 | for (;;) { |
---|
1453 | 1469 | struct work_atoms *data; |
---|
1454 | | - node = rb_first(root); |
---|
| 1470 | + node = rb_first_cached(root); |
---|
1455 | 1471 | if (!node) |
---|
1456 | 1472 | break; |
---|
1457 | 1473 | |
---|
1458 | | - rb_erase(node, root); |
---|
| 1474 | + rb_erase_cached(node, root); |
---|
1459 | 1475 | data = rb_entry(node, struct work_atoms, node); |
---|
1460 | 1476 | __thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list); |
---|
1461 | 1477 | } |
---|
.. | .. |
---|
1466 | 1482 | } |
---|
1467 | 1483 | |
---|
1468 | 1484 | static int process_sched_wakeup_event(struct perf_tool *tool, |
---|
1469 | | - struct perf_evsel *evsel, |
---|
| 1485 | + struct evsel *evsel, |
---|
1470 | 1486 | struct perf_sample *sample, |
---|
1471 | 1487 | struct machine *machine) |
---|
1472 | 1488 | { |
---|
.. | .. |
---|
1510 | 1526 | return thread; |
---|
1511 | 1527 | } |
---|
1512 | 1528 | |
---|
1513 | | -static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, |
---|
| 1529 | +static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, |
---|
1514 | 1530 | struct perf_sample *sample, struct machine *machine) |
---|
1515 | 1531 | { |
---|
1516 | | - const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid"); |
---|
| 1532 | + const u32 next_pid = evsel__intval(evsel, sample, "next_pid"); |
---|
1517 | 1533 | struct thread *sched_in; |
---|
1518 | 1534 | struct thread_runtime *tr; |
---|
1519 | 1535 | int new_shortname; |
---|
.. | .. |
---|
1651 | 1667 | } |
---|
1652 | 1668 | |
---|
1653 | 1669 | static int process_sched_switch_event(struct perf_tool *tool, |
---|
1654 | | - struct perf_evsel *evsel, |
---|
| 1670 | + struct evsel *evsel, |
---|
1655 | 1671 | struct perf_sample *sample, |
---|
1656 | 1672 | struct machine *machine) |
---|
1657 | 1673 | { |
---|
1658 | 1674 | struct perf_sched *sched = container_of(tool, struct perf_sched, tool); |
---|
1659 | 1675 | int this_cpu = sample->cpu, err = 0; |
---|
1660 | | - u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), |
---|
1661 | | - next_pid = perf_evsel__intval(evsel, sample, "next_pid"); |
---|
| 1676 | + u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), |
---|
| 1677 | + next_pid = evsel__intval(evsel, sample, "next_pid"); |
---|
1662 | 1678 | |
---|
1663 | 1679 | if (sched->curr_pid[this_cpu] != (u32)-1) { |
---|
1664 | 1680 | /* |
---|
.. | .. |
---|
1677 | 1693 | } |
---|
1678 | 1694 | |
---|
1679 | 1695 | static int process_sched_runtime_event(struct perf_tool *tool, |
---|
1680 | | - struct perf_evsel *evsel, |
---|
| 1696 | + struct evsel *evsel, |
---|
1681 | 1697 | struct perf_sample *sample, |
---|
1682 | 1698 | struct machine *machine) |
---|
1683 | 1699 | { |
---|
.. | .. |
---|
1707 | 1723 | } |
---|
1708 | 1724 | |
---|
1709 | 1725 | static int process_sched_migrate_task_event(struct perf_tool *tool, |
---|
1710 | | - struct perf_evsel *evsel, |
---|
| 1726 | + struct evsel *evsel, |
---|
1711 | 1727 | struct perf_sample *sample, |
---|
1712 | 1728 | struct machine *machine) |
---|
1713 | 1729 | { |
---|
.. | .. |
---|
1720 | 1736 | } |
---|
1721 | 1737 | |
---|
1722 | 1738 | typedef int (*tracepoint_handler)(struct perf_tool *tool, |
---|
1723 | | - struct perf_evsel *evsel, |
---|
| 1739 | + struct evsel *evsel, |
---|
1724 | 1740 | struct perf_sample *sample, |
---|
1725 | 1741 | struct machine *machine); |
---|
1726 | 1742 | |
---|
1727 | 1743 | static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused, |
---|
1728 | 1744 | union perf_event *event __maybe_unused, |
---|
1729 | 1745 | struct perf_sample *sample, |
---|
1730 | | - struct perf_evsel *evsel, |
---|
| 1746 | + struct evsel *evsel, |
---|
1731 | 1747 | struct machine *machine) |
---|
1732 | 1748 | { |
---|
1733 | 1749 | int err = 0; |
---|
.. | .. |
---|
1773 | 1789 | |
---|
1774 | 1790 | static int perf_sched__read_events(struct perf_sched *sched) |
---|
1775 | 1791 | { |
---|
1776 | | - const struct perf_evsel_str_handler handlers[] = { |
---|
| 1792 | + const struct evsel_str_handler handlers[] = { |
---|
1777 | 1793 | { "sched:sched_switch", process_sched_switch_event, }, |
---|
1778 | 1794 | { "sched:sched_stat_runtime", process_sched_runtime_event, }, |
---|
1779 | 1795 | { "sched:sched_wakeup", process_sched_wakeup_event, }, |
---|
.. | .. |
---|
1782 | 1798 | }; |
---|
1783 | 1799 | struct perf_session *session; |
---|
1784 | 1800 | struct perf_data data = { |
---|
1785 | | - .file = { |
---|
1786 | | - .path = input_name, |
---|
1787 | | - }, |
---|
1788 | | - .mode = PERF_DATA_MODE_READ, |
---|
1789 | | - .force = sched->force, |
---|
| 1801 | + .path = input_name, |
---|
| 1802 | + .mode = PERF_DATA_MODE_READ, |
---|
| 1803 | + .force = sched->force, |
---|
1790 | 1804 | }; |
---|
1791 | 1805 | int rc = -1; |
---|
1792 | 1806 | |
---|
1793 | 1807 | session = perf_session__new(&data, false, &sched->tool); |
---|
1794 | | - if (session == NULL) { |
---|
1795 | | - pr_debug("No Memory for session\n"); |
---|
1796 | | - return -1; |
---|
| 1808 | + if (IS_ERR(session)) { |
---|
| 1809 | + pr_debug("Error creating perf session"); |
---|
| 1810 | + return PTR_ERR(session); |
---|
1797 | 1811 | } |
---|
1798 | 1812 | |
---|
1799 | 1813 | symbol__init(&session->header.env); |
---|
.. | .. |
---|
1837 | 1851 | * returns runtime data for event, allocating memory for it the |
---|
1838 | 1852 | * first time it is used. |
---|
1839 | 1853 | */ |
---|
1840 | | -static struct evsel_runtime *perf_evsel__get_runtime(struct perf_evsel *evsel) |
---|
| 1854 | +static struct evsel_runtime *evsel__get_runtime(struct evsel *evsel) |
---|
1841 | 1855 | { |
---|
1842 | 1856 | struct evsel_runtime *r = evsel->priv; |
---|
1843 | 1857 | |
---|
.. | .. |
---|
1852 | 1866 | /* |
---|
1853 | 1867 | * save last time event was seen per cpu |
---|
1854 | 1868 | */ |
---|
1855 | | -static void perf_evsel__save_time(struct perf_evsel *evsel, |
---|
1856 | | - u64 timestamp, u32 cpu) |
---|
| 1869 | +static void evsel__save_time(struct evsel *evsel, u64 timestamp, u32 cpu) |
---|
1857 | 1870 | { |
---|
1858 | | - struct evsel_runtime *r = perf_evsel__get_runtime(evsel); |
---|
| 1871 | + struct evsel_runtime *r = evsel__get_runtime(evsel); |
---|
1859 | 1872 | |
---|
1860 | 1873 | if (r == NULL) |
---|
1861 | 1874 | return; |
---|
.. | .. |
---|
1879 | 1892 | } |
---|
1880 | 1893 | |
---|
1881 | 1894 | /* returns last time this event was seen on the given cpu */ |
---|
1882 | | -static u64 perf_evsel__get_time(struct perf_evsel *evsel, u32 cpu) |
---|
| 1895 | +static u64 evsel__get_time(struct evsel *evsel, u32 cpu) |
---|
1883 | 1896 | { |
---|
1884 | | - struct evsel_runtime *r = perf_evsel__get_runtime(evsel); |
---|
| 1897 | + struct evsel_runtime *r = evsel__get_runtime(evsel); |
---|
1885 | 1898 | |
---|
1886 | 1899 | if ((r == NULL) || (r->last_time == NULL) || (cpu >= r->ncpu)) |
---|
1887 | 1900 | return 0; |
---|
.. | .. |
---|
1986 | 1999 | } |
---|
1987 | 2000 | |
---|
1988 | 2001 | static void timehist_print_sample(struct perf_sched *sched, |
---|
1989 | | - struct perf_evsel *evsel, |
---|
| 2002 | + struct evsel *evsel, |
---|
1990 | 2003 | struct perf_sample *sample, |
---|
1991 | 2004 | struct addr_location *al, |
---|
1992 | 2005 | struct thread *thread, |
---|
1993 | 2006 | u64 t, int state) |
---|
1994 | 2007 | { |
---|
1995 | 2008 | struct thread_runtime *tr = thread__priv(thread); |
---|
1996 | | - const char *next_comm = perf_evsel__strval(evsel, sample, "next_comm"); |
---|
1997 | | - const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid"); |
---|
| 2009 | + const char *next_comm = evsel__strval(evsel, sample, "next_comm"); |
---|
| 2010 | + const u32 next_pid = evsel__intval(evsel, sample, "next_pid"); |
---|
1998 | 2011 | u32 max_cpus = sched->max_cpu + 1; |
---|
1999 | 2012 | char tstr[64]; |
---|
2000 | 2013 | char nstr[30]; |
---|
2001 | 2014 | u64 wait_time; |
---|
| 2015 | + |
---|
| 2016 | + if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
---|
| 2017 | + return; |
---|
2002 | 2018 | |
---|
2003 | 2019 | timestamp__scnprintf_usec(t, tstr, sizeof(tstr)); |
---|
2004 | 2020 | printf("%15s [%04d] ", tstr, sample->cpu); |
---|
.. | .. |
---|
2048 | 2064 | EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE | |
---|
2049 | 2065 | EVSEL__PRINT_CALLCHAIN_ARROW | |
---|
2050 | 2066 | EVSEL__PRINT_SKIP_IGNORED, |
---|
2051 | | - &callchain_cursor, stdout); |
---|
| 2067 | + &callchain_cursor, symbol_conf.bt_stop_list, stdout); |
---|
2052 | 2068 | |
---|
2053 | 2069 | out: |
---|
2054 | 2070 | printf("\n"); |
---|
.. | .. |
---|
2119 | 2135 | } |
---|
2120 | 2136 | |
---|
2121 | 2137 | static bool is_idle_sample(struct perf_sample *sample, |
---|
2122 | | - struct perf_evsel *evsel) |
---|
| 2138 | + struct evsel *evsel) |
---|
2123 | 2139 | { |
---|
2124 | 2140 | /* pid 0 == swapper == idle task */ |
---|
2125 | | - if (strcmp(perf_evsel__name(evsel), "sched:sched_switch") == 0) |
---|
2126 | | - return perf_evsel__intval(evsel, sample, "prev_pid") == 0; |
---|
| 2141 | + if (strcmp(evsel__name(evsel), "sched:sched_switch") == 0) |
---|
| 2142 | + return evsel__intval(evsel, sample, "prev_pid") == 0; |
---|
2127 | 2143 | |
---|
2128 | 2144 | return sample->pid == 0; |
---|
2129 | 2145 | } |
---|
2130 | 2146 | |
---|
2131 | 2147 | static void save_task_callchain(struct perf_sched *sched, |
---|
2132 | 2148 | struct perf_sample *sample, |
---|
2133 | | - struct perf_evsel *evsel, |
---|
| 2149 | + struct evsel *evsel, |
---|
2134 | 2150 | struct machine *machine) |
---|
2135 | 2151 | { |
---|
2136 | 2152 | struct callchain_cursor *cursor = &callchain_cursor; |
---|
.. | .. |
---|
2164 | 2180 | if (node == NULL) |
---|
2165 | 2181 | break; |
---|
2166 | 2182 | |
---|
2167 | | - sym = node->sym; |
---|
| 2183 | + sym = node->ms.sym; |
---|
2168 | 2184 | if (sym) { |
---|
2169 | 2185 | if (!strcmp(sym->name, "schedule") || |
---|
2170 | 2186 | !strcmp(sym->name, "__schedule") || |
---|
.. | .. |
---|
2284 | 2300 | static struct thread *timehist_get_thread(struct perf_sched *sched, |
---|
2285 | 2301 | struct perf_sample *sample, |
---|
2286 | 2302 | struct machine *machine, |
---|
2287 | | - struct perf_evsel *evsel) |
---|
| 2303 | + struct evsel *evsel) |
---|
2288 | 2304 | { |
---|
2289 | 2305 | struct thread *thread; |
---|
2290 | 2306 | |
---|
.. | .. |
---|
2320 | 2336 | itr->last_thread = thread; |
---|
2321 | 2337 | |
---|
2322 | 2338 | /* copy task callchain when entering to idle */ |
---|
2323 | | - if (perf_evsel__intval(evsel, sample, "next_pid") == 0) |
---|
| 2339 | + if (evsel__intval(evsel, sample, "next_pid") == 0) |
---|
2324 | 2340 | save_idle_callchain(sched, itr, sample); |
---|
2325 | 2341 | } |
---|
2326 | 2342 | } |
---|
.. | .. |
---|
2330 | 2346 | |
---|
2331 | 2347 | static bool timehist_skip_sample(struct perf_sched *sched, |
---|
2332 | 2348 | struct thread *thread, |
---|
2333 | | - struct perf_evsel *evsel, |
---|
| 2349 | + struct evsel *evsel, |
---|
2334 | 2350 | struct perf_sample *sample) |
---|
2335 | 2351 | { |
---|
2336 | 2352 | bool rc = false; |
---|
.. | .. |
---|
2341 | 2357 | } |
---|
2342 | 2358 | |
---|
2343 | 2359 | if (sched->idle_hist) { |
---|
2344 | | - if (strcmp(perf_evsel__name(evsel), "sched:sched_switch")) |
---|
| 2360 | + if (strcmp(evsel__name(evsel), "sched:sched_switch")) |
---|
2345 | 2361 | rc = true; |
---|
2346 | | - else if (perf_evsel__intval(evsel, sample, "prev_pid") != 0 && |
---|
2347 | | - perf_evsel__intval(evsel, sample, "next_pid") != 0) |
---|
| 2362 | + else if (evsel__intval(evsel, sample, "prev_pid") != 0 && |
---|
| 2363 | + evsel__intval(evsel, sample, "next_pid") != 0) |
---|
2348 | 2364 | rc = true; |
---|
2349 | 2365 | } |
---|
2350 | 2366 | |
---|
.. | .. |
---|
2352 | 2368 | } |
---|
2353 | 2369 | |
---|
2354 | 2370 | static void timehist_print_wakeup_event(struct perf_sched *sched, |
---|
2355 | | - struct perf_evsel *evsel, |
---|
| 2371 | + struct evsel *evsel, |
---|
2356 | 2372 | struct perf_sample *sample, |
---|
2357 | 2373 | struct machine *machine, |
---|
2358 | 2374 | struct thread *awakened) |
---|
.. | .. |
---|
2385 | 2401 | printf("\n"); |
---|
2386 | 2402 | } |
---|
2387 | 2403 | |
---|
| 2404 | +static int timehist_sched_wakeup_ignore(struct perf_tool *tool __maybe_unused, |
---|
| 2405 | + union perf_event *event __maybe_unused, |
---|
| 2406 | + struct evsel *evsel __maybe_unused, |
---|
| 2407 | + struct perf_sample *sample __maybe_unused, |
---|
| 2408 | + struct machine *machine __maybe_unused) |
---|
| 2409 | +{ |
---|
| 2410 | + return 0; |
---|
| 2411 | +} |
---|
| 2412 | + |
---|
2388 | 2413 | static int timehist_sched_wakeup_event(struct perf_tool *tool, |
---|
2389 | 2414 | union perf_event *event __maybe_unused, |
---|
2390 | | - struct perf_evsel *evsel, |
---|
| 2415 | + struct evsel *evsel, |
---|
2391 | 2416 | struct perf_sample *sample, |
---|
2392 | 2417 | struct machine *machine) |
---|
2393 | 2418 | { |
---|
.. | .. |
---|
2395 | 2420 | struct thread *thread; |
---|
2396 | 2421 | struct thread_runtime *tr = NULL; |
---|
2397 | 2422 | /* want pid of awakened task not pid in sample */ |
---|
2398 | | - const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
---|
| 2423 | + const u32 pid = evsel__intval(evsel, sample, "pid"); |
---|
2399 | 2424 | |
---|
2400 | 2425 | thread = machine__findnew_thread(machine, 0, pid); |
---|
2401 | 2426 | if (thread == NULL) |
---|
.. | .. |
---|
2417 | 2442 | } |
---|
2418 | 2443 | |
---|
2419 | 2444 | static void timehist_print_migration_event(struct perf_sched *sched, |
---|
2420 | | - struct perf_evsel *evsel, |
---|
| 2445 | + struct evsel *evsel, |
---|
2421 | 2446 | struct perf_sample *sample, |
---|
2422 | 2447 | struct machine *machine, |
---|
2423 | 2448 | struct thread *migrated) |
---|
.. | .. |
---|
2431 | 2456 | return; |
---|
2432 | 2457 | |
---|
2433 | 2458 | max_cpus = sched->max_cpu + 1; |
---|
2434 | | - ocpu = perf_evsel__intval(evsel, sample, "orig_cpu"); |
---|
2435 | | - dcpu = perf_evsel__intval(evsel, sample, "dest_cpu"); |
---|
| 2459 | + ocpu = evsel__intval(evsel, sample, "orig_cpu"); |
---|
| 2460 | + dcpu = evsel__intval(evsel, sample, "dest_cpu"); |
---|
2436 | 2461 | |
---|
2437 | 2462 | thread = machine__findnew_thread(machine, sample->pid, sample->tid); |
---|
2438 | 2463 | if (thread == NULL) |
---|
.. | .. |
---|
2471 | 2496 | |
---|
2472 | 2497 | static int timehist_migrate_task_event(struct perf_tool *tool, |
---|
2473 | 2498 | union perf_event *event __maybe_unused, |
---|
2474 | | - struct perf_evsel *evsel, |
---|
| 2499 | + struct evsel *evsel, |
---|
2475 | 2500 | struct perf_sample *sample, |
---|
2476 | 2501 | struct machine *machine) |
---|
2477 | 2502 | { |
---|
.. | .. |
---|
2479 | 2504 | struct thread *thread; |
---|
2480 | 2505 | struct thread_runtime *tr = NULL; |
---|
2481 | 2506 | /* want pid of migrated task not pid in sample */ |
---|
2482 | | - const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
---|
| 2507 | + const u32 pid = evsel__intval(evsel, sample, "pid"); |
---|
2483 | 2508 | |
---|
2484 | 2509 | thread = machine__findnew_thread(machine, 0, pid); |
---|
2485 | 2510 | if (thread == NULL) |
---|
.. | .. |
---|
2499 | 2524 | |
---|
2500 | 2525 | static int timehist_sched_change_event(struct perf_tool *tool, |
---|
2501 | 2526 | union perf_event *event, |
---|
2502 | | - struct perf_evsel *evsel, |
---|
| 2527 | + struct evsel *evsel, |
---|
2503 | 2528 | struct perf_sample *sample, |
---|
2504 | 2529 | struct machine *machine) |
---|
2505 | 2530 | { |
---|
.. | .. |
---|
2510 | 2535 | struct thread_runtime *tr = NULL; |
---|
2511 | 2536 | u64 tprev, t = sample->time; |
---|
2512 | 2537 | int rc = 0; |
---|
2513 | | - int state = perf_evsel__intval(evsel, sample, "prev_state"); |
---|
2514 | | - |
---|
| 2538 | + int state = evsel__intval(evsel, sample, "prev_state"); |
---|
2515 | 2539 | |
---|
2516 | 2540 | if (machine__resolve(machine, &al, sample) < 0) { |
---|
2517 | 2541 | pr_err("problem processing %d event. skipping it\n", |
---|
.. | .. |
---|
2535 | 2559 | goto out; |
---|
2536 | 2560 | } |
---|
2537 | 2561 | |
---|
2538 | | - tprev = perf_evsel__get_time(evsel, sample->cpu); |
---|
| 2562 | + tprev = evsel__get_time(evsel, sample->cpu); |
---|
2539 | 2563 | |
---|
2540 | 2564 | /* |
---|
2541 | 2565 | * If start time given: |
---|
.. | .. |
---|
2563 | 2587 | } |
---|
2564 | 2588 | |
---|
2565 | 2589 | if (!sched->idle_hist || thread->tid == 0) { |
---|
2566 | | - timehist_update_runtime_stats(tr, t, tprev); |
---|
| 2590 | + if (!cpu_list || test_bit(sample->cpu, cpu_bitmap)) |
---|
| 2591 | + timehist_update_runtime_stats(tr, t, tprev); |
---|
2567 | 2592 | |
---|
2568 | 2593 | if (sched->idle_hist) { |
---|
2569 | 2594 | struct idle_thread_runtime *itr = (void *)tr; |
---|
.. | .. |
---|
2618 | 2643 | tr->ready_to_run = 0; |
---|
2619 | 2644 | } |
---|
2620 | 2645 | |
---|
2621 | | - perf_evsel__save_time(evsel, sample->time, sample->cpu); |
---|
| 2646 | + evsel__save_time(evsel, sample->time, sample->cpu); |
---|
2622 | 2647 | |
---|
2623 | 2648 | return rc; |
---|
2624 | 2649 | } |
---|
2625 | 2650 | |
---|
2626 | 2651 | static int timehist_sched_switch_event(struct perf_tool *tool, |
---|
2627 | 2652 | union perf_event *event, |
---|
2628 | | - struct perf_evsel *evsel, |
---|
| 2653 | + struct evsel *evsel, |
---|
2629 | 2654 | struct perf_sample *sample, |
---|
2630 | 2655 | struct machine *machine __maybe_unused) |
---|
2631 | 2656 | { |
---|
.. | .. |
---|
2641 | 2666 | |
---|
2642 | 2667 | timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); |
---|
2643 | 2668 | printf("%15s ", tstr); |
---|
2644 | | - printf("lost %" PRIu64 " events on cpu %d\n", event->lost.lost, sample->cpu); |
---|
| 2669 | + printf("lost %" PRI_lu64 " events on cpu %d\n", event->lost.lost, sample->cpu); |
---|
2645 | 2670 | |
---|
2646 | 2671 | return 0; |
---|
2647 | 2672 | } |
---|
.. | .. |
---|
2762 | 2787 | return ret; |
---|
2763 | 2788 | } |
---|
2764 | 2789 | |
---|
2765 | | -static size_t timehist_print_idlehist_callchain(struct rb_root *root) |
---|
| 2790 | +static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root) |
---|
2766 | 2791 | { |
---|
2767 | 2792 | size_t ret = 0; |
---|
2768 | 2793 | FILE *fp = stdout; |
---|
2769 | 2794 | struct callchain_node *chain; |
---|
2770 | | - struct rb_node *rb_node = rb_first(root); |
---|
| 2795 | + struct rb_node *rb_node = rb_first_cached(root); |
---|
2771 | 2796 | |
---|
2772 | 2797 | printf(" %16s %8s %s\n", "Idle time (msec)", "Count", "Callchains"); |
---|
2773 | 2798 | printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line, |
---|
.. | .. |
---|
2836 | 2861 | |
---|
2837 | 2862 | printf("\nIdle stats:\n"); |
---|
2838 | 2863 | for (i = 0; i < idle_max_cpu; ++i) { |
---|
| 2864 | + if (cpu_list && !test_bit(i, cpu_bitmap)) |
---|
| 2865 | + continue; |
---|
| 2866 | + |
---|
2839 | 2867 | t = idle_threads[i]; |
---|
2840 | 2868 | if (!t) |
---|
2841 | 2869 | continue; |
---|
.. | .. |
---|
2868 | 2896 | if (itr == NULL) |
---|
2869 | 2897 | continue; |
---|
2870 | 2898 | |
---|
2871 | | - callchain_param.sort(&itr->sorted_root, &itr->callchain, |
---|
| 2899 | + callchain_param.sort(&itr->sorted_root.rb_root, &itr->callchain, |
---|
2872 | 2900 | 0, &callchain_param); |
---|
2873 | 2901 | |
---|
2874 | 2902 | printf(" CPU %2d:", i); |
---|
.. | .. |
---|
2895 | 2923 | |
---|
2896 | 2924 | typedef int (*sched_handler)(struct perf_tool *tool, |
---|
2897 | 2925 | union perf_event *event, |
---|
2898 | | - struct perf_evsel *evsel, |
---|
| 2926 | + struct evsel *evsel, |
---|
2899 | 2927 | struct perf_sample *sample, |
---|
2900 | 2928 | struct machine *machine); |
---|
2901 | 2929 | |
---|
2902 | 2930 | static int perf_timehist__process_sample(struct perf_tool *tool, |
---|
2903 | 2931 | union perf_event *event, |
---|
2904 | 2932 | struct perf_sample *sample, |
---|
2905 | | - struct perf_evsel *evsel, |
---|
| 2933 | + struct evsel *evsel, |
---|
2906 | 2934 | struct machine *machine) |
---|
2907 | 2935 | { |
---|
2908 | 2936 | struct perf_sched *sched = container_of(tool, struct perf_sched, tool); |
---|
.. | .. |
---|
2922 | 2950 | } |
---|
2923 | 2951 | |
---|
2924 | 2952 | static int timehist_check_attr(struct perf_sched *sched, |
---|
2925 | | - struct perf_evlist *evlist) |
---|
| 2953 | + struct evlist *evlist) |
---|
2926 | 2954 | { |
---|
2927 | | - struct perf_evsel *evsel; |
---|
| 2955 | + struct evsel *evsel; |
---|
2928 | 2956 | struct evsel_runtime *er; |
---|
2929 | 2957 | |
---|
2930 | | - list_for_each_entry(evsel, &evlist->entries, node) { |
---|
2931 | | - er = perf_evsel__get_runtime(evsel); |
---|
| 2958 | + list_for_each_entry(evsel, &evlist->core.entries, core.node) { |
---|
| 2959 | + er = evsel__get_runtime(evsel); |
---|
2932 | 2960 | if (er == NULL) { |
---|
2933 | 2961 | pr_err("Failed to allocate memory for evsel runtime data\n"); |
---|
2934 | 2962 | return -1; |
---|
.. | .. |
---|
2946 | 2974 | |
---|
2947 | 2975 | static int perf_sched__timehist(struct perf_sched *sched) |
---|
2948 | 2976 | { |
---|
2949 | | - const struct perf_evsel_str_handler handlers[] = { |
---|
| 2977 | + struct evsel_str_handler handlers[] = { |
---|
2950 | 2978 | { "sched:sched_switch", timehist_sched_switch_event, }, |
---|
2951 | 2979 | { "sched:sched_wakeup", timehist_sched_wakeup_event, }, |
---|
| 2980 | + { "sched:sched_waking", timehist_sched_wakeup_event, }, |
---|
2952 | 2981 | { "sched:sched_wakeup_new", timehist_sched_wakeup_event, }, |
---|
2953 | 2982 | }; |
---|
2954 | | - const struct perf_evsel_str_handler migrate_handlers[] = { |
---|
| 2983 | + const struct evsel_str_handler migrate_handlers[] = { |
---|
2955 | 2984 | { "sched:sched_migrate_task", timehist_migrate_task_event, }, |
---|
2956 | 2985 | }; |
---|
2957 | 2986 | struct perf_data data = { |
---|
2958 | | - .file = { |
---|
2959 | | - .path = input_name, |
---|
2960 | | - }, |
---|
2961 | | - .mode = PERF_DATA_MODE_READ, |
---|
2962 | | - .force = sched->force, |
---|
| 2987 | + .path = input_name, |
---|
| 2988 | + .mode = PERF_DATA_MODE_READ, |
---|
| 2989 | + .force = sched->force, |
---|
2963 | 2990 | }; |
---|
2964 | 2991 | |
---|
2965 | 2992 | struct perf_session *session; |
---|
2966 | | - struct perf_evlist *evlist; |
---|
| 2993 | + struct evlist *evlist; |
---|
2967 | 2994 | int err = -1; |
---|
2968 | 2995 | |
---|
2969 | 2996 | /* |
---|
.. | .. |
---|
2985 | 3012 | symbol_conf.use_callchain = sched->show_callchain; |
---|
2986 | 3013 | |
---|
2987 | 3014 | session = perf_session__new(&data, false, &sched->tool); |
---|
2988 | | - if (session == NULL) |
---|
2989 | | - return -ENOMEM; |
---|
| 3015 | + if (IS_ERR(session)) |
---|
| 3016 | + return PTR_ERR(session); |
---|
| 3017 | + |
---|
| 3018 | + if (cpu_list) { |
---|
| 3019 | + err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); |
---|
| 3020 | + if (err < 0) |
---|
| 3021 | + goto out; |
---|
| 3022 | + } |
---|
2990 | 3023 | |
---|
2991 | 3024 | evlist = session->evlist; |
---|
2992 | 3025 | |
---|
.. | .. |
---|
3001 | 3034 | goto out; |
---|
3002 | 3035 | |
---|
3003 | 3036 | setup_pager(); |
---|
| 3037 | + |
---|
| 3038 | + /* prefer sched_waking if it is captured */ |
---|
| 3039 | + if (perf_evlist__find_tracepoint_by_name(session->evlist, |
---|
| 3040 | + "sched:sched_waking")) |
---|
| 3041 | + handlers[1].handler = timehist_sched_wakeup_ignore; |
---|
3004 | 3042 | |
---|
3005 | 3043 | /* setup per-evsel handlers */ |
---|
3006 | 3044 | if (perf_session__set_tracepoints_handlers(session, handlers)) |
---|
.. | .. |
---|
3074 | 3112 | } |
---|
3075 | 3113 | } |
---|
3076 | 3114 | |
---|
3077 | | -static void __merge_work_atoms(struct rb_root *root, struct work_atoms *data) |
---|
| 3115 | +static void __merge_work_atoms(struct rb_root_cached *root, struct work_atoms *data) |
---|
3078 | 3116 | { |
---|
3079 | | - struct rb_node **new = &(root->rb_node), *parent = NULL; |
---|
| 3117 | + struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL; |
---|
3080 | 3118 | struct work_atoms *this; |
---|
3081 | 3119 | const char *comm = thread__comm_str(data->thread), *this_comm; |
---|
| 3120 | + bool leftmost = true; |
---|
3082 | 3121 | |
---|
3083 | 3122 | while (*new) { |
---|
3084 | 3123 | int cmp; |
---|
.. | .. |
---|
3092 | 3131 | new = &((*new)->rb_left); |
---|
3093 | 3132 | } else if (cmp < 0) { |
---|
3094 | 3133 | new = &((*new)->rb_right); |
---|
| 3134 | + leftmost = false; |
---|
3095 | 3135 | } else { |
---|
3096 | 3136 | this->num_merged++; |
---|
3097 | 3137 | this->total_runtime += data->total_runtime; |
---|
.. | .. |
---|
3100 | 3140 | list_splice(&data->work_list, &this->work_list); |
---|
3101 | 3141 | if (this->max_lat < data->max_lat) { |
---|
3102 | 3142 | this->max_lat = data->max_lat; |
---|
3103 | | - this->max_lat_at = data->max_lat_at; |
---|
| 3143 | + this->max_lat_start = data->max_lat_start; |
---|
| 3144 | + this->max_lat_end = data->max_lat_end; |
---|
3104 | 3145 | } |
---|
3105 | 3146 | zfree(&data); |
---|
3106 | 3147 | return; |
---|
.. | .. |
---|
3109 | 3150 | |
---|
3110 | 3151 | data->num_merged++; |
---|
3111 | 3152 | rb_link_node(&data->node, parent, new); |
---|
3112 | | - rb_insert_color(&data->node, root); |
---|
| 3153 | + rb_insert_color_cached(&data->node, root, leftmost); |
---|
3113 | 3154 | } |
---|
3114 | 3155 | |
---|
3115 | 3156 | static void perf_sched__merge_lat(struct perf_sched *sched) |
---|
.. | .. |
---|
3120 | 3161 | if (sched->skip_merge) |
---|
3121 | 3162 | return; |
---|
3122 | 3163 | |
---|
3123 | | - while ((node = rb_first(&sched->atom_root))) { |
---|
3124 | | - rb_erase(node, &sched->atom_root); |
---|
| 3164 | + while ((node = rb_first_cached(&sched->atom_root))) { |
---|
| 3165 | + rb_erase_cached(node, &sched->atom_root); |
---|
3125 | 3166 | data = rb_entry(node, struct work_atoms, node); |
---|
3126 | 3167 | __merge_work_atoms(&sched->merged_atom_root, data); |
---|
3127 | 3168 | } |
---|
.. | .. |
---|
3139 | 3180 | perf_sched__merge_lat(sched); |
---|
3140 | 3181 | perf_sched__sort_lat(sched); |
---|
3141 | 3182 | |
---|
3142 | | - printf("\n -----------------------------------------------------------------------------------------------------------------\n"); |
---|
3143 | | - printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n"); |
---|
3144 | | - printf(" -----------------------------------------------------------------------------------------------------------------\n"); |
---|
| 3183 | + printf("\n -------------------------------------------------------------------------------------------------------------------------------------------\n"); |
---|
| 3184 | + printf(" Task | Runtime ms | Switches | Avg delay ms | Max delay ms | Max delay start | Max delay end |\n"); |
---|
| 3185 | + printf(" -------------------------------------------------------------------------------------------------------------------------------------------\n"); |
---|
3145 | 3186 | |
---|
3146 | | - next = rb_first(&sched->sorted_atom_root); |
---|
| 3187 | + next = rb_first_cached(&sched->sorted_atom_root); |
---|
3147 | 3188 | |
---|
3148 | 3189 | while (next) { |
---|
3149 | 3190 | struct work_atoms *work_list; |
---|
.. | .. |
---|
3168 | 3209 | |
---|
3169 | 3210 | static int setup_map_cpus(struct perf_sched *sched) |
---|
3170 | 3211 | { |
---|
3171 | | - struct cpu_map *map; |
---|
| 3212 | + struct perf_cpu_map *map; |
---|
3172 | 3213 | |
---|
3173 | 3214 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); |
---|
3174 | 3215 | |
---|
.. | .. |
---|
3181 | 3222 | if (!sched->map.cpus_str) |
---|
3182 | 3223 | return 0; |
---|
3183 | 3224 | |
---|
3184 | | - map = cpu_map__new(sched->map.cpus_str); |
---|
| 3225 | + map = perf_cpu_map__new(sched->map.cpus_str); |
---|
3185 | 3226 | if (!map) { |
---|
3186 | 3227 | pr_err("failed to get cpus map from %s\n", sched->map.cpus_str); |
---|
3187 | 3228 | return -1; |
---|
.. | .. |
---|
3193 | 3234 | |
---|
3194 | 3235 | static int setup_color_pids(struct perf_sched *sched) |
---|
3195 | 3236 | { |
---|
3196 | | - struct thread_map *map; |
---|
| 3237 | + struct perf_thread_map *map; |
---|
3197 | 3238 | |
---|
3198 | 3239 | if (!sched->map.color_pids_str) |
---|
3199 | 3240 | return 0; |
---|
.. | .. |
---|
3210 | 3251 | |
---|
3211 | 3252 | static int setup_color_cpus(struct perf_sched *sched) |
---|
3212 | 3253 | { |
---|
3213 | | - struct cpu_map *map; |
---|
| 3254 | + struct perf_cpu_map *map; |
---|
3214 | 3255 | |
---|
3215 | 3256 | if (!sched->map.color_cpus_str) |
---|
3216 | 3257 | return 0; |
---|
3217 | 3258 | |
---|
3218 | | - map = cpu_map__new(sched->map.color_cpus_str); |
---|
| 3259 | + map = perf_cpu_map__new(sched->map.color_cpus_str); |
---|
3219 | 3260 | if (!map) { |
---|
3220 | 3261 | pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str); |
---|
3221 | 3262 | return -1; |
---|
.. | .. |
---|
3296 | 3337 | sort_dimension__add("pid", &sched->cmp_pid); |
---|
3297 | 3338 | } |
---|
3298 | 3339 | |
---|
| 3340 | +static bool schedstat_events_exposed(void) |
---|
| 3341 | +{ |
---|
| 3342 | + /* |
---|
| 3343 | + * Select "sched:sched_stat_wait" event to check |
---|
| 3344 | + * whether schedstat tracepoints are exposed. |
---|
| 3345 | + */ |
---|
| 3346 | + return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ? |
---|
| 3347 | + false : true; |
---|
| 3348 | +} |
---|
| 3349 | + |
---|
3299 | 3350 | static int __cmd_record(int argc, const char **argv) |
---|
3300 | 3351 | { |
---|
3301 | 3352 | unsigned int rec_argc, i, j; |
---|
.. | .. |
---|
3307 | 3358 | "-m", "1024", |
---|
3308 | 3359 | "-c", "1", |
---|
3309 | 3360 | "-e", "sched:sched_switch", |
---|
3310 | | - "-e", "sched:sched_stat_wait", |
---|
3311 | | - "-e", "sched:sched_stat_sleep", |
---|
3312 | | - "-e", "sched:sched_stat_iowait", |
---|
3313 | 3361 | "-e", "sched:sched_stat_runtime", |
---|
3314 | 3362 | "-e", "sched:sched_process_fork", |
---|
3315 | | - "-e", "sched:sched_wakeup", |
---|
3316 | 3363 | "-e", "sched:sched_wakeup_new", |
---|
3317 | 3364 | "-e", "sched:sched_migrate_task", |
---|
3318 | 3365 | }; |
---|
3319 | 3366 | |
---|
3320 | | - rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
---|
| 3367 | + /* |
---|
| 3368 | + * The tracepoints trace_sched_stat_{wait, sleep, iowait} |
---|
| 3369 | + * are not exposed to user if CONFIG_SCHEDSTATS is not set, |
---|
| 3370 | + * to prevent "perf sched record" execution failure, determine |
---|
| 3371 | + * whether to record schedstat events according to actual situation. |
---|
| 3372 | + */ |
---|
| 3373 | + const char * const schedstat_args[] = { |
---|
| 3374 | + "-e", "sched:sched_stat_wait", |
---|
| 3375 | + "-e", "sched:sched_stat_sleep", |
---|
| 3376 | + "-e", "sched:sched_stat_iowait", |
---|
| 3377 | + }; |
---|
| 3378 | + unsigned int schedstat_argc = schedstat_events_exposed() ? |
---|
| 3379 | + ARRAY_SIZE(schedstat_args) : 0; |
---|
| 3380 | + |
---|
| 3381 | + struct tep_event *waking_event; |
---|
| 3382 | + |
---|
| 3383 | + /* |
---|
| 3384 | + * +2 for either "-e", "sched:sched_wakeup" or |
---|
| 3385 | + * "-e", "sched:sched_waking" |
---|
| 3386 | + */ |
---|
| 3387 | + rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1; |
---|
3321 | 3388 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
---|
3322 | 3389 | |
---|
3323 | 3390 | if (rec_argv == NULL) |
---|
.. | .. |
---|
3325 | 3392 | |
---|
3326 | 3393 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
---|
3327 | 3394 | rec_argv[i] = strdup(record_args[i]); |
---|
| 3395 | + |
---|
| 3396 | + rec_argv[i++] = "-e"; |
---|
| 3397 | + waking_event = trace_event__tp_format("sched", "sched_waking"); |
---|
| 3398 | + if (!IS_ERR(waking_event)) |
---|
| 3399 | + rec_argv[i++] = strdup("sched:sched_waking"); |
---|
| 3400 | + else |
---|
| 3401 | + rec_argv[i++] = strdup("sched:sched_wakeup"); |
---|
| 3402 | + |
---|
| 3403 | + for (j = 0; j < schedstat_argc; j++) |
---|
| 3404 | + rec_argv[i++] = strdup(schedstat_args[j]); |
---|
3328 | 3405 | |
---|
3329 | 3406 | for (j = 1; j < (unsigned int)argc; j++, i++) |
---|
3330 | 3407 | rec_argv[i] = argv[j]; |
---|
.. | .. |
---|
3336 | 3413 | |
---|
3337 | 3414 | int cmd_sched(int argc, const char **argv) |
---|
3338 | 3415 | { |
---|
3339 | | - const char default_sort_order[] = "avg, max, switch, runtime"; |
---|
| 3416 | + static const char default_sort_order[] = "avg, max, switch, runtime"; |
---|
3340 | 3417 | struct perf_sched sched = { |
---|
3341 | 3418 | .tool = { |
---|
3342 | 3419 | .sample = perf_sched__process_tracepoint_sample, |
---|
.. | .. |
---|
3421 | 3498 | "analyze events only for given process id(s)"), |
---|
3422 | 3499 | OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]", |
---|
3423 | 3500 | "analyze events only for given thread id(s)"), |
---|
| 3501 | + OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
---|
3424 | 3502 | OPT_PARENT(sched_options) |
---|
3425 | 3503 | }; |
---|
3426 | 3504 | |
---|