| .. | .. |
|---|
| 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 | }; |
|---|
| .. | .. |
|---|
| 659 | 670 | err = pthread_attr_init(&attr); |
|---|
| 660 | 671 | BUG_ON(err); |
|---|
| 661 | 672 | err = pthread_attr_setstacksize(&attr, |
|---|
| 662 | | - (size_t) max(16 * 1024, PTHREAD_STACK_MIN)); |
|---|
| 673 | + (size_t) max(16 * 1024, (int)PTHREAD_STACK_MIN)); |
|---|
| 663 | 674 | BUG_ON(err); |
|---|
| 664 | 675 | err = pthread_mutex_lock(&sched->start_work_mutex); |
|---|
| 665 | 676 | BUG_ON(err); |
|---|
| .. | .. |
|---|
| 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 | |
|---|