1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 20a02ad93SIngo Molnar #include "builtin.h" 3b1ffe8f3SIngo Molnar #include "perf.h" 491854f9aSArnaldo Carvalho de Melo #include "perf-sys.h" 50a02ad93SIngo Molnar 687ffb6c6SArnaldo Carvalho de Melo #include "util/cpumap.h" 7ee29be62SArnaldo Carvalho de Melo #include "util/evlist.h" 8e3f42609SArnaldo Carvalho de Melo #include "util/evsel.h" 9ca125277SArnaldo Carvalho de Melo #include "util/evsel_fprintf.h" 100a02ad93SIngo Molnar #include "util/symbol.h" 110a02ad93SIngo Molnar #include "util/thread.h" 120a02ad93SIngo Molnar #include "util/header.h" 1394c744b6SArnaldo Carvalho de Melo #include "util/session.h" 1445694aa7SArnaldo Carvalho de Melo #include "util/tool.h" 1557480d2cSYann Droneaud #include "util/cloexec.h" 16a151a37aSJiri Olsa #include "util/thread_map.h" 178cd91195SJiri Olsa #include "util/color.h" 1849394a2aSDavid Ahern #include "util/stat.h" 196a9fa4e3SArnaldo Carvalho de Melo #include "util/string2.h" 206c973c90SDavid Ahern #include "util/callchain.h" 21853b7407SDavid Ahern #include "util/time-utils.h" 220a02ad93SIngo Molnar 23fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h> 244b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 25b1ffe8f3SIngo Molnar #include "util/trace-event.h" 260a02ad93SIngo Molnar 270a02ad93SIngo Molnar #include "util/debug.h" 28f12be047SArnaldo Carvalho de Melo #include "util/event.h" 290a02ad93SIngo Molnar 30877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 3149394a2aSDavid Ahern #include <linux/log2.h> 327f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 33b1ffe8f3SIngo Molnar #include <sys/prctl.h> 347b78f136SMarkus Trippelsdorf #include <sys/resource.h> 35fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 360a02ad93SIngo Molnar 37a43783aeSArnaldo Carvalho de Melo #include <errno.h> 38b1ffe8f3SIngo Molnar #include <semaphore.h> 39b1ffe8f3SIngo Molnar #include <pthread.h> 40b1ffe8f3SIngo Molnar #include <math.h> 41cb06ac25SYunlong Song #include <api/fs/fs.h> 4287ffb6c6SArnaldo Carvalho de Melo #include <perf/cpumap.h> 434fc76e49SArnaldo Carvalho de Melo #include <linux/time64.h> 446ef81c55SMamatha Inamdar #include <linux/err.h> 45419ab0d6SFrederic Weisbecker 463052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 473d689ed6SArnaldo Carvalho de Melo 48ec156764SIngo Molnar #define PR_SET_NAME 15 /* Set process name */ 49b1ffe8f3SIngo Molnar #define MAX_CPUS 4096 50ec156764SIngo Molnar #define COMM_LEN 20 51ec156764SIngo Molnar #define SYM_LEN 129 52a35e27d0SYunlong Song #define MAX_PID 1024000 53ec156764SIngo Molnar 54c30d630dSDavid Ahern static const char *cpu_list; 55c30d630dSDavid Ahern static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 56c30d630dSDavid Ahern 5739aeb52fSmingo struct sched_atom; 58ec156764SIngo Molnar 59ec156764SIngo Molnar struct task_desc { 60ec156764SIngo Molnar unsigned long nr; 61ec156764SIngo Molnar unsigned long pid; 62ec156764SIngo Molnar char comm[COMM_LEN]; 63ec156764SIngo Molnar 64ec156764SIngo Molnar unsigned long nr_events; 65ec156764SIngo Molnar unsigned long curr_event; 6639aeb52fSmingo struct sched_atom **atoms; 67ec156764SIngo Molnar 68ec156764SIngo Molnar pthread_t thread; 69ec156764SIngo Molnar sem_t sleep_sem; 70ec156764SIngo Molnar 71ec156764SIngo Molnar sem_t ready_for_work; 72ec156764SIngo Molnar sem_t work_done_sem; 73ec156764SIngo Molnar 74b1ffe8f3SIngo Molnar u64 cpu_usage; 75ec156764SIngo Molnar }; 76ec156764SIngo Molnar 77ec156764SIngo Molnar enum sched_event_type { 78ec156764SIngo Molnar SCHED_EVENT_RUN, 79ec156764SIngo Molnar SCHED_EVENT_SLEEP, 80ec156764SIngo Molnar SCHED_EVENT_WAKEUP, 8155ffb7a6SMike Galbraith SCHED_EVENT_MIGRATION, 82ec156764SIngo Molnar }; 83ec156764SIngo Molnar 8439aeb52fSmingo struct sched_atom { 85ec156764SIngo Molnar enum sched_event_type type; 86eed05fe7SArnaldo Carvalho de Melo int specific_wait; 87b1ffe8f3SIngo Molnar u64 timestamp; 88b1ffe8f3SIngo Molnar u64 duration; 89ec156764SIngo Molnar unsigned long nr; 90ec156764SIngo Molnar sem_t *wait_sem; 91ec156764SIngo Molnar struct task_desc *wakee; 92ec156764SIngo Molnar }; 93ec156764SIngo Molnar 94e936e8e4SDongsheng #define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP" 95b1ffe8f3SIngo Molnar 96941bdea7SNamhyung Kim /* task state bitmask, copied from include/linux/sched.h */ 97941bdea7SNamhyung Kim #define TASK_RUNNING 0 98941bdea7SNamhyung Kim #define TASK_INTERRUPTIBLE 1 99941bdea7SNamhyung Kim #define TASK_UNINTERRUPTIBLE 2 100941bdea7SNamhyung Kim #define __TASK_STOPPED 4 101941bdea7SNamhyung Kim #define __TASK_TRACED 8 102941bdea7SNamhyung Kim /* in tsk->exit_state */ 103941bdea7SNamhyung Kim #define EXIT_DEAD 16 104941bdea7SNamhyung Kim #define EXIT_ZOMBIE 32 105941bdea7SNamhyung Kim #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD) 106941bdea7SNamhyung Kim /* in tsk->state again */ 107941bdea7SNamhyung Kim #define TASK_DEAD 64 108941bdea7SNamhyung Kim #define TASK_WAKEKILL 128 109941bdea7SNamhyung Kim #define TASK_WAKING 256 110941bdea7SNamhyung Kim #define TASK_PARKED 512 111941bdea7SNamhyung Kim 112b1ffe8f3SIngo Molnar enum thread_state { 113b1ffe8f3SIngo Molnar THREAD_SLEEPING = 0, 114b1ffe8f3SIngo Molnar THREAD_WAIT_CPU, 115b1ffe8f3SIngo Molnar THREAD_SCHED_IN, 116b1ffe8f3SIngo Molnar THREAD_IGNORE 117b1ffe8f3SIngo Molnar }; 118b1ffe8f3SIngo Molnar 119b1ffe8f3SIngo Molnar struct work_atom { 120b1ffe8f3SIngo Molnar struct list_head list; 121b1ffe8f3SIngo Molnar enum thread_state state; 122aa1ab9d2SFrederic Weisbecker u64 sched_out_time; 123b1ffe8f3SIngo Molnar u64 wake_up_time; 124b1ffe8f3SIngo Molnar u64 sched_in_time; 125b1ffe8f3SIngo Molnar u64 runtime; 126b1ffe8f3SIngo Molnar }; 127b1ffe8f3SIngo Molnar 12839aeb52fSmingo struct work_atoms { 12939aeb52fSmingo struct list_head work_list; 130b1ffe8f3SIngo Molnar struct thread *thread; 131b1ffe8f3SIngo Molnar struct rb_node node; 132b1ffe8f3SIngo Molnar u64 max_lat; 133dc000c45SJoel Fernandes (Google) u64 max_lat_start; 134dc000c45SJoel Fernandes (Google) u64 max_lat_end; 135b1ffe8f3SIngo Molnar u64 total_lat; 136b1ffe8f3SIngo Molnar u64 nb_atoms; 137b1ffe8f3SIngo Molnar u64 total_runtime; 1382f80dd44SJosef Bacik int num_merged; 139b1ffe8f3SIngo Molnar }; 140b1ffe8f3SIngo Molnar 14139aeb52fSmingo typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *); 142b1ffe8f3SIngo Molnar 1430e9b07e5SArnaldo Carvalho de Melo struct perf_sched; 1440e9b07e5SArnaldo Carvalho de Melo 145419ab0d6SFrederic Weisbecker struct trace_sched_handler { 14632dcd021SJiri Olsa int (*switch_event)(struct perf_sched *sched, struct evsel *evsel, 1479ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, struct machine *machine); 148419ab0d6SFrederic Weisbecker 14932dcd021SJiri Olsa int (*runtime_event)(struct perf_sched *sched, struct evsel *evsel, 1509ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, struct machine *machine); 15139aeb52fSmingo 15232dcd021SJiri Olsa int (*wakeup_event)(struct perf_sched *sched, struct evsel *evsel, 1539ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, struct machine *machine); 154419ab0d6SFrederic Weisbecker 155cb627505SDavid Ahern /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */ 156cb627505SDavid Ahern int (*fork_event)(struct perf_sched *sched, union perf_event *event, 157cb627505SDavid Ahern struct machine *machine); 15855ffb7a6SMike Galbraith 1590e9b07e5SArnaldo Carvalho de Melo int (*migrate_task_event)(struct perf_sched *sched, 16032dcd021SJiri Olsa struct evsel *evsel, 1619ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, 1629ec3f4e4SArnaldo Carvalho de Melo struct machine *machine); 163419ab0d6SFrederic Weisbecker }; 164419ab0d6SFrederic Weisbecker 165a151a37aSJiri Olsa #define COLOR_PIDS PERF_COLOR_BLUE 166cf294f24SJiri Olsa #define COLOR_CPUS PERF_COLOR_BG_RED 167a151a37aSJiri Olsa 16899623c62SJiri Olsa struct perf_sched_map { 16999623c62SJiri Olsa DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS); 17099623c62SJiri Olsa int *comp_cpus; 17199623c62SJiri Olsa bool comp; 1729749b90eSJiri Olsa struct perf_thread_map *color_pids; 173a151a37aSJiri Olsa const char *color_pids_str; 174f854839bSJiri Olsa struct perf_cpu_map *color_cpus; 175cf294f24SJiri Olsa const char *color_cpus_str; 176f854839bSJiri Olsa struct perf_cpu_map *cpus; 17773643bb6SJiri Olsa const char *cpus_str; 17899623c62SJiri Olsa }; 17999623c62SJiri Olsa 1800e9b07e5SArnaldo Carvalho de Melo struct perf_sched { 1810e9b07e5SArnaldo Carvalho de Melo struct perf_tool tool; 1820e9b07e5SArnaldo Carvalho de Melo const char *sort_order; 1830e9b07e5SArnaldo Carvalho de Melo unsigned long nr_tasks; 184cb06ac25SYunlong Song struct task_desc **pid_to_task; 1850e9b07e5SArnaldo Carvalho de Melo struct task_desc **tasks; 1860e9b07e5SArnaldo Carvalho de Melo const struct trace_sched_handler *tp_handler; 1870e9b07e5SArnaldo Carvalho de Melo pthread_mutex_t start_work_mutex; 1880e9b07e5SArnaldo Carvalho de Melo pthread_mutex_t work_done_wait_mutex; 1890e9b07e5SArnaldo Carvalho de Melo int profile_cpu; 1900e9b07e5SArnaldo Carvalho de Melo /* 1910e9b07e5SArnaldo Carvalho de Melo * Track the current task - that way we can know whether there's any 1920e9b07e5SArnaldo Carvalho de Melo * weird events, such as a task being switched away that is not current. 1930e9b07e5SArnaldo Carvalho de Melo */ 1940e9b07e5SArnaldo Carvalho de Melo int max_cpu; 1950e9b07e5SArnaldo Carvalho de Melo u32 curr_pid[MAX_CPUS]; 1960e9b07e5SArnaldo Carvalho de Melo struct thread *curr_thread[MAX_CPUS]; 1970e9b07e5SArnaldo Carvalho de Melo char next_shortname1; 1980e9b07e5SArnaldo Carvalho de Melo char next_shortname2; 1990e9b07e5SArnaldo Carvalho de Melo unsigned int replay_repeat; 2000e9b07e5SArnaldo Carvalho de Melo unsigned long nr_run_events; 2010e9b07e5SArnaldo Carvalho de Melo unsigned long nr_sleep_events; 2020e9b07e5SArnaldo Carvalho de Melo unsigned long nr_wakeup_events; 2030e9b07e5SArnaldo Carvalho de Melo unsigned long nr_sleep_corrections; 2040e9b07e5SArnaldo Carvalho de Melo unsigned long nr_run_events_optimized; 2050e9b07e5SArnaldo Carvalho de Melo unsigned long targetless_wakeups; 2060e9b07e5SArnaldo Carvalho de Melo unsigned long multitarget_wakeups; 2070e9b07e5SArnaldo Carvalho de Melo unsigned long nr_runs; 2080e9b07e5SArnaldo Carvalho de Melo unsigned long nr_timestamps; 2090e9b07e5SArnaldo Carvalho de Melo unsigned long nr_unordered_timestamps; 2100e9b07e5SArnaldo Carvalho de Melo unsigned long nr_context_switch_bugs; 2110e9b07e5SArnaldo Carvalho de Melo unsigned long nr_events; 2120e9b07e5SArnaldo Carvalho de Melo unsigned long nr_lost_chunks; 2130e9b07e5SArnaldo Carvalho de Melo unsigned long nr_lost_events; 2140e9b07e5SArnaldo Carvalho de Melo u64 run_measurement_overhead; 2150e9b07e5SArnaldo Carvalho de Melo u64 sleep_measurement_overhead; 2160e9b07e5SArnaldo Carvalho de Melo u64 start_time; 2170e9b07e5SArnaldo Carvalho de Melo u64 cpu_usage; 2180e9b07e5SArnaldo Carvalho de Melo u64 runavg_cpu_usage; 2190e9b07e5SArnaldo Carvalho de Melo u64 parent_cpu_usage; 2200e9b07e5SArnaldo Carvalho de Melo u64 runavg_parent_cpu_usage; 2210e9b07e5SArnaldo Carvalho de Melo u64 sum_runtime; 2220e9b07e5SArnaldo Carvalho de Melo u64 sum_fluct; 2230e9b07e5SArnaldo Carvalho de Melo u64 run_avg; 2240e9b07e5SArnaldo Carvalho de Melo u64 all_runtime; 2250e9b07e5SArnaldo Carvalho de Melo u64 all_count; 2260e9b07e5SArnaldo Carvalho de Melo u64 cpu_last_switched[MAX_CPUS]; 227cb4c13a5SDavidlohr Bueso struct rb_root_cached atom_root, sorted_atom_root, merged_atom_root; 2280e9b07e5SArnaldo Carvalho de Melo struct list_head sort_list, cmp_pid; 229939cda52SYunlong Song bool force; 2302f80dd44SJosef Bacik bool skip_merge; 23199623c62SJiri Olsa struct perf_sched_map map; 23252df138cSDavid Ahern 23352df138cSDavid Ahern /* options for timehist command */ 23452df138cSDavid Ahern bool summary; 23552df138cSDavid Ahern bool summary_only; 236699b5b92SNamhyung Kim bool idle_hist; 2376c973c90SDavid Ahern bool show_callchain; 2386c973c90SDavid Ahern unsigned int max_stack; 239a407b067SDavid Ahern bool show_cpu_visual; 240fc1469f1SDavid Ahern bool show_wakeups; 241292c4a8fSBrendan Gregg bool show_next; 242350f54faSDavid Ahern bool show_migrations; 243414e050cSNamhyung Kim bool show_state; 24452df138cSDavid Ahern u64 skipped_samples; 245853b7407SDavid Ahern const char *time_str; 246853b7407SDavid Ahern struct perf_time_interval ptime; 2479396c9cbSNamhyung Kim struct perf_time_interval hist_time; 2480e9b07e5SArnaldo Carvalho de Melo }; 2490e9b07e5SArnaldo Carvalho de Melo 25049394a2aSDavid Ahern /* per thread run time data */ 25149394a2aSDavid Ahern struct thread_runtime { 25249394a2aSDavid Ahern u64 last_time; /* time of previous sched in/out event */ 25349394a2aSDavid Ahern u64 dt_run; /* run time */ 254941bdea7SNamhyung Kim u64 dt_sleep; /* time between CPU access by sleep (off cpu) */ 255941bdea7SNamhyung Kim u64 dt_iowait; /* time between CPU access by iowait (off cpu) */ 256941bdea7SNamhyung Kim u64 dt_preempt; /* time between CPU access by preempt (off cpu) */ 25749394a2aSDavid Ahern u64 dt_delay; /* time between wakeup and sched-in */ 25849394a2aSDavid Ahern u64 ready_to_run; /* time of wakeup */ 25949394a2aSDavid Ahern 26049394a2aSDavid Ahern struct stats run_stats; 26149394a2aSDavid Ahern u64 total_run_time; 262587782c5SNamhyung Kim u64 total_sleep_time; 263587782c5SNamhyung Kim u64 total_iowait_time; 264587782c5SNamhyung Kim u64 total_preempt_time; 265587782c5SNamhyung Kim u64 total_delay_time; 266350f54faSDavid Ahern 267941bdea7SNamhyung Kim int last_state; 2688640da9fSChangbin Du 2698640da9fSChangbin Du char shortname[3]; 27099a3c3a9SChangbin Du bool comm_changed; 27199a3c3a9SChangbin Du 272350f54faSDavid Ahern u64 migrations; 27349394a2aSDavid Ahern }; 27449394a2aSDavid Ahern 27549394a2aSDavid Ahern /* per event run time data */ 27649394a2aSDavid Ahern struct evsel_runtime { 27749394a2aSDavid Ahern u64 *last_time; /* time this event was last seen per cpu */ 27849394a2aSDavid Ahern u32 ncpu; /* highest cpu slot allocated */ 27949394a2aSDavid Ahern }; 28049394a2aSDavid Ahern 2813bc2fa9cSNamhyung Kim /* per cpu idle time data */ 2823bc2fa9cSNamhyung Kim struct idle_thread_runtime { 2833bc2fa9cSNamhyung Kim struct thread_runtime tr; 2843bc2fa9cSNamhyung Kim struct thread *last_thread; 285cb4c13a5SDavidlohr Bueso struct rb_root_cached sorted_root; 2863bc2fa9cSNamhyung Kim struct callchain_root callchain; 2873bc2fa9cSNamhyung Kim struct callchain_cursor cursor; 2883bc2fa9cSNamhyung Kim }; 2893bc2fa9cSNamhyung Kim 29049394a2aSDavid Ahern /* track idle times per cpu */ 29149394a2aSDavid Ahern static struct thread **idle_threads; 29249394a2aSDavid Ahern static int idle_max_cpu; 29349394a2aSDavid Ahern static char idle_comm[] = "<idle>"; 29449394a2aSDavid Ahern 2950e9b07e5SArnaldo Carvalho de Melo static u64 get_nsecs(void) 2960e9b07e5SArnaldo Carvalho de Melo { 2970e9b07e5SArnaldo Carvalho de Melo struct timespec ts; 2980e9b07e5SArnaldo Carvalho de Melo 2990e9b07e5SArnaldo Carvalho de Melo clock_gettime(CLOCK_MONOTONIC, &ts); 3000e9b07e5SArnaldo Carvalho de Melo 3014fc76e49SArnaldo Carvalho de Melo return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; 3020e9b07e5SArnaldo Carvalho de Melo } 3030e9b07e5SArnaldo Carvalho de Melo 3040e9b07e5SArnaldo Carvalho de Melo static void burn_nsecs(struct perf_sched *sched, u64 nsecs) 3050e9b07e5SArnaldo Carvalho de Melo { 3060e9b07e5SArnaldo Carvalho de Melo u64 T0 = get_nsecs(), T1; 3070e9b07e5SArnaldo Carvalho de Melo 3080e9b07e5SArnaldo Carvalho de Melo do { 3090e9b07e5SArnaldo Carvalho de Melo T1 = get_nsecs(); 3100e9b07e5SArnaldo Carvalho de Melo } while (T1 + sched->run_measurement_overhead < T0 + nsecs); 3110e9b07e5SArnaldo Carvalho de Melo } 3120e9b07e5SArnaldo Carvalho de Melo 3130e9b07e5SArnaldo Carvalho de Melo static void sleep_nsecs(u64 nsecs) 3140e9b07e5SArnaldo Carvalho de Melo { 3150e9b07e5SArnaldo Carvalho de Melo struct timespec ts; 3160e9b07e5SArnaldo Carvalho de Melo 3170e9b07e5SArnaldo Carvalho de Melo ts.tv_nsec = nsecs % 999999999; 3180e9b07e5SArnaldo Carvalho de Melo ts.tv_sec = nsecs / 999999999; 3190e9b07e5SArnaldo Carvalho de Melo 3200e9b07e5SArnaldo Carvalho de Melo nanosleep(&ts, NULL); 3210e9b07e5SArnaldo Carvalho de Melo } 3220e9b07e5SArnaldo Carvalho de Melo 3230e9b07e5SArnaldo Carvalho de Melo static void calibrate_run_measurement_overhead(struct perf_sched *sched) 3240e9b07e5SArnaldo Carvalho de Melo { 3254fc76e49SArnaldo Carvalho de Melo u64 T0, T1, delta, min_delta = NSEC_PER_SEC; 3260e9b07e5SArnaldo Carvalho de Melo int i; 3270e9b07e5SArnaldo Carvalho de Melo 3280e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < 10; i++) { 3290e9b07e5SArnaldo Carvalho de Melo T0 = get_nsecs(); 3300e9b07e5SArnaldo Carvalho de Melo burn_nsecs(sched, 0); 3310e9b07e5SArnaldo Carvalho de Melo T1 = get_nsecs(); 3320e9b07e5SArnaldo Carvalho de Melo delta = T1-T0; 3330e9b07e5SArnaldo Carvalho de Melo min_delta = min(min_delta, delta); 3340e9b07e5SArnaldo Carvalho de Melo } 3350e9b07e5SArnaldo Carvalho de Melo sched->run_measurement_overhead = min_delta; 3360e9b07e5SArnaldo Carvalho de Melo 3370e9b07e5SArnaldo Carvalho de Melo printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta); 3380e9b07e5SArnaldo Carvalho de Melo } 3390e9b07e5SArnaldo Carvalho de Melo 3400e9b07e5SArnaldo Carvalho de Melo static void calibrate_sleep_measurement_overhead(struct perf_sched *sched) 3410e9b07e5SArnaldo Carvalho de Melo { 3424fc76e49SArnaldo Carvalho de Melo u64 T0, T1, delta, min_delta = NSEC_PER_SEC; 3430e9b07e5SArnaldo Carvalho de Melo int i; 3440e9b07e5SArnaldo Carvalho de Melo 3450e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < 10; i++) { 3460e9b07e5SArnaldo Carvalho de Melo T0 = get_nsecs(); 3470e9b07e5SArnaldo Carvalho de Melo sleep_nsecs(10000); 3480e9b07e5SArnaldo Carvalho de Melo T1 = get_nsecs(); 3490e9b07e5SArnaldo Carvalho de Melo delta = T1-T0; 3500e9b07e5SArnaldo Carvalho de Melo min_delta = min(min_delta, delta); 3510e9b07e5SArnaldo Carvalho de Melo } 3520e9b07e5SArnaldo Carvalho de Melo min_delta -= 10000; 3530e9b07e5SArnaldo Carvalho de Melo sched->sleep_measurement_overhead = min_delta; 3540e9b07e5SArnaldo Carvalho de Melo 3550e9b07e5SArnaldo Carvalho de Melo printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta); 3560e9b07e5SArnaldo Carvalho de Melo } 3570e9b07e5SArnaldo Carvalho de Melo 3580e9b07e5SArnaldo Carvalho de Melo static struct sched_atom * 3590e9b07e5SArnaldo Carvalho de Melo get_new_event(struct task_desc *task, u64 timestamp) 3600e9b07e5SArnaldo Carvalho de Melo { 3610e9b07e5SArnaldo Carvalho de Melo struct sched_atom *event = zalloc(sizeof(*event)); 3620e9b07e5SArnaldo Carvalho de Melo unsigned long idx = task->nr_events; 3630e9b07e5SArnaldo Carvalho de Melo size_t size; 3640e9b07e5SArnaldo Carvalho de Melo 3650e9b07e5SArnaldo Carvalho de Melo event->timestamp = timestamp; 3660e9b07e5SArnaldo Carvalho de Melo event->nr = idx; 3670e9b07e5SArnaldo Carvalho de Melo 3680e9b07e5SArnaldo Carvalho de Melo task->nr_events++; 3690e9b07e5SArnaldo Carvalho de Melo size = sizeof(struct sched_atom *) * task->nr_events; 3700e9b07e5SArnaldo Carvalho de Melo task->atoms = realloc(task->atoms, size); 3710e9b07e5SArnaldo Carvalho de Melo BUG_ON(!task->atoms); 3720e9b07e5SArnaldo Carvalho de Melo 3730e9b07e5SArnaldo Carvalho de Melo task->atoms[idx] = event; 3740e9b07e5SArnaldo Carvalho de Melo 3750e9b07e5SArnaldo Carvalho de Melo return event; 3760e9b07e5SArnaldo Carvalho de Melo } 3770e9b07e5SArnaldo Carvalho de Melo 3780e9b07e5SArnaldo Carvalho de Melo static struct sched_atom *last_event(struct task_desc *task) 3790e9b07e5SArnaldo Carvalho de Melo { 3800e9b07e5SArnaldo Carvalho de Melo if (!task->nr_events) 3810e9b07e5SArnaldo Carvalho de Melo return NULL; 3820e9b07e5SArnaldo Carvalho de Melo 3830e9b07e5SArnaldo Carvalho de Melo return task->atoms[task->nr_events - 1]; 3840e9b07e5SArnaldo Carvalho de Melo } 3850e9b07e5SArnaldo Carvalho de Melo 3860e9b07e5SArnaldo Carvalho de Melo static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task, 3870e9b07e5SArnaldo Carvalho de Melo u64 timestamp, u64 duration) 3880e9b07e5SArnaldo Carvalho de Melo { 3890e9b07e5SArnaldo Carvalho de Melo struct sched_atom *event, *curr_event = last_event(task); 3900e9b07e5SArnaldo Carvalho de Melo 3910e9b07e5SArnaldo Carvalho de Melo /* 3920e9b07e5SArnaldo Carvalho de Melo * optimize an existing RUN event by merging this one 3930e9b07e5SArnaldo Carvalho de Melo * to it: 3940e9b07e5SArnaldo Carvalho de Melo */ 3950e9b07e5SArnaldo Carvalho de Melo if (curr_event && curr_event->type == SCHED_EVENT_RUN) { 3960e9b07e5SArnaldo Carvalho de Melo sched->nr_run_events_optimized++; 3970e9b07e5SArnaldo Carvalho de Melo curr_event->duration += duration; 3980e9b07e5SArnaldo Carvalho de Melo return; 3990e9b07e5SArnaldo Carvalho de Melo } 4000e9b07e5SArnaldo Carvalho de Melo 4010e9b07e5SArnaldo Carvalho de Melo event = get_new_event(task, timestamp); 4020e9b07e5SArnaldo Carvalho de Melo 4030e9b07e5SArnaldo Carvalho de Melo event->type = SCHED_EVENT_RUN; 4040e9b07e5SArnaldo Carvalho de Melo event->duration = duration; 4050e9b07e5SArnaldo Carvalho de Melo 4060e9b07e5SArnaldo Carvalho de Melo sched->nr_run_events++; 4070e9b07e5SArnaldo Carvalho de Melo } 4080e9b07e5SArnaldo Carvalho de Melo 4090e9b07e5SArnaldo Carvalho de Melo static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *task, 4100e9b07e5SArnaldo Carvalho de Melo u64 timestamp, struct task_desc *wakee) 4110e9b07e5SArnaldo Carvalho de Melo { 4120e9b07e5SArnaldo Carvalho de Melo struct sched_atom *event, *wakee_event; 4130e9b07e5SArnaldo Carvalho de Melo 4140e9b07e5SArnaldo Carvalho de Melo event = get_new_event(task, timestamp); 4150e9b07e5SArnaldo Carvalho de Melo event->type = SCHED_EVENT_WAKEUP; 4160e9b07e5SArnaldo Carvalho de Melo event->wakee = wakee; 4170e9b07e5SArnaldo Carvalho de Melo 4180e9b07e5SArnaldo Carvalho de Melo wakee_event = last_event(wakee); 4190e9b07e5SArnaldo Carvalho de Melo if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) { 4200e9b07e5SArnaldo Carvalho de Melo sched->targetless_wakeups++; 4210e9b07e5SArnaldo Carvalho de Melo return; 4220e9b07e5SArnaldo Carvalho de Melo } 4230e9b07e5SArnaldo Carvalho de Melo if (wakee_event->wait_sem) { 4240e9b07e5SArnaldo Carvalho de Melo sched->multitarget_wakeups++; 4250e9b07e5SArnaldo Carvalho de Melo return; 4260e9b07e5SArnaldo Carvalho de Melo } 4270e9b07e5SArnaldo Carvalho de Melo 4280e9b07e5SArnaldo Carvalho de Melo wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem)); 4290e9b07e5SArnaldo Carvalho de Melo sem_init(wakee_event->wait_sem, 0, 0); 4300e9b07e5SArnaldo Carvalho de Melo wakee_event->specific_wait = 1; 4310e9b07e5SArnaldo Carvalho de Melo event->wait_sem = wakee_event->wait_sem; 4320e9b07e5SArnaldo Carvalho de Melo 4330e9b07e5SArnaldo Carvalho de Melo sched->nr_wakeup_events++; 4340e9b07e5SArnaldo Carvalho de Melo } 4350e9b07e5SArnaldo Carvalho de Melo 4360e9b07e5SArnaldo Carvalho de Melo static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task, 4370e9b07e5SArnaldo Carvalho de Melo u64 timestamp, u64 task_state __maybe_unused) 4380e9b07e5SArnaldo Carvalho de Melo { 4390e9b07e5SArnaldo Carvalho de Melo struct sched_atom *event = get_new_event(task, timestamp); 4400e9b07e5SArnaldo Carvalho de Melo 4410e9b07e5SArnaldo Carvalho de Melo event->type = SCHED_EVENT_SLEEP; 4420e9b07e5SArnaldo Carvalho de Melo 4430e9b07e5SArnaldo Carvalho de Melo sched->nr_sleep_events++; 4440e9b07e5SArnaldo Carvalho de Melo } 4450e9b07e5SArnaldo Carvalho de Melo 4460e9b07e5SArnaldo Carvalho de Melo static struct task_desc *register_pid(struct perf_sched *sched, 4470e9b07e5SArnaldo Carvalho de Melo unsigned long pid, const char *comm) 4480e9b07e5SArnaldo Carvalho de Melo { 4490e9b07e5SArnaldo Carvalho de Melo struct task_desc *task; 450cb06ac25SYunlong Song static int pid_max; 4510e9b07e5SArnaldo Carvalho de Melo 452cb06ac25SYunlong Song if (sched->pid_to_task == NULL) { 453cb06ac25SYunlong Song if (sysctl__read_int("kernel/pid_max", &pid_max) < 0) 454cb06ac25SYunlong Song pid_max = MAX_PID; 455cb06ac25SYunlong Song BUG_ON((sched->pid_to_task = calloc(pid_max, sizeof(struct task_desc *))) == NULL); 456cb06ac25SYunlong Song } 4573a423a5cSYunlong Song if (pid >= (unsigned long)pid_max) { 4583a423a5cSYunlong Song BUG_ON((sched->pid_to_task = realloc(sched->pid_to_task, (pid + 1) * 4593a423a5cSYunlong Song sizeof(struct task_desc *))) == NULL); 4603a423a5cSYunlong Song while (pid >= (unsigned long)pid_max) 4613a423a5cSYunlong Song sched->pid_to_task[pid_max++] = NULL; 4623a423a5cSYunlong Song } 4630e9b07e5SArnaldo Carvalho de Melo 4640e9b07e5SArnaldo Carvalho de Melo task = sched->pid_to_task[pid]; 4650e9b07e5SArnaldo Carvalho de Melo 4660e9b07e5SArnaldo Carvalho de Melo if (task) 4670e9b07e5SArnaldo Carvalho de Melo return task; 4680e9b07e5SArnaldo Carvalho de Melo 4690e9b07e5SArnaldo Carvalho de Melo task = zalloc(sizeof(*task)); 4700e9b07e5SArnaldo Carvalho de Melo task->pid = pid; 4710e9b07e5SArnaldo Carvalho de Melo task->nr = sched->nr_tasks; 4720e9b07e5SArnaldo Carvalho de Melo strcpy(task->comm, comm); 4730e9b07e5SArnaldo Carvalho de Melo /* 4740e9b07e5SArnaldo Carvalho de Melo * every task starts in sleeping state - this gets ignored 4750e9b07e5SArnaldo Carvalho de Melo * if there's no wakeup pointing to this sleep state: 4760e9b07e5SArnaldo Carvalho de Melo */ 4770e9b07e5SArnaldo Carvalho de Melo add_sched_event_sleep(sched, task, 0, 0); 4780e9b07e5SArnaldo Carvalho de Melo 4790e9b07e5SArnaldo Carvalho de Melo sched->pid_to_task[pid] = task; 4800e9b07e5SArnaldo Carvalho de Melo sched->nr_tasks++; 4810755bc4dSYunlong Song sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_desc *)); 4820e9b07e5SArnaldo Carvalho de Melo BUG_ON(!sched->tasks); 4830e9b07e5SArnaldo Carvalho de Melo sched->tasks[task->nr] = task; 4840e9b07e5SArnaldo Carvalho de Melo 485bb963e16SNamhyung Kim if (verbose > 0) 4860e9b07e5SArnaldo Carvalho de Melo printf("registered task #%ld, PID %ld (%s)\n", sched->nr_tasks, pid, comm); 4870e9b07e5SArnaldo Carvalho de Melo 4880e9b07e5SArnaldo Carvalho de Melo return task; 4890e9b07e5SArnaldo Carvalho de Melo } 4900e9b07e5SArnaldo Carvalho de Melo 4910e9b07e5SArnaldo Carvalho de Melo 4920e9b07e5SArnaldo Carvalho de Melo static void print_task_traces(struct perf_sched *sched) 4930e9b07e5SArnaldo Carvalho de Melo { 4940e9b07e5SArnaldo Carvalho de Melo struct task_desc *task; 4950e9b07e5SArnaldo Carvalho de Melo unsigned long i; 4960e9b07e5SArnaldo Carvalho de Melo 4970e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->nr_tasks; i++) { 4980e9b07e5SArnaldo Carvalho de Melo task = sched->tasks[i]; 4990e9b07e5SArnaldo Carvalho de Melo printf("task %6ld (%20s:%10ld), nr_events: %ld\n", 5000e9b07e5SArnaldo Carvalho de Melo task->nr, task->comm, task->pid, task->nr_events); 5010e9b07e5SArnaldo Carvalho de Melo } 5020e9b07e5SArnaldo Carvalho de Melo } 5030e9b07e5SArnaldo Carvalho de Melo 5040e9b07e5SArnaldo Carvalho de Melo static void add_cross_task_wakeups(struct perf_sched *sched) 5050e9b07e5SArnaldo Carvalho de Melo { 5060e9b07e5SArnaldo Carvalho de Melo struct task_desc *task1, *task2; 5070e9b07e5SArnaldo Carvalho de Melo unsigned long i, j; 5080e9b07e5SArnaldo Carvalho de Melo 5090e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->nr_tasks; i++) { 5100e9b07e5SArnaldo Carvalho de Melo task1 = sched->tasks[i]; 5110e9b07e5SArnaldo Carvalho de Melo j = i + 1; 5120e9b07e5SArnaldo Carvalho de Melo if (j == sched->nr_tasks) 5130e9b07e5SArnaldo Carvalho de Melo j = 0; 5140e9b07e5SArnaldo Carvalho de Melo task2 = sched->tasks[j]; 5150e9b07e5SArnaldo Carvalho de Melo add_sched_event_wakeup(sched, task1, 0, task2); 5160e9b07e5SArnaldo Carvalho de Melo } 5170e9b07e5SArnaldo Carvalho de Melo } 5180e9b07e5SArnaldo Carvalho de Melo 5190e9b07e5SArnaldo Carvalho de Melo static void perf_sched__process_event(struct perf_sched *sched, 5200e9b07e5SArnaldo Carvalho de Melo struct sched_atom *atom) 5210e9b07e5SArnaldo Carvalho de Melo { 5220e9b07e5SArnaldo Carvalho de Melo int ret = 0; 5230e9b07e5SArnaldo Carvalho de Melo 5240e9b07e5SArnaldo Carvalho de Melo switch (atom->type) { 5250e9b07e5SArnaldo Carvalho de Melo case SCHED_EVENT_RUN: 5260e9b07e5SArnaldo Carvalho de Melo burn_nsecs(sched, atom->duration); 5270e9b07e5SArnaldo Carvalho de Melo break; 5280e9b07e5SArnaldo Carvalho de Melo case SCHED_EVENT_SLEEP: 5290e9b07e5SArnaldo Carvalho de Melo if (atom->wait_sem) 5300e9b07e5SArnaldo Carvalho de Melo ret = sem_wait(atom->wait_sem); 5310e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 5320e9b07e5SArnaldo Carvalho de Melo break; 5330e9b07e5SArnaldo Carvalho de Melo case SCHED_EVENT_WAKEUP: 5340e9b07e5SArnaldo Carvalho de Melo if (atom->wait_sem) 5350e9b07e5SArnaldo Carvalho de Melo ret = sem_post(atom->wait_sem); 5360e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 5370e9b07e5SArnaldo Carvalho de Melo break; 5380e9b07e5SArnaldo Carvalho de Melo case SCHED_EVENT_MIGRATION: 5390e9b07e5SArnaldo Carvalho de Melo break; 5400e9b07e5SArnaldo Carvalho de Melo default: 5410e9b07e5SArnaldo Carvalho de Melo BUG_ON(1); 5420e9b07e5SArnaldo Carvalho de Melo } 5430e9b07e5SArnaldo Carvalho de Melo } 5440e9b07e5SArnaldo Carvalho de Melo 5450e9b07e5SArnaldo Carvalho de Melo static u64 get_cpu_usage_nsec_parent(void) 5460e9b07e5SArnaldo Carvalho de Melo { 5470e9b07e5SArnaldo Carvalho de Melo struct rusage ru; 5480e9b07e5SArnaldo Carvalho de Melo u64 sum; 5490e9b07e5SArnaldo Carvalho de Melo int err; 5500e9b07e5SArnaldo Carvalho de Melo 5510e9b07e5SArnaldo Carvalho de Melo err = getrusage(RUSAGE_SELF, &ru); 5520e9b07e5SArnaldo Carvalho de Melo BUG_ON(err); 5530e9b07e5SArnaldo Carvalho de Melo 5544fc76e49SArnaldo Carvalho de Melo sum = ru.ru_utime.tv_sec * NSEC_PER_SEC + ru.ru_utime.tv_usec * NSEC_PER_USEC; 5554fc76e49SArnaldo Carvalho de Melo sum += ru.ru_stime.tv_sec * NSEC_PER_SEC + ru.ru_stime.tv_usec * NSEC_PER_USEC; 5560e9b07e5SArnaldo Carvalho de Melo 5570e9b07e5SArnaldo Carvalho de Melo return sum; 5580e9b07e5SArnaldo Carvalho de Melo } 5590e9b07e5SArnaldo Carvalho de Melo 560939cda52SYunlong Song static int self_open_counters(struct perf_sched *sched, unsigned long cur_task) 5610e9b07e5SArnaldo Carvalho de Melo { 5620e9b07e5SArnaldo Carvalho de Melo struct perf_event_attr attr; 563939cda52SYunlong Song char sbuf[STRERR_BUFSIZE], info[STRERR_BUFSIZE]; 5640e9b07e5SArnaldo Carvalho de Melo int fd; 565939cda52SYunlong Song struct rlimit limit; 566939cda52SYunlong Song bool need_privilege = false; 5670e9b07e5SArnaldo Carvalho de Melo 5680e9b07e5SArnaldo Carvalho de Melo memset(&attr, 0, sizeof(attr)); 5690e9b07e5SArnaldo Carvalho de Melo 5700e9b07e5SArnaldo Carvalho de Melo attr.type = PERF_TYPE_SOFTWARE; 5710e9b07e5SArnaldo Carvalho de Melo attr.config = PERF_COUNT_SW_TASK_CLOCK; 5720e9b07e5SArnaldo Carvalho de Melo 573939cda52SYunlong Song force_again: 57457480d2cSYann Droneaud fd = sys_perf_event_open(&attr, 0, -1, -1, 57557480d2cSYann Droneaud perf_event_open_cloexec_flag()); 5760e9b07e5SArnaldo Carvalho de Melo 5771aff59beSYunlong Song if (fd < 0) { 578939cda52SYunlong Song if (errno == EMFILE) { 579939cda52SYunlong Song if (sched->force) { 580939cda52SYunlong Song BUG_ON(getrlimit(RLIMIT_NOFILE, &limit) == -1); 581939cda52SYunlong Song limit.rlim_cur += sched->nr_tasks - cur_task; 582939cda52SYunlong Song if (limit.rlim_cur > limit.rlim_max) { 583939cda52SYunlong Song limit.rlim_max = limit.rlim_cur; 584939cda52SYunlong Song need_privilege = true; 585939cda52SYunlong Song } 586939cda52SYunlong Song if (setrlimit(RLIMIT_NOFILE, &limit) == -1) { 587939cda52SYunlong Song if (need_privilege && errno == EPERM) 588939cda52SYunlong Song strcpy(info, "Need privilege\n"); 589939cda52SYunlong Song } else 590939cda52SYunlong Song goto force_again; 591939cda52SYunlong Song } else 592939cda52SYunlong Song strcpy(info, "Have a try with -f option\n"); 593939cda52SYunlong Song } 59460b7d14aSNamhyung Kim pr_err("Error: sys_perf_event_open() syscall returned " 595939cda52SYunlong Song "with %d (%s)\n%s", fd, 596c8b5f2c9SArnaldo Carvalho de Melo str_error_r(errno, sbuf, sizeof(sbuf)), info); 5971aff59beSYunlong Song exit(EXIT_FAILURE); 5981aff59beSYunlong Song } 5990e9b07e5SArnaldo Carvalho de Melo return fd; 6000e9b07e5SArnaldo Carvalho de Melo } 6010e9b07e5SArnaldo Carvalho de Melo 6020e9b07e5SArnaldo Carvalho de Melo static u64 get_cpu_usage_nsec_self(int fd) 6030e9b07e5SArnaldo Carvalho de Melo { 6040e9b07e5SArnaldo Carvalho de Melo u64 runtime; 6050e9b07e5SArnaldo Carvalho de Melo int ret; 6060e9b07e5SArnaldo Carvalho de Melo 6070e9b07e5SArnaldo Carvalho de Melo ret = read(fd, &runtime, sizeof(runtime)); 6080e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret != sizeof(runtime)); 6090e9b07e5SArnaldo Carvalho de Melo 6100e9b07e5SArnaldo Carvalho de Melo return runtime; 6110e9b07e5SArnaldo Carvalho de Melo } 6120e9b07e5SArnaldo Carvalho de Melo 6130e9b07e5SArnaldo Carvalho de Melo struct sched_thread_parms { 6140e9b07e5SArnaldo Carvalho de Melo struct task_desc *task; 6150e9b07e5SArnaldo Carvalho de Melo struct perf_sched *sched; 61608097abcSYunlong Song int fd; 6170e9b07e5SArnaldo Carvalho de Melo }; 6180e9b07e5SArnaldo Carvalho de Melo 6190e9b07e5SArnaldo Carvalho de Melo static void *thread_func(void *ctx) 6200e9b07e5SArnaldo Carvalho de Melo { 6210e9b07e5SArnaldo Carvalho de Melo struct sched_thread_parms *parms = ctx; 6220e9b07e5SArnaldo Carvalho de Melo struct task_desc *this_task = parms->task; 6230e9b07e5SArnaldo Carvalho de Melo struct perf_sched *sched = parms->sched; 6240e9b07e5SArnaldo Carvalho de Melo u64 cpu_usage_0, cpu_usage_1; 6250e9b07e5SArnaldo Carvalho de Melo unsigned long i, ret; 6260e9b07e5SArnaldo Carvalho de Melo char comm2[22]; 62708097abcSYunlong Song int fd = parms->fd; 6280e9b07e5SArnaldo Carvalho de Melo 62974cf249dSArnaldo Carvalho de Melo zfree(&parms); 6300e9b07e5SArnaldo Carvalho de Melo 6310e9b07e5SArnaldo Carvalho de Melo sprintf(comm2, ":%s", this_task->comm); 6320e9b07e5SArnaldo Carvalho de Melo prctl(PR_SET_NAME, comm2); 6330e9b07e5SArnaldo Carvalho de Melo if (fd < 0) 6340e9b07e5SArnaldo Carvalho de Melo return NULL; 6350e9b07e5SArnaldo Carvalho de Melo again: 6360e9b07e5SArnaldo Carvalho de Melo ret = sem_post(&this_task->ready_for_work); 6370e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 6380e9b07e5SArnaldo Carvalho de Melo ret = pthread_mutex_lock(&sched->start_work_mutex); 6390e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 6400e9b07e5SArnaldo Carvalho de Melo ret = pthread_mutex_unlock(&sched->start_work_mutex); 6410e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 6420e9b07e5SArnaldo Carvalho de Melo 6430e9b07e5SArnaldo Carvalho de Melo cpu_usage_0 = get_cpu_usage_nsec_self(fd); 6440e9b07e5SArnaldo Carvalho de Melo 6450e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < this_task->nr_events; i++) { 6460e9b07e5SArnaldo Carvalho de Melo this_task->curr_event = i; 6470e9b07e5SArnaldo Carvalho de Melo perf_sched__process_event(sched, this_task->atoms[i]); 6480e9b07e5SArnaldo Carvalho de Melo } 6490e9b07e5SArnaldo Carvalho de Melo 6500e9b07e5SArnaldo Carvalho de Melo cpu_usage_1 = get_cpu_usage_nsec_self(fd); 6510e9b07e5SArnaldo Carvalho de Melo this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; 6520e9b07e5SArnaldo Carvalho de Melo ret = sem_post(&this_task->work_done_sem); 6530e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 6540e9b07e5SArnaldo Carvalho de Melo 6550e9b07e5SArnaldo Carvalho de Melo ret = pthread_mutex_lock(&sched->work_done_wait_mutex); 6560e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 6570e9b07e5SArnaldo Carvalho de Melo ret = pthread_mutex_unlock(&sched->work_done_wait_mutex); 6580e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 6590e9b07e5SArnaldo Carvalho de Melo 6600e9b07e5SArnaldo Carvalho de Melo goto again; 6610e9b07e5SArnaldo Carvalho de Melo } 6620e9b07e5SArnaldo Carvalho de Melo 6630e9b07e5SArnaldo Carvalho de Melo static void create_tasks(struct perf_sched *sched) 6640e9b07e5SArnaldo Carvalho de Melo { 6650e9b07e5SArnaldo Carvalho de Melo struct task_desc *task; 6660e9b07e5SArnaldo Carvalho de Melo pthread_attr_t attr; 6670e9b07e5SArnaldo Carvalho de Melo unsigned long i; 6680e9b07e5SArnaldo Carvalho de Melo int err; 6690e9b07e5SArnaldo Carvalho de Melo 6700e9b07e5SArnaldo Carvalho de Melo err = pthread_attr_init(&attr); 6710e9b07e5SArnaldo Carvalho de Melo BUG_ON(err); 6720e9b07e5SArnaldo Carvalho de Melo err = pthread_attr_setstacksize(&attr, 673d08c84e0SArnaldo Carvalho de Melo (size_t) max(16 * 1024, (int)PTHREAD_STACK_MIN)); 6740e9b07e5SArnaldo Carvalho de Melo BUG_ON(err); 6750e9b07e5SArnaldo Carvalho de Melo err = pthread_mutex_lock(&sched->start_work_mutex); 6760e9b07e5SArnaldo Carvalho de Melo BUG_ON(err); 6770e9b07e5SArnaldo Carvalho de Melo err = pthread_mutex_lock(&sched->work_done_wait_mutex); 6780e9b07e5SArnaldo Carvalho de Melo BUG_ON(err); 6790e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->nr_tasks; i++) { 6800e9b07e5SArnaldo Carvalho de Melo struct sched_thread_parms *parms = malloc(sizeof(*parms)); 6810e9b07e5SArnaldo Carvalho de Melo BUG_ON(parms == NULL); 6820e9b07e5SArnaldo Carvalho de Melo parms->task = task = sched->tasks[i]; 6830e9b07e5SArnaldo Carvalho de Melo parms->sched = sched; 684939cda52SYunlong Song parms->fd = self_open_counters(sched, i); 6850e9b07e5SArnaldo Carvalho de Melo sem_init(&task->sleep_sem, 0, 0); 6860e9b07e5SArnaldo Carvalho de Melo sem_init(&task->ready_for_work, 0, 0); 6870e9b07e5SArnaldo Carvalho de Melo sem_init(&task->work_done_sem, 0, 0); 6880e9b07e5SArnaldo Carvalho de Melo task->curr_event = 0; 6890e9b07e5SArnaldo Carvalho de Melo err = pthread_create(&task->thread, &attr, thread_func, parms); 6900e9b07e5SArnaldo Carvalho de Melo BUG_ON(err); 6910e9b07e5SArnaldo Carvalho de Melo } 6920e9b07e5SArnaldo Carvalho de Melo } 6930e9b07e5SArnaldo Carvalho de Melo 6940e9b07e5SArnaldo Carvalho de Melo static void wait_for_tasks(struct perf_sched *sched) 6950e9b07e5SArnaldo Carvalho de Melo { 6960e9b07e5SArnaldo Carvalho de Melo u64 cpu_usage_0, cpu_usage_1; 6970e9b07e5SArnaldo Carvalho de Melo struct task_desc *task; 6980e9b07e5SArnaldo Carvalho de Melo unsigned long i, ret; 6990e9b07e5SArnaldo Carvalho de Melo 7000e9b07e5SArnaldo Carvalho de Melo sched->start_time = get_nsecs(); 7010e9b07e5SArnaldo Carvalho de Melo sched->cpu_usage = 0; 7020e9b07e5SArnaldo Carvalho de Melo pthread_mutex_unlock(&sched->work_done_wait_mutex); 7030e9b07e5SArnaldo Carvalho de Melo 7040e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->nr_tasks; i++) { 7050e9b07e5SArnaldo Carvalho de Melo task = sched->tasks[i]; 7060e9b07e5SArnaldo Carvalho de Melo ret = sem_wait(&task->ready_for_work); 7070e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 7080e9b07e5SArnaldo Carvalho de Melo sem_init(&task->ready_for_work, 0, 0); 7090e9b07e5SArnaldo Carvalho de Melo } 7100e9b07e5SArnaldo Carvalho de Melo ret = pthread_mutex_lock(&sched->work_done_wait_mutex); 7110e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 7120e9b07e5SArnaldo Carvalho de Melo 7130e9b07e5SArnaldo Carvalho de Melo cpu_usage_0 = get_cpu_usage_nsec_parent(); 7140e9b07e5SArnaldo Carvalho de Melo 7150e9b07e5SArnaldo Carvalho de Melo pthread_mutex_unlock(&sched->start_work_mutex); 7160e9b07e5SArnaldo Carvalho de Melo 7170e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->nr_tasks; i++) { 7180e9b07e5SArnaldo Carvalho de Melo task = sched->tasks[i]; 7190e9b07e5SArnaldo Carvalho de Melo ret = sem_wait(&task->work_done_sem); 7200e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 7210e9b07e5SArnaldo Carvalho de Melo sem_init(&task->work_done_sem, 0, 0); 7220e9b07e5SArnaldo Carvalho de Melo sched->cpu_usage += task->cpu_usage; 7230e9b07e5SArnaldo Carvalho de Melo task->cpu_usage = 0; 7240e9b07e5SArnaldo Carvalho de Melo } 7250e9b07e5SArnaldo Carvalho de Melo 7260e9b07e5SArnaldo Carvalho de Melo cpu_usage_1 = get_cpu_usage_nsec_parent(); 7270e9b07e5SArnaldo Carvalho de Melo if (!sched->runavg_cpu_usage) 7280e9b07e5SArnaldo Carvalho de Melo sched->runavg_cpu_usage = sched->cpu_usage; 729ff5f3bbdSYunlong Song sched->runavg_cpu_usage = (sched->runavg_cpu_usage * (sched->replay_repeat - 1) + sched->cpu_usage) / sched->replay_repeat; 7300e9b07e5SArnaldo Carvalho de Melo 7310e9b07e5SArnaldo Carvalho de Melo sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0; 7320e9b07e5SArnaldo Carvalho de Melo if (!sched->runavg_parent_cpu_usage) 7330e9b07e5SArnaldo Carvalho de Melo sched->runavg_parent_cpu_usage = sched->parent_cpu_usage; 734ff5f3bbdSYunlong Song sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * (sched->replay_repeat - 1) + 735ff5f3bbdSYunlong Song sched->parent_cpu_usage)/sched->replay_repeat; 7360e9b07e5SArnaldo Carvalho de Melo 7370e9b07e5SArnaldo Carvalho de Melo ret = pthread_mutex_lock(&sched->start_work_mutex); 7380e9b07e5SArnaldo Carvalho de Melo BUG_ON(ret); 7390e9b07e5SArnaldo Carvalho de Melo 7400e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->nr_tasks; i++) { 7410e9b07e5SArnaldo Carvalho de Melo task = sched->tasks[i]; 7420e9b07e5SArnaldo Carvalho de Melo sem_init(&task->sleep_sem, 0, 0); 7430e9b07e5SArnaldo Carvalho de Melo task->curr_event = 0; 7440e9b07e5SArnaldo Carvalho de Melo } 7450e9b07e5SArnaldo Carvalho de Melo } 7460e9b07e5SArnaldo Carvalho de Melo 7470e9b07e5SArnaldo Carvalho de Melo static void run_one_test(struct perf_sched *sched) 7480e9b07e5SArnaldo Carvalho de Melo { 7490e9b07e5SArnaldo Carvalho de Melo u64 T0, T1, delta, avg_delta, fluct; 7500e9b07e5SArnaldo Carvalho de Melo 7510e9b07e5SArnaldo Carvalho de Melo T0 = get_nsecs(); 7520e9b07e5SArnaldo Carvalho de Melo wait_for_tasks(sched); 7530e9b07e5SArnaldo Carvalho de Melo T1 = get_nsecs(); 7540e9b07e5SArnaldo Carvalho de Melo 7550e9b07e5SArnaldo Carvalho de Melo delta = T1 - T0; 7560e9b07e5SArnaldo Carvalho de Melo sched->sum_runtime += delta; 7570e9b07e5SArnaldo Carvalho de Melo sched->nr_runs++; 7580e9b07e5SArnaldo Carvalho de Melo 7590e9b07e5SArnaldo Carvalho de Melo avg_delta = sched->sum_runtime / sched->nr_runs; 7600e9b07e5SArnaldo Carvalho de Melo if (delta < avg_delta) 7610e9b07e5SArnaldo Carvalho de Melo fluct = avg_delta - delta; 7620e9b07e5SArnaldo Carvalho de Melo else 7630e9b07e5SArnaldo Carvalho de Melo fluct = delta - avg_delta; 7640e9b07e5SArnaldo Carvalho de Melo sched->sum_fluct += fluct; 7650e9b07e5SArnaldo Carvalho de Melo if (!sched->run_avg) 7660e9b07e5SArnaldo Carvalho de Melo sched->run_avg = delta; 767ff5f3bbdSYunlong Song sched->run_avg = (sched->run_avg * (sched->replay_repeat - 1) + delta) / sched->replay_repeat; 7680e9b07e5SArnaldo Carvalho de Melo 7694fc76e49SArnaldo Carvalho de Melo printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / NSEC_PER_MSEC); 7700e9b07e5SArnaldo Carvalho de Melo 7714fc76e49SArnaldo Carvalho de Melo printf("ravg: %0.2f, ", (double)sched->run_avg / NSEC_PER_MSEC); 7720e9b07e5SArnaldo Carvalho de Melo 7730e9b07e5SArnaldo Carvalho de Melo printf("cpu: %0.2f / %0.2f", 7744fc76e49SArnaldo Carvalho de Melo (double)sched->cpu_usage / NSEC_PER_MSEC, (double)sched->runavg_cpu_usage / NSEC_PER_MSEC); 7750e9b07e5SArnaldo Carvalho de Melo 7760e9b07e5SArnaldo Carvalho de Melo #if 0 7770e9b07e5SArnaldo Carvalho de Melo /* 7780e9b07e5SArnaldo Carvalho de Melo * rusage statistics done by the parent, these are less 7790e9b07e5SArnaldo Carvalho de Melo * accurate than the sched->sum_exec_runtime based statistics: 7800e9b07e5SArnaldo Carvalho de Melo */ 7810e9b07e5SArnaldo Carvalho de Melo printf(" [%0.2f / %0.2f]", 7824fc76e49SArnaldo Carvalho de Melo (double)sched->parent_cpu_usage / NSEC_PER_MSEC, 7834fc76e49SArnaldo Carvalho de Melo (double)sched->runavg_parent_cpu_usage / NSEC_PER_MSEC); 7840e9b07e5SArnaldo Carvalho de Melo #endif 7850e9b07e5SArnaldo Carvalho de Melo 7860e9b07e5SArnaldo Carvalho de Melo printf("\n"); 7870e9b07e5SArnaldo Carvalho de Melo 7880e9b07e5SArnaldo Carvalho de Melo if (sched->nr_sleep_corrections) 7890e9b07e5SArnaldo Carvalho de Melo printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections); 7900e9b07e5SArnaldo Carvalho de Melo sched->nr_sleep_corrections = 0; 7910e9b07e5SArnaldo Carvalho de Melo } 7920e9b07e5SArnaldo Carvalho de Melo 7930e9b07e5SArnaldo Carvalho de Melo static void test_calibrations(struct perf_sched *sched) 7940e9b07e5SArnaldo Carvalho de Melo { 7950e9b07e5SArnaldo Carvalho de Melo u64 T0, T1; 7960e9b07e5SArnaldo Carvalho de Melo 7970e9b07e5SArnaldo Carvalho de Melo T0 = get_nsecs(); 7984fc76e49SArnaldo Carvalho de Melo burn_nsecs(sched, NSEC_PER_MSEC); 7990e9b07e5SArnaldo Carvalho de Melo T1 = get_nsecs(); 8000e9b07e5SArnaldo Carvalho de Melo 8010e9b07e5SArnaldo Carvalho de Melo printf("the run test took %" PRIu64 " nsecs\n", T1 - T0); 8020e9b07e5SArnaldo Carvalho de Melo 8030e9b07e5SArnaldo Carvalho de Melo T0 = get_nsecs(); 8044fc76e49SArnaldo Carvalho de Melo sleep_nsecs(NSEC_PER_MSEC); 8050e9b07e5SArnaldo Carvalho de Melo T1 = get_nsecs(); 8060e9b07e5SArnaldo Carvalho de Melo 8070e9b07e5SArnaldo Carvalho de Melo printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0); 8080e9b07e5SArnaldo Carvalho de Melo } 8090e9b07e5SArnaldo Carvalho de Melo 810a116e05dSArnaldo Carvalho de Melo static int 8110e9b07e5SArnaldo Carvalho de Melo replay_wakeup_event(struct perf_sched *sched, 81232dcd021SJiri Olsa struct evsel *evsel, struct perf_sample *sample, 8139ec3f4e4SArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 814ec156764SIngo Molnar { 815efc0cdc9SArnaldo Carvalho de Melo const char *comm = evsel__strval(evsel, sample, "comm"); 816efc0cdc9SArnaldo Carvalho de Melo const u32 pid = evsel__intval(evsel, sample, "pid"); 817419ab0d6SFrederic Weisbecker struct task_desc *waker, *wakee; 818419ab0d6SFrederic Weisbecker 819bb963e16SNamhyung Kim if (verbose > 0) { 8202b7fcbc5SArnaldo Carvalho de Melo printf("sched_wakeup event %p\n", evsel); 821419ab0d6SFrederic Weisbecker 8229ec3f4e4SArnaldo Carvalho de Melo printf(" ... pid %d woke up %s/%d\n", sample->tid, comm, pid); 823419ab0d6SFrederic Weisbecker } 824419ab0d6SFrederic Weisbecker 8252b7fcbc5SArnaldo Carvalho de Melo waker = register_pid(sched, sample->tid, "<unknown>"); 8269ec3f4e4SArnaldo Carvalho de Melo wakee = register_pid(sched, pid, comm); 827419ab0d6SFrederic Weisbecker 8280e9b07e5SArnaldo Carvalho de Melo add_sched_event_wakeup(sched, waker, sample->time, wakee); 829a116e05dSArnaldo Carvalho de Melo return 0; 830419ab0d6SFrederic Weisbecker } 831419ab0d6SFrederic Weisbecker 8329ec3f4e4SArnaldo Carvalho de Melo static int replay_switch_event(struct perf_sched *sched, 83332dcd021SJiri Olsa struct evsel *evsel, 8349ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, 8359ec3f4e4SArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 836419ab0d6SFrederic Weisbecker { 837efc0cdc9SArnaldo Carvalho de Melo const char *prev_comm = evsel__strval(evsel, sample, "prev_comm"), 838efc0cdc9SArnaldo Carvalho de Melo *next_comm = evsel__strval(evsel, sample, "next_comm"); 839efc0cdc9SArnaldo Carvalho de Melo const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), 840efc0cdc9SArnaldo Carvalho de Melo next_pid = evsel__intval(evsel, sample, "next_pid"); 841efc0cdc9SArnaldo Carvalho de Melo const u64 prev_state = evsel__intval(evsel, sample, "prev_state"); 8421d037ca1SIrina Tirdea struct task_desc *prev, __maybe_unused *next; 8437f7f8d0bSArnaldo Carvalho de Melo u64 timestamp0, timestamp = sample->time; 8447f7f8d0bSArnaldo Carvalho de Melo int cpu = sample->cpu; 845fbf94829SIngo Molnar s64 delta; 846fbf94829SIngo Molnar 847bb963e16SNamhyung Kim if (verbose > 0) 8482b7fcbc5SArnaldo Carvalho de Melo printf("sched_switch event %p\n", evsel); 849ad236fd2SIngo Molnar 850fbf94829SIngo Molnar if (cpu >= MAX_CPUS || cpu < 0) 851a116e05dSArnaldo Carvalho de Melo return 0; 852fbf94829SIngo Molnar 8530e9b07e5SArnaldo Carvalho de Melo timestamp0 = sched->cpu_last_switched[cpu]; 854fbf94829SIngo Molnar if (timestamp0) 855fbf94829SIngo Molnar delta = timestamp - timestamp0; 856fbf94829SIngo Molnar else 857fbf94829SIngo Molnar delta = 0; 858fbf94829SIngo Molnar 859a116e05dSArnaldo Carvalho de Melo if (delta < 0) { 86060b7d14aSNamhyung Kim pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); 861a116e05dSArnaldo Carvalho de Melo return -1; 862a116e05dSArnaldo Carvalho de Melo } 863fbf94829SIngo Molnar 8649ec3f4e4SArnaldo Carvalho de Melo pr_debug(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n", 8659ec3f4e4SArnaldo Carvalho de Melo prev_comm, prev_pid, next_comm, next_pid, delta); 866fbf94829SIngo Molnar 8679ec3f4e4SArnaldo Carvalho de Melo prev = register_pid(sched, prev_pid, prev_comm); 8689ec3f4e4SArnaldo Carvalho de Melo next = register_pid(sched, next_pid, next_comm); 869fbf94829SIngo Molnar 8700e9b07e5SArnaldo Carvalho de Melo sched->cpu_last_switched[cpu] = timestamp; 871fbf94829SIngo Molnar 8720e9b07e5SArnaldo Carvalho de Melo add_sched_event_run(sched, prev, timestamp, delta); 8739ec3f4e4SArnaldo Carvalho de Melo add_sched_event_sleep(sched, prev, timestamp, prev_state); 874a116e05dSArnaldo Carvalho de Melo 875a116e05dSArnaldo Carvalho de Melo return 0; 876fbf94829SIngo Molnar } 877fbf94829SIngo Molnar 878cb627505SDavid Ahern static int replay_fork_event(struct perf_sched *sched, 879cb627505SDavid Ahern union perf_event *event, 880cb627505SDavid Ahern struct machine *machine) 881419ab0d6SFrederic Weisbecker { 882cb627505SDavid Ahern struct thread *child, *parent; 8839ec3f4e4SArnaldo Carvalho de Melo 884314add6bSAdrian Hunter child = machine__findnew_thread(machine, event->fork.pid, 885314add6bSAdrian Hunter event->fork.tid); 886314add6bSAdrian Hunter parent = machine__findnew_thread(machine, event->fork.ppid, 887314add6bSAdrian Hunter event->fork.ptid); 888cb627505SDavid Ahern 889cb627505SDavid Ahern if (child == NULL || parent == NULL) { 890cb627505SDavid Ahern pr_debug("thread does not exist on fork event: child %p, parent %p\n", 891cb627505SDavid Ahern child, parent); 892b91fc39fSArnaldo Carvalho de Melo goto out_put; 893419ab0d6SFrederic Weisbecker } 8949ec3f4e4SArnaldo Carvalho de Melo 895bb963e16SNamhyung Kim if (verbose > 0) { 896cb627505SDavid Ahern printf("fork event\n"); 897b9c5143aSFrederic Weisbecker printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid); 898b9c5143aSFrederic Weisbecker printf("... child: %s/%d\n", thread__comm_str(child), child->tid); 899cb627505SDavid Ahern } 900cb627505SDavid Ahern 901b9c5143aSFrederic Weisbecker register_pid(sched, parent->tid, thread__comm_str(parent)); 902b9c5143aSFrederic Weisbecker register_pid(sched, child->tid, thread__comm_str(child)); 903b91fc39fSArnaldo Carvalho de Melo out_put: 904b91fc39fSArnaldo Carvalho de Melo thread__put(child); 905b91fc39fSArnaldo Carvalho de Melo thread__put(parent); 906a116e05dSArnaldo Carvalho de Melo return 0; 907419ab0d6SFrederic Weisbecker } 908419ab0d6SFrederic Weisbecker 909b1ffe8f3SIngo Molnar struct sort_dimension { 910b1ffe8f3SIngo Molnar const char *name; 911b5fae128SIngo Molnar sort_fn_t cmp; 912b1ffe8f3SIngo Molnar struct list_head list; 913b1ffe8f3SIngo Molnar }; 914b1ffe8f3SIngo Molnar 9158640da9fSChangbin Du /* 9168640da9fSChangbin Du * handle runtime stats saved per thread 9178640da9fSChangbin Du */ 9188640da9fSChangbin Du static struct thread_runtime *thread__init_runtime(struct thread *thread) 9198640da9fSChangbin Du { 9208640da9fSChangbin Du struct thread_runtime *r; 9218640da9fSChangbin Du 9228640da9fSChangbin Du r = zalloc(sizeof(struct thread_runtime)); 9238640da9fSChangbin Du if (!r) 9248640da9fSChangbin Du return NULL; 9258640da9fSChangbin Du 9268640da9fSChangbin Du init_stats(&r->run_stats); 9278640da9fSChangbin Du thread__set_priv(thread, r); 9288640da9fSChangbin Du 9298640da9fSChangbin Du return r; 9308640da9fSChangbin Du } 9318640da9fSChangbin Du 9328640da9fSChangbin Du static struct thread_runtime *thread__get_runtime(struct thread *thread) 9338640da9fSChangbin Du { 9348640da9fSChangbin Du struct thread_runtime *tr; 9358640da9fSChangbin Du 9368640da9fSChangbin Du tr = thread__priv(thread); 9378640da9fSChangbin Du if (tr == NULL) { 9388640da9fSChangbin Du tr = thread__init_runtime(thread); 9398640da9fSChangbin Du if (tr == NULL) 9408640da9fSChangbin Du pr_debug("Failed to malloc memory for runtime data.\n"); 9418640da9fSChangbin Du } 9428640da9fSChangbin Du 9438640da9fSChangbin Du return tr; 9448640da9fSChangbin Du } 9458640da9fSChangbin Du 946daa1d7a5SFrederic Weisbecker static int 94739aeb52fSmingo thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r) 948daa1d7a5SFrederic Weisbecker { 949daa1d7a5SFrederic Weisbecker struct sort_dimension *sort; 950daa1d7a5SFrederic Weisbecker int ret = 0; 951daa1d7a5SFrederic Weisbecker 952b5fae128SIngo Molnar BUG_ON(list_empty(list)); 953b5fae128SIngo Molnar 954daa1d7a5SFrederic Weisbecker list_for_each_entry(sort, list, list) { 955daa1d7a5SFrederic Weisbecker ret = sort->cmp(l, r); 956daa1d7a5SFrederic Weisbecker if (ret) 957daa1d7a5SFrederic Weisbecker return ret; 958daa1d7a5SFrederic Weisbecker } 959daa1d7a5SFrederic Weisbecker 960daa1d7a5SFrederic Weisbecker return ret; 961daa1d7a5SFrederic Weisbecker } 962daa1d7a5SFrederic Weisbecker 96339aeb52fSmingo static struct work_atoms * 964cb4c13a5SDavidlohr Bueso thread_atoms_search(struct rb_root_cached *root, struct thread *thread, 965b5fae128SIngo Molnar struct list_head *sort_list) 966b5fae128SIngo Molnar { 967cb4c13a5SDavidlohr Bueso struct rb_node *node = root->rb_root.rb_node; 96839aeb52fSmingo struct work_atoms key = { .thread = thread }; 969b5fae128SIngo Molnar 970b5fae128SIngo Molnar while (node) { 97139aeb52fSmingo struct work_atoms *atoms; 972b5fae128SIngo Molnar int cmp; 973b5fae128SIngo Molnar 97439aeb52fSmingo atoms = container_of(node, struct work_atoms, node); 975b5fae128SIngo Molnar 976b5fae128SIngo Molnar cmp = thread_lat_cmp(sort_list, &key, atoms); 977b5fae128SIngo Molnar if (cmp > 0) 978b5fae128SIngo Molnar node = node->rb_left; 979b5fae128SIngo Molnar else if (cmp < 0) 980b5fae128SIngo Molnar node = node->rb_right; 981b5fae128SIngo Molnar else { 982b5fae128SIngo Molnar BUG_ON(thread != atoms->thread); 983b5fae128SIngo Molnar return atoms; 984b5fae128SIngo Molnar } 985b5fae128SIngo Molnar } 986b5fae128SIngo Molnar return NULL; 987b5fae128SIngo Molnar } 988b5fae128SIngo Molnar 989cdce9d73SFrederic Weisbecker static void 990cb4c13a5SDavidlohr Bueso __thread_latency_insert(struct rb_root_cached *root, struct work_atoms *data, 991daa1d7a5SFrederic Weisbecker struct list_head *sort_list) 992cdce9d73SFrederic Weisbecker { 993cb4c13a5SDavidlohr Bueso struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL; 994cb4c13a5SDavidlohr Bueso bool leftmost = true; 995cdce9d73SFrederic Weisbecker 996cdce9d73SFrederic Weisbecker while (*new) { 99739aeb52fSmingo struct work_atoms *this; 998daa1d7a5SFrederic Weisbecker int cmp; 999cdce9d73SFrederic Weisbecker 100039aeb52fSmingo this = container_of(*new, struct work_atoms, node); 1001cdce9d73SFrederic Weisbecker parent = *new; 1002daa1d7a5SFrederic Weisbecker 1003daa1d7a5SFrederic Weisbecker cmp = thread_lat_cmp(sort_list, data, this); 1004daa1d7a5SFrederic Weisbecker 1005daa1d7a5SFrederic Weisbecker if (cmp > 0) 1006cdce9d73SFrederic Weisbecker new = &((*new)->rb_left); 1007cb4c13a5SDavidlohr Bueso else { 1008daa1d7a5SFrederic Weisbecker new = &((*new)->rb_right); 1009cb4c13a5SDavidlohr Bueso leftmost = false; 1010cb4c13a5SDavidlohr Bueso } 1011cdce9d73SFrederic Weisbecker } 1012cdce9d73SFrederic Weisbecker 1013cdce9d73SFrederic Weisbecker rb_link_node(&data->node, parent, new); 1014cb4c13a5SDavidlohr Bueso rb_insert_color_cached(&data->node, root, leftmost); 1015cdce9d73SFrederic Weisbecker } 1016cdce9d73SFrederic Weisbecker 10170e9b07e5SArnaldo Carvalho de Melo static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) 1018cdce9d73SFrederic Weisbecker { 101936479484SArnaldo Carvalho de Melo struct work_atoms *atoms = zalloc(sizeof(*atoms)); 1020a116e05dSArnaldo Carvalho de Melo if (!atoms) { 1021a116e05dSArnaldo Carvalho de Melo pr_err("No memory at %s\n", __func__); 1022a116e05dSArnaldo Carvalho de Melo return -1; 1023a116e05dSArnaldo Carvalho de Melo } 1024cdce9d73SFrederic Weisbecker 1025f3b623b8SArnaldo Carvalho de Melo atoms->thread = thread__get(thread); 102639aeb52fSmingo INIT_LIST_HEAD(&atoms->work_list); 10270e9b07e5SArnaldo Carvalho de Melo __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid); 1028a116e05dSArnaldo Carvalho de Melo return 0; 1029cdce9d73SFrederic Weisbecker } 1030cdce9d73SFrederic Weisbecker 10319ec3f4e4SArnaldo Carvalho de Melo static char sched_out_state(u64 prev_state) 1032cdce9d73SFrederic Weisbecker { 1033cdce9d73SFrederic Weisbecker const char *str = TASK_STATE_TO_CHAR_STR; 1034cdce9d73SFrederic Weisbecker 10359ec3f4e4SArnaldo Carvalho de Melo return str[prev_state]; 1036cdce9d73SFrederic Weisbecker } 1037cdce9d73SFrederic Weisbecker 1038a116e05dSArnaldo Carvalho de Melo static int 103939aeb52fSmingo add_sched_out_event(struct work_atoms *atoms, 104039aeb52fSmingo char run_state, 1041c6ced611SFrederic Weisbecker u64 timestamp) 1042cdce9d73SFrederic Weisbecker { 104336479484SArnaldo Carvalho de Melo struct work_atom *atom = zalloc(sizeof(*atom)); 1044a116e05dSArnaldo Carvalho de Melo if (!atom) { 1045a116e05dSArnaldo Carvalho de Melo pr_err("Non memory at %s", __func__); 1046a116e05dSArnaldo Carvalho de Melo return -1; 1047a116e05dSArnaldo Carvalho de Melo } 1048cdce9d73SFrederic Weisbecker 1049aa1ab9d2SFrederic Weisbecker atom->sched_out_time = timestamp; 1050aa1ab9d2SFrederic Weisbecker 105139aeb52fSmingo if (run_state == 'R') { 1052b1ffe8f3SIngo Molnar atom->state = THREAD_WAIT_CPU; 1053aa1ab9d2SFrederic Weisbecker atom->wake_up_time = atom->sched_out_time; 1054c6ced611SFrederic Weisbecker } 1055c6ced611SFrederic Weisbecker 105639aeb52fSmingo list_add_tail(&atom->list, &atoms->work_list); 1057a116e05dSArnaldo Carvalho de Melo return 0; 1058cdce9d73SFrederic Weisbecker } 1059cdce9d73SFrederic Weisbecker 1060cdce9d73SFrederic Weisbecker static void 10611d037ca1SIrina Tirdea add_runtime_event(struct work_atoms *atoms, u64 delta, 10621d037ca1SIrina Tirdea u64 timestamp __maybe_unused) 106339aeb52fSmingo { 106439aeb52fSmingo struct work_atom *atom; 106539aeb52fSmingo 106639aeb52fSmingo BUG_ON(list_empty(&atoms->work_list)); 106739aeb52fSmingo 106839aeb52fSmingo atom = list_entry(atoms->work_list.prev, struct work_atom, list); 106939aeb52fSmingo 107039aeb52fSmingo atom->runtime += delta; 107139aeb52fSmingo atoms->total_runtime += delta; 107239aeb52fSmingo } 107339aeb52fSmingo 107439aeb52fSmingo static void 107539aeb52fSmingo add_sched_in_event(struct work_atoms *atoms, u64 timestamp) 1076cdce9d73SFrederic Weisbecker { 1077b1ffe8f3SIngo Molnar struct work_atom *atom; 107866685678SFrederic Weisbecker u64 delta; 1079cdce9d73SFrederic Weisbecker 108039aeb52fSmingo if (list_empty(&atoms->work_list)) 1081cdce9d73SFrederic Weisbecker return; 1082cdce9d73SFrederic Weisbecker 108339aeb52fSmingo atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1084cdce9d73SFrederic Weisbecker 1085b1ffe8f3SIngo Molnar if (atom->state != THREAD_WAIT_CPU) 1086cdce9d73SFrederic Weisbecker return; 1087cdce9d73SFrederic Weisbecker 1088b1ffe8f3SIngo Molnar if (timestamp < atom->wake_up_time) { 1089b1ffe8f3SIngo Molnar atom->state = THREAD_IGNORE; 1090cdce9d73SFrederic Weisbecker return; 1091cdce9d73SFrederic Weisbecker } 1092cdce9d73SFrederic Weisbecker 1093b1ffe8f3SIngo Molnar atom->state = THREAD_SCHED_IN; 1094b1ffe8f3SIngo Molnar atom->sched_in_time = timestamp; 109566685678SFrederic Weisbecker 1096b1ffe8f3SIngo Molnar delta = atom->sched_in_time - atom->wake_up_time; 109766685678SFrederic Weisbecker atoms->total_lat += delta; 10983786310aSFrederic Weisbecker if (delta > atoms->max_lat) { 109966685678SFrederic Weisbecker atoms->max_lat = delta; 1100dc000c45SJoel Fernandes (Google) atoms->max_lat_start = atom->wake_up_time; 1101dc000c45SJoel Fernandes (Google) atoms->max_lat_end = timestamp; 11023786310aSFrederic Weisbecker } 110366685678SFrederic Weisbecker atoms->nb_atoms++; 1104cdce9d73SFrederic Weisbecker } 1105cdce9d73SFrederic Weisbecker 11069ec3f4e4SArnaldo Carvalho de Melo static int latency_switch_event(struct perf_sched *sched, 110732dcd021SJiri Olsa struct evsel *evsel, 11089ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, 11099ec3f4e4SArnaldo Carvalho de Melo struct machine *machine) 1110cdce9d73SFrederic Weisbecker { 1111efc0cdc9SArnaldo Carvalho de Melo const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), 1112efc0cdc9SArnaldo Carvalho de Melo next_pid = evsel__intval(evsel, sample, "next_pid"); 1113efc0cdc9SArnaldo Carvalho de Melo const u64 prev_state = evsel__intval(evsel, sample, "prev_state"); 111439aeb52fSmingo struct work_atoms *out_events, *in_events; 1115cdce9d73SFrederic Weisbecker struct thread *sched_out, *sched_in; 11167f7f8d0bSArnaldo Carvalho de Melo u64 timestamp0, timestamp = sample->time; 1117b91fc39fSArnaldo Carvalho de Melo int cpu = sample->cpu, err = -1; 1118ea92ed5aSIngo Molnar s64 delta; 1119ea92ed5aSIngo Molnar 112039aeb52fSmingo BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1121ea92ed5aSIngo Molnar 11220e9b07e5SArnaldo Carvalho de Melo timestamp0 = sched->cpu_last_switched[cpu]; 11230e9b07e5SArnaldo Carvalho de Melo sched->cpu_last_switched[cpu] = timestamp; 1124ea92ed5aSIngo Molnar if (timestamp0) 1125ea92ed5aSIngo Molnar delta = timestamp - timestamp0; 1126ea92ed5aSIngo Molnar else 1127ea92ed5aSIngo Molnar delta = 0; 1128ea92ed5aSIngo Molnar 1129a116e05dSArnaldo Carvalho de Melo if (delta < 0) { 1130a116e05dSArnaldo Carvalho de Melo pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1131a116e05dSArnaldo Carvalho de Melo return -1; 1132a116e05dSArnaldo Carvalho de Melo } 1133cdce9d73SFrederic Weisbecker 11341fcb8768SAdrian Hunter sched_out = machine__findnew_thread(machine, -1, prev_pid); 11351fcb8768SAdrian Hunter sched_in = machine__findnew_thread(machine, -1, next_pid); 1136b91fc39fSArnaldo Carvalho de Melo if (sched_out == NULL || sched_in == NULL) 1137b91fc39fSArnaldo Carvalho de Melo goto out_put; 1138cdce9d73SFrederic Weisbecker 11390e9b07e5SArnaldo Carvalho de Melo out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 114039aeb52fSmingo if (!out_events) { 11410e9b07e5SArnaldo Carvalho de Melo if (thread_atoms_insert(sched, sched_out)) 1142b91fc39fSArnaldo Carvalho de Melo goto out_put; 11430e9b07e5SArnaldo Carvalho de Melo out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 1144a116e05dSArnaldo Carvalho de Melo if (!out_events) { 1145a116e05dSArnaldo Carvalho de Melo pr_err("out-event: Internal tree error"); 1146b91fc39fSArnaldo Carvalho de Melo goto out_put; 114739aeb52fSmingo } 1148a116e05dSArnaldo Carvalho de Melo } 11499ec3f4e4SArnaldo Carvalho de Melo if (add_sched_out_event(out_events, sched_out_state(prev_state), timestamp)) 1150a116e05dSArnaldo Carvalho de Melo return -1; 115139aeb52fSmingo 11520e9b07e5SArnaldo Carvalho de Melo in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid); 115339aeb52fSmingo if (!in_events) { 11540e9b07e5SArnaldo Carvalho de Melo if (thread_atoms_insert(sched, sched_in)) 1155b91fc39fSArnaldo Carvalho de Melo goto out_put; 11560e9b07e5SArnaldo Carvalho de Melo in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid); 1157a116e05dSArnaldo Carvalho de Melo if (!in_events) { 1158a116e05dSArnaldo Carvalho de Melo pr_err("in-event: Internal tree error"); 1159b91fc39fSArnaldo Carvalho de Melo goto out_put; 1160a116e05dSArnaldo Carvalho de Melo } 116139aeb52fSmingo /* 116239aeb52fSmingo * Take came in we have not heard about yet, 116339aeb52fSmingo * add in an initial atom in runnable state: 116439aeb52fSmingo */ 1165a116e05dSArnaldo Carvalho de Melo if (add_sched_out_event(in_events, 'R', timestamp)) 1166b91fc39fSArnaldo Carvalho de Melo goto out_put; 116739aeb52fSmingo } 116839aeb52fSmingo add_sched_in_event(in_events, timestamp); 1169b91fc39fSArnaldo Carvalho de Melo err = 0; 1170b91fc39fSArnaldo Carvalho de Melo out_put: 1171b91fc39fSArnaldo Carvalho de Melo thread__put(sched_out); 1172b91fc39fSArnaldo Carvalho de Melo thread__put(sched_in); 1173b91fc39fSArnaldo Carvalho de Melo return err; 1174cdce9d73SFrederic Weisbecker } 1175cdce9d73SFrederic Weisbecker 11769ec3f4e4SArnaldo Carvalho de Melo static int latency_runtime_event(struct perf_sched *sched, 117732dcd021SJiri Olsa struct evsel *evsel, 11789ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, 11799ec3f4e4SArnaldo Carvalho de Melo struct machine *machine) 118039aeb52fSmingo { 1181efc0cdc9SArnaldo Carvalho de Melo const u32 pid = evsel__intval(evsel, sample, "pid"); 1182efc0cdc9SArnaldo Carvalho de Melo const u64 runtime = evsel__intval(evsel, sample, "runtime"); 11831fcb8768SAdrian Hunter struct thread *thread = machine__findnew_thread(machine, -1, pid); 11840e9b07e5SArnaldo Carvalho de Melo struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 11857f7f8d0bSArnaldo Carvalho de Melo u64 timestamp = sample->time; 1186b91fc39fSArnaldo Carvalho de Melo int cpu = sample->cpu, err = -1; 1187b91fc39fSArnaldo Carvalho de Melo 1188b91fc39fSArnaldo Carvalho de Melo if (thread == NULL) 1189b91fc39fSArnaldo Carvalho de Melo return -1; 119039aeb52fSmingo 119139aeb52fSmingo BUG_ON(cpu >= MAX_CPUS || cpu < 0); 119239aeb52fSmingo if (!atoms) { 11930e9b07e5SArnaldo Carvalho de Melo if (thread_atoms_insert(sched, thread)) 1194b91fc39fSArnaldo Carvalho de Melo goto out_put; 11950e9b07e5SArnaldo Carvalho de Melo atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 1196a116e05dSArnaldo Carvalho de Melo if (!atoms) { 119760b7d14aSNamhyung Kim pr_err("in-event: Internal tree error"); 1198b91fc39fSArnaldo Carvalho de Melo goto out_put; 1199a116e05dSArnaldo Carvalho de Melo } 1200a116e05dSArnaldo Carvalho de Melo if (add_sched_out_event(atoms, 'R', timestamp)) 1201b91fc39fSArnaldo Carvalho de Melo goto out_put; 120239aeb52fSmingo } 120339aeb52fSmingo 12049ec3f4e4SArnaldo Carvalho de Melo add_runtime_event(atoms, runtime, timestamp); 1205b91fc39fSArnaldo Carvalho de Melo err = 0; 1206b91fc39fSArnaldo Carvalho de Melo out_put: 1207b91fc39fSArnaldo Carvalho de Melo thread__put(thread); 1208b91fc39fSArnaldo Carvalho de Melo return err; 1209cdce9d73SFrederic Weisbecker } 1210cdce9d73SFrederic Weisbecker 12119ec3f4e4SArnaldo Carvalho de Melo static int latency_wakeup_event(struct perf_sched *sched, 121232dcd021SJiri Olsa struct evsel *evsel, 12139ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, 12149ec3f4e4SArnaldo Carvalho de Melo struct machine *machine) 1215cdce9d73SFrederic Weisbecker { 1216efc0cdc9SArnaldo Carvalho de Melo const u32 pid = evsel__intval(evsel, sample, "pid"); 121739aeb52fSmingo struct work_atoms *atoms; 1218b1ffe8f3SIngo Molnar struct work_atom *atom; 1219cdce9d73SFrederic Weisbecker struct thread *wakee; 12207f7f8d0bSArnaldo Carvalho de Melo u64 timestamp = sample->time; 1221b91fc39fSArnaldo Carvalho de Melo int err = -1; 1222cdce9d73SFrederic Weisbecker 12231fcb8768SAdrian Hunter wakee = machine__findnew_thread(machine, -1, pid); 1224b91fc39fSArnaldo Carvalho de Melo if (wakee == NULL) 1225b91fc39fSArnaldo Carvalho de Melo return -1; 12260e9b07e5SArnaldo Carvalho de Melo atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 122717562205SFrederic Weisbecker if (!atoms) { 12280e9b07e5SArnaldo Carvalho de Melo if (thread_atoms_insert(sched, wakee)) 1229b91fc39fSArnaldo Carvalho de Melo goto out_put; 12300e9b07e5SArnaldo Carvalho de Melo atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1231a116e05dSArnaldo Carvalho de Melo if (!atoms) { 123260b7d14aSNamhyung Kim pr_err("wakeup-event: Internal tree error"); 1233b91fc39fSArnaldo Carvalho de Melo goto out_put; 1234a116e05dSArnaldo Carvalho de Melo } 1235a116e05dSArnaldo Carvalho de Melo if (add_sched_out_event(atoms, 'S', timestamp)) 1236b91fc39fSArnaldo Carvalho de Melo goto out_put; 1237cdce9d73SFrederic Weisbecker } 1238cdce9d73SFrederic Weisbecker 123939aeb52fSmingo BUG_ON(list_empty(&atoms->work_list)); 1240cdce9d73SFrederic Weisbecker 124139aeb52fSmingo atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1242cdce9d73SFrederic Weisbecker 124355ffb7a6SMike Galbraith /* 124467d6259dSDongsheng Yang * As we do not guarantee the wakeup event happens when 124567d6259dSDongsheng Yang * task is out of run queue, also may happen when task is 124667d6259dSDongsheng Yang * on run queue and wakeup only change ->state to TASK_RUNNING, 124767d6259dSDongsheng Yang * then we should not set the ->wake_up_time when wake up a 124867d6259dSDongsheng Yang * task which is on run queue. 124967d6259dSDongsheng Yang * 125055ffb7a6SMike Galbraith * You WILL be missing events if you've recorded only 125155ffb7a6SMike Galbraith * one CPU, or are only looking at only one, so don't 125267d6259dSDongsheng Yang * skip in this case. 125355ffb7a6SMike Galbraith */ 12540e9b07e5SArnaldo Carvalho de Melo if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING) 1255b91fc39fSArnaldo Carvalho de Melo goto out_ok; 1256cdce9d73SFrederic Weisbecker 12570e9b07e5SArnaldo Carvalho de Melo sched->nr_timestamps++; 1258ea57c4f5SIngo Molnar if (atom->sched_out_time > timestamp) { 12590e9b07e5SArnaldo Carvalho de Melo sched->nr_unordered_timestamps++; 1260b91fc39fSArnaldo Carvalho de Melo goto out_ok; 1261ea57c4f5SIngo Molnar } 1262aa1ab9d2SFrederic Weisbecker 1263b1ffe8f3SIngo Molnar atom->state = THREAD_WAIT_CPU; 1264b1ffe8f3SIngo Molnar atom->wake_up_time = timestamp; 1265b91fc39fSArnaldo Carvalho de Melo out_ok: 1266b91fc39fSArnaldo Carvalho de Melo err = 0; 1267b91fc39fSArnaldo Carvalho de Melo out_put: 1268b91fc39fSArnaldo Carvalho de Melo thread__put(wakee); 1269b91fc39fSArnaldo Carvalho de Melo return err; 1270cdce9d73SFrederic Weisbecker } 1271cdce9d73SFrederic Weisbecker 12729ec3f4e4SArnaldo Carvalho de Melo static int latency_migrate_task_event(struct perf_sched *sched, 127332dcd021SJiri Olsa struct evsel *evsel, 12749ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, 12759ec3f4e4SArnaldo Carvalho de Melo struct machine *machine) 127655ffb7a6SMike Galbraith { 1277efc0cdc9SArnaldo Carvalho de Melo const u32 pid = evsel__intval(evsel, sample, "pid"); 12787f7f8d0bSArnaldo Carvalho de Melo u64 timestamp = sample->time; 127955ffb7a6SMike Galbraith struct work_atoms *atoms; 128055ffb7a6SMike Galbraith struct work_atom *atom; 128155ffb7a6SMike Galbraith struct thread *migrant; 1282b91fc39fSArnaldo Carvalho de Melo int err = -1; 128355ffb7a6SMike Galbraith 128455ffb7a6SMike Galbraith /* 128555ffb7a6SMike Galbraith * Only need to worry about migration when profiling one CPU. 128655ffb7a6SMike Galbraith */ 12870e9b07e5SArnaldo Carvalho de Melo if (sched->profile_cpu == -1) 1288a116e05dSArnaldo Carvalho de Melo return 0; 128955ffb7a6SMike Galbraith 12901fcb8768SAdrian Hunter migrant = machine__findnew_thread(machine, -1, pid); 1291b91fc39fSArnaldo Carvalho de Melo if (migrant == NULL) 1292b91fc39fSArnaldo Carvalho de Melo return -1; 12930e9b07e5SArnaldo Carvalho de Melo atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 129455ffb7a6SMike Galbraith if (!atoms) { 12950e9b07e5SArnaldo Carvalho de Melo if (thread_atoms_insert(sched, migrant)) 1296b91fc39fSArnaldo Carvalho de Melo goto out_put; 1297b9c5143aSFrederic Weisbecker register_pid(sched, migrant->tid, thread__comm_str(migrant)); 12980e9b07e5SArnaldo Carvalho de Melo atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1299a116e05dSArnaldo Carvalho de Melo if (!atoms) { 130060b7d14aSNamhyung Kim pr_err("migration-event: Internal tree error"); 1301b91fc39fSArnaldo Carvalho de Melo goto out_put; 1302a116e05dSArnaldo Carvalho de Melo } 1303a116e05dSArnaldo Carvalho de Melo if (add_sched_out_event(atoms, 'R', timestamp)) 1304b91fc39fSArnaldo Carvalho de Melo goto out_put; 130555ffb7a6SMike Galbraith } 130655ffb7a6SMike Galbraith 130755ffb7a6SMike Galbraith BUG_ON(list_empty(&atoms->work_list)); 130855ffb7a6SMike Galbraith 130955ffb7a6SMike Galbraith atom = list_entry(atoms->work_list.prev, struct work_atom, list); 131055ffb7a6SMike Galbraith atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp; 131155ffb7a6SMike Galbraith 13120e9b07e5SArnaldo Carvalho de Melo sched->nr_timestamps++; 131355ffb7a6SMike Galbraith 131455ffb7a6SMike Galbraith if (atom->sched_out_time > timestamp) 13150e9b07e5SArnaldo Carvalho de Melo sched->nr_unordered_timestamps++; 1316b91fc39fSArnaldo Carvalho de Melo err = 0; 1317b91fc39fSArnaldo Carvalho de Melo out_put: 1318b91fc39fSArnaldo Carvalho de Melo thread__put(migrant); 1319b91fc39fSArnaldo Carvalho de Melo return err; 132055ffb7a6SMike Galbraith } 132155ffb7a6SMike Galbraith 13220e9b07e5SArnaldo Carvalho de Melo static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_list) 1323cdce9d73SFrederic Weisbecker { 1324cdce9d73SFrederic Weisbecker int i; 1325cdce9d73SFrederic Weisbecker int ret; 132666685678SFrederic Weisbecker u64 avg; 1327dc000c45SJoel Fernandes (Google) char max_lat_start[32], max_lat_end[32]; 1328cdce9d73SFrederic Weisbecker 132939aeb52fSmingo if (!work_list->nb_atoms) 1330cdce9d73SFrederic Weisbecker return; 1331ea57c4f5SIngo Molnar /* 1332ea57c4f5SIngo Molnar * Ignore idle threads: 1333ea57c4f5SIngo Molnar */ 1334b9c5143aSFrederic Weisbecker if (!strcmp(thread__comm_str(work_list->thread), "swapper")) 1335ea57c4f5SIngo Molnar return; 1336cdce9d73SFrederic Weisbecker 13370e9b07e5SArnaldo Carvalho de Melo sched->all_runtime += work_list->total_runtime; 13380e9b07e5SArnaldo Carvalho de Melo sched->all_count += work_list->nb_atoms; 133966685678SFrederic Weisbecker 13402f80dd44SJosef Bacik if (work_list->num_merged > 1) 13412f80dd44SJosef Bacik ret = printf(" %s:(%d) ", thread__comm_str(work_list->thread), work_list->num_merged); 13422f80dd44SJosef Bacik else 1343b9c5143aSFrederic Weisbecker ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid); 1344cdce9d73SFrederic Weisbecker 134508f69e6cSmingo for (i = 0; i < 24 - ret; i++) 1346cdce9d73SFrederic Weisbecker printf(" "); 1347cdce9d73SFrederic Weisbecker 134839aeb52fSmingo avg = work_list->total_lat / work_list->nb_atoms; 1349dc000c45SJoel Fernandes (Google) timestamp__scnprintf_usec(work_list->max_lat_start, max_lat_start, sizeof(max_lat_start)); 1350dc000c45SJoel Fernandes (Google) timestamp__scnprintf_usec(work_list->max_lat_end, max_lat_end, sizeof(max_lat_end)); 1351cdce9d73SFrederic Weisbecker 1352dc000c45SJoel Fernandes (Google) printf("|%11.3f ms |%9" PRIu64 " | avg:%8.3f ms | max:%8.3f ms | max start: %12s s | max end: %12s s\n", 13534fc76e49SArnaldo Carvalho de Melo (double)work_list->total_runtime / NSEC_PER_MSEC, 13544fc76e49SArnaldo Carvalho de Melo work_list->nb_atoms, (double)avg / NSEC_PER_MSEC, 13554fc76e49SArnaldo Carvalho de Melo (double)work_list->max_lat / NSEC_PER_MSEC, 1356dc000c45SJoel Fernandes (Google) max_lat_start, max_lat_end); 1357cdce9d73SFrederic Weisbecker } 1358cdce9d73SFrederic Weisbecker 135939aeb52fSmingo static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1360daa1d7a5SFrederic Weisbecker { 13610014de17SJiri Olsa if (l->thread == r->thread) 13620014de17SJiri Olsa return 0; 136338051234SAdrian Hunter if (l->thread->tid < r->thread->tid) 1364daa1d7a5SFrederic Weisbecker return -1; 136538051234SAdrian Hunter if (l->thread->tid > r->thread->tid) 1366daa1d7a5SFrederic Weisbecker return 1; 13670014de17SJiri Olsa return (int)(l->thread - r->thread); 1368daa1d7a5SFrederic Weisbecker } 1369daa1d7a5SFrederic Weisbecker 137039aeb52fSmingo static int avg_cmp(struct work_atoms *l, struct work_atoms *r) 1371daa1d7a5SFrederic Weisbecker { 1372daa1d7a5SFrederic Weisbecker u64 avgl, avgr; 1373daa1d7a5SFrederic Weisbecker 1374daa1d7a5SFrederic Weisbecker if (!l->nb_atoms) 1375daa1d7a5SFrederic Weisbecker return -1; 1376daa1d7a5SFrederic Weisbecker 1377daa1d7a5SFrederic Weisbecker if (!r->nb_atoms) 1378daa1d7a5SFrederic Weisbecker return 1; 1379daa1d7a5SFrederic Weisbecker 1380daa1d7a5SFrederic Weisbecker avgl = l->total_lat / l->nb_atoms; 1381daa1d7a5SFrederic Weisbecker avgr = r->total_lat / r->nb_atoms; 1382daa1d7a5SFrederic Weisbecker 1383daa1d7a5SFrederic Weisbecker if (avgl < avgr) 1384daa1d7a5SFrederic Weisbecker return -1; 1385daa1d7a5SFrederic Weisbecker if (avgl > avgr) 1386daa1d7a5SFrederic Weisbecker return 1; 1387daa1d7a5SFrederic Weisbecker 1388daa1d7a5SFrederic Weisbecker return 0; 1389daa1d7a5SFrederic Weisbecker } 1390daa1d7a5SFrederic Weisbecker 139139aeb52fSmingo static int max_cmp(struct work_atoms *l, struct work_atoms *r) 1392daa1d7a5SFrederic Weisbecker { 1393daa1d7a5SFrederic Weisbecker if (l->max_lat < r->max_lat) 1394daa1d7a5SFrederic Weisbecker return -1; 1395daa1d7a5SFrederic Weisbecker if (l->max_lat > r->max_lat) 1396daa1d7a5SFrederic Weisbecker return 1; 1397daa1d7a5SFrederic Weisbecker 1398daa1d7a5SFrederic Weisbecker return 0; 1399daa1d7a5SFrederic Weisbecker } 1400daa1d7a5SFrederic Weisbecker 140139aeb52fSmingo static int switch_cmp(struct work_atoms *l, struct work_atoms *r) 1402daa1d7a5SFrederic Weisbecker { 1403daa1d7a5SFrederic Weisbecker if (l->nb_atoms < r->nb_atoms) 1404daa1d7a5SFrederic Weisbecker return -1; 1405daa1d7a5SFrederic Weisbecker if (l->nb_atoms > r->nb_atoms) 1406daa1d7a5SFrederic Weisbecker return 1; 1407daa1d7a5SFrederic Weisbecker 1408daa1d7a5SFrederic Weisbecker return 0; 1409daa1d7a5SFrederic Weisbecker } 1410daa1d7a5SFrederic Weisbecker 141139aeb52fSmingo static int runtime_cmp(struct work_atoms *l, struct work_atoms *r) 1412daa1d7a5SFrederic Weisbecker { 1413daa1d7a5SFrederic Weisbecker if (l->total_runtime < r->total_runtime) 1414daa1d7a5SFrederic Weisbecker return -1; 1415daa1d7a5SFrederic Weisbecker if (l->total_runtime > r->total_runtime) 1416daa1d7a5SFrederic Weisbecker return 1; 1417daa1d7a5SFrederic Weisbecker 1418daa1d7a5SFrederic Weisbecker return 0; 1419daa1d7a5SFrederic Weisbecker } 1420daa1d7a5SFrederic Weisbecker 14210e9b07e5SArnaldo Carvalho de Melo static int sort_dimension__add(const char *tok, struct list_head *list) 14220e9b07e5SArnaldo Carvalho de Melo { 14230e9b07e5SArnaldo Carvalho de Melo size_t i; 14240e9b07e5SArnaldo Carvalho de Melo static struct sort_dimension avg_sort_dimension = { 14250e9b07e5SArnaldo Carvalho de Melo .name = "avg", 14260e9b07e5SArnaldo Carvalho de Melo .cmp = avg_cmp, 14270e9b07e5SArnaldo Carvalho de Melo }; 14280e9b07e5SArnaldo Carvalho de Melo static struct sort_dimension max_sort_dimension = { 14290e9b07e5SArnaldo Carvalho de Melo .name = "max", 14300e9b07e5SArnaldo Carvalho de Melo .cmp = max_cmp, 14310e9b07e5SArnaldo Carvalho de Melo }; 14320e9b07e5SArnaldo Carvalho de Melo static struct sort_dimension pid_sort_dimension = { 14330e9b07e5SArnaldo Carvalho de Melo .name = "pid", 14340e9b07e5SArnaldo Carvalho de Melo .cmp = pid_cmp, 14350e9b07e5SArnaldo Carvalho de Melo }; 1436daa1d7a5SFrederic Weisbecker static struct sort_dimension runtime_sort_dimension = { 1437daa1d7a5SFrederic Weisbecker .name = "runtime", 1438daa1d7a5SFrederic Weisbecker .cmp = runtime_cmp, 1439daa1d7a5SFrederic Weisbecker }; 14400e9b07e5SArnaldo Carvalho de Melo static struct sort_dimension switch_sort_dimension = { 14410e9b07e5SArnaldo Carvalho de Melo .name = "switch", 14420e9b07e5SArnaldo Carvalho de Melo .cmp = switch_cmp, 14430e9b07e5SArnaldo Carvalho de Melo }; 14440e9b07e5SArnaldo Carvalho de Melo struct sort_dimension *available_sorts[] = { 1445daa1d7a5SFrederic Weisbecker &pid_sort_dimension, 1446daa1d7a5SFrederic Weisbecker &avg_sort_dimension, 1447daa1d7a5SFrederic Weisbecker &max_sort_dimension, 1448daa1d7a5SFrederic Weisbecker &switch_sort_dimension, 1449daa1d7a5SFrederic Weisbecker &runtime_sort_dimension, 1450daa1d7a5SFrederic Weisbecker }; 1451daa1d7a5SFrederic Weisbecker 14520e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < ARRAY_SIZE(available_sorts); i++) { 1453daa1d7a5SFrederic Weisbecker if (!strcmp(available_sorts[i]->name, tok)) { 1454daa1d7a5SFrederic Weisbecker list_add_tail(&available_sorts[i]->list, list); 1455daa1d7a5SFrederic Weisbecker 1456daa1d7a5SFrederic Weisbecker return 0; 1457daa1d7a5SFrederic Weisbecker } 1458daa1d7a5SFrederic Weisbecker } 1459daa1d7a5SFrederic Weisbecker 1460daa1d7a5SFrederic Weisbecker return -1; 1461daa1d7a5SFrederic Weisbecker } 1462daa1d7a5SFrederic Weisbecker 14630e9b07e5SArnaldo Carvalho de Melo static void perf_sched__sort_lat(struct perf_sched *sched) 1464daa1d7a5SFrederic Weisbecker { 1465daa1d7a5SFrederic Weisbecker struct rb_node *node; 1466cb4c13a5SDavidlohr Bueso struct rb_root_cached *root = &sched->atom_root; 14672f80dd44SJosef Bacik again: 1468daa1d7a5SFrederic Weisbecker for (;;) { 146939aeb52fSmingo struct work_atoms *data; 1470cb4c13a5SDavidlohr Bueso node = rb_first_cached(root); 1471daa1d7a5SFrederic Weisbecker if (!node) 1472daa1d7a5SFrederic Weisbecker break; 1473daa1d7a5SFrederic Weisbecker 1474cb4c13a5SDavidlohr Bueso rb_erase_cached(node, root); 147539aeb52fSmingo data = rb_entry(node, struct work_atoms, node); 14760e9b07e5SArnaldo Carvalho de Melo __thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list); 1477daa1d7a5SFrederic Weisbecker } 14782f80dd44SJosef Bacik if (root == &sched->atom_root) { 14792f80dd44SJosef Bacik root = &sched->merged_atom_root; 14802f80dd44SJosef Bacik goto again; 14812f80dd44SJosef Bacik } 1482daa1d7a5SFrederic Weisbecker } 1483daa1d7a5SFrederic Weisbecker 14840e9b07e5SArnaldo Carvalho de Melo static int process_sched_wakeup_event(struct perf_tool *tool, 148532dcd021SJiri Olsa struct evsel *evsel, 1486ee29be62SArnaldo Carvalho de Melo struct perf_sample *sample, 14874218e673SArnaldo Carvalho de Melo struct machine *machine) 1488419ab0d6SFrederic Weisbecker { 14890e9b07e5SArnaldo Carvalho de Melo struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1490419ab0d6SFrederic Weisbecker 14919ec3f4e4SArnaldo Carvalho de Melo if (sched->tp_handler->wakeup_event) 14929ec3f4e4SArnaldo Carvalho de Melo return sched->tp_handler->wakeup_event(sched, evsel, sample, machine); 1493419ab0d6SFrederic Weisbecker 14942b7fcbc5SArnaldo Carvalho de Melo return 0; 1495419ab0d6SFrederic Weisbecker } 1496419ab0d6SFrederic Weisbecker 1497a151a37aSJiri Olsa union map_priv { 1498a151a37aSJiri Olsa void *ptr; 1499a151a37aSJiri Olsa bool color; 1500a151a37aSJiri Olsa }; 1501a151a37aSJiri Olsa 1502a151a37aSJiri Olsa static bool thread__has_color(struct thread *thread) 1503a151a37aSJiri Olsa { 1504a151a37aSJiri Olsa union map_priv priv = { 1505a151a37aSJiri Olsa .ptr = thread__priv(thread), 1506a151a37aSJiri Olsa }; 1507a151a37aSJiri Olsa 1508a151a37aSJiri Olsa return priv.color; 1509a151a37aSJiri Olsa } 1510a151a37aSJiri Olsa 1511a151a37aSJiri Olsa static struct thread* 1512a151a37aSJiri Olsa map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid) 1513a151a37aSJiri Olsa { 1514a151a37aSJiri Olsa struct thread *thread = machine__findnew_thread(machine, pid, tid); 1515a151a37aSJiri Olsa union map_priv priv = { 1516a151a37aSJiri Olsa .color = false, 1517a151a37aSJiri Olsa }; 1518a151a37aSJiri Olsa 1519a151a37aSJiri Olsa if (!sched->map.color_pids || !thread || thread__priv(thread)) 1520a151a37aSJiri Olsa return thread; 1521a151a37aSJiri Olsa 1522a151a37aSJiri Olsa if (thread_map__has(sched->map.color_pids, tid)) 1523a151a37aSJiri Olsa priv.color = true; 1524a151a37aSJiri Olsa 1525a151a37aSJiri Olsa thread__set_priv(thread, priv.ptr); 1526a151a37aSJiri Olsa return thread; 1527a151a37aSJiri Olsa } 1528a151a37aSJiri Olsa 152932dcd021SJiri Olsa static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, 15309ec3f4e4SArnaldo Carvalho de Melo struct perf_sample *sample, struct machine *machine) 15310ec04e16SIngo Molnar { 1532efc0cdc9SArnaldo Carvalho de Melo const u32 next_pid = evsel__intval(evsel, sample, "next_pid"); 15339d372ca5SDongsheng Yang struct thread *sched_in; 15348640da9fSChangbin Du struct thread_runtime *tr; 15350ec04e16SIngo Molnar int new_shortname; 15367f7f8d0bSArnaldo Carvalho de Melo u64 timestamp0, timestamp = sample->time; 15370ec04e16SIngo Molnar s64 delta; 153899623c62SJiri Olsa int i, this_cpu = sample->cpu; 153999623c62SJiri Olsa int cpus_nr; 154099623c62SJiri Olsa bool new_cpu = false; 15418cd91195SJiri Olsa const char *color = PERF_COLOR_NORMAL; 154299620a5dSNamhyung Kim char stimestamp[32]; 15430ec04e16SIngo Molnar 15440ec04e16SIngo Molnar BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); 15450ec04e16SIngo Molnar 15460e9b07e5SArnaldo Carvalho de Melo if (this_cpu > sched->max_cpu) 15470e9b07e5SArnaldo Carvalho de Melo sched->max_cpu = this_cpu; 15480ec04e16SIngo Molnar 154999623c62SJiri Olsa if (sched->map.comp) { 155099623c62SJiri Olsa cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS); 155199623c62SJiri Olsa if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) { 155299623c62SJiri Olsa sched->map.comp_cpus[cpus_nr++] = this_cpu; 155399623c62SJiri Olsa new_cpu = true; 155499623c62SJiri Olsa } 155599623c62SJiri Olsa } else 155699623c62SJiri Olsa cpus_nr = sched->max_cpu; 155799623c62SJiri Olsa 15580e9b07e5SArnaldo Carvalho de Melo timestamp0 = sched->cpu_last_switched[this_cpu]; 15590e9b07e5SArnaldo Carvalho de Melo sched->cpu_last_switched[this_cpu] = timestamp; 15600ec04e16SIngo Molnar if (timestamp0) 15610ec04e16SIngo Molnar delta = timestamp - timestamp0; 15620ec04e16SIngo Molnar else 15630ec04e16SIngo Molnar delta = 0; 15640ec04e16SIngo Molnar 1565a116e05dSArnaldo Carvalho de Melo if (delta < 0) { 156660b7d14aSNamhyung Kim pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1567a116e05dSArnaldo Carvalho de Melo return -1; 1568a116e05dSArnaldo Carvalho de Melo } 15690ec04e16SIngo Molnar 1570a151a37aSJiri Olsa sched_in = map__findnew_thread(sched, machine, -1, next_pid); 1571b91fc39fSArnaldo Carvalho de Melo if (sched_in == NULL) 1572b91fc39fSArnaldo Carvalho de Melo return -1; 15730ec04e16SIngo Molnar 15748640da9fSChangbin Du tr = thread__get_runtime(sched_in); 15758640da9fSChangbin Du if (tr == NULL) { 15768640da9fSChangbin Du thread__put(sched_in); 15778640da9fSChangbin Du return -1; 15788640da9fSChangbin Du } 15798640da9fSChangbin Du 1580b91fc39fSArnaldo Carvalho de Melo sched->curr_thread[this_cpu] = thread__get(sched_in); 15810ec04e16SIngo Molnar 15820ec04e16SIngo Molnar printf(" "); 15830ec04e16SIngo Molnar 15840ec04e16SIngo Molnar new_shortname = 0; 15858640da9fSChangbin Du if (!tr->shortname[0]) { 15866bcab4e1SDongsheng if (!strcmp(thread__comm_str(sched_in), "swapper")) { 15876bcab4e1SDongsheng /* 15886bcab4e1SDongsheng * Don't allocate a letter-number for swapper:0 15896bcab4e1SDongsheng * as a shortname. Instead, we use '.' for it. 15906bcab4e1SDongsheng */ 15918640da9fSChangbin Du tr->shortname[0] = '.'; 15928640da9fSChangbin Du tr->shortname[1] = ' '; 15936bcab4e1SDongsheng } else { 15948640da9fSChangbin Du tr->shortname[0] = sched->next_shortname1; 15958640da9fSChangbin Du tr->shortname[1] = sched->next_shortname2; 15960ec04e16SIngo Molnar 15970e9b07e5SArnaldo Carvalho de Melo if (sched->next_shortname1 < 'Z') { 15980e9b07e5SArnaldo Carvalho de Melo sched->next_shortname1++; 15990ec04e16SIngo Molnar } else { 16000e9b07e5SArnaldo Carvalho de Melo sched->next_shortname1 = 'A'; 16016bcab4e1SDongsheng if (sched->next_shortname2 < '9') 16020e9b07e5SArnaldo Carvalho de Melo sched->next_shortname2++; 16036bcab4e1SDongsheng else 16040e9b07e5SArnaldo Carvalho de Melo sched->next_shortname2 = '0'; 16050ec04e16SIngo Molnar } 16060ec04e16SIngo Molnar } 16070ec04e16SIngo Molnar new_shortname = 1; 16080ec04e16SIngo Molnar } 16090ec04e16SIngo Molnar 161099623c62SJiri Olsa for (i = 0; i < cpus_nr; i++) { 161199623c62SJiri Olsa int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i; 1612a151a37aSJiri Olsa struct thread *curr_thread = sched->curr_thread[cpu]; 16138640da9fSChangbin Du struct thread_runtime *curr_tr; 1614a151a37aSJiri Olsa const char *pid_color = color; 1615cf294f24SJiri Olsa const char *cpu_color = color; 1616a151a37aSJiri Olsa 1617a151a37aSJiri Olsa if (curr_thread && thread__has_color(curr_thread)) 1618a151a37aSJiri Olsa pid_color = COLOR_PIDS; 161999623c62SJiri Olsa 1620*dfc66befSIan Rogers if (sched->map.cpus && !perf_cpu_map__has(sched->map.cpus, cpu)) 162173643bb6SJiri Olsa continue; 162273643bb6SJiri Olsa 1623*dfc66befSIan Rogers if (sched->map.color_cpus && perf_cpu_map__has(sched->map.color_cpus, cpu)) 1624cf294f24SJiri Olsa cpu_color = COLOR_CPUS; 1625cf294f24SJiri Olsa 16260ec04e16SIngo Molnar if (cpu != this_cpu) 16271208bb27SNamhyung Kim color_fprintf(stdout, color, " "); 16280ec04e16SIngo Molnar else 1629cf294f24SJiri Olsa color_fprintf(stdout, cpu_color, "*"); 16300ec04e16SIngo Molnar 16318640da9fSChangbin Du if (sched->curr_thread[cpu]) { 16328640da9fSChangbin Du curr_tr = thread__get_runtime(sched->curr_thread[cpu]); 16338640da9fSChangbin Du if (curr_tr == NULL) { 16348640da9fSChangbin Du thread__put(sched_in); 16358640da9fSChangbin Du return -1; 16368640da9fSChangbin Du } 16378640da9fSChangbin Du color_fprintf(stdout, pid_color, "%2s ", curr_tr->shortname); 16388640da9fSChangbin Du } else 16398cd91195SJiri Olsa color_fprintf(stdout, color, " "); 16400ec04e16SIngo Molnar } 16410ec04e16SIngo Molnar 1642*dfc66befSIan Rogers if (sched->map.cpus && !perf_cpu_map__has(sched->map.cpus, this_cpu)) 164373643bb6SJiri Olsa goto out; 164473643bb6SJiri Olsa 164599620a5dSNamhyung Kim timestamp__scnprintf_usec(timestamp, stimestamp, sizeof(stimestamp)); 164699620a5dSNamhyung Kim color_fprintf(stdout, color, " %12s secs ", stimestamp); 164799a3c3a9SChangbin Du if (new_shortname || tr->comm_changed || (verbose > 0 && sched_in->tid)) { 1648a151a37aSJiri Olsa const char *pid_color = color; 1649a151a37aSJiri Olsa 1650a151a37aSJiri Olsa if (thread__has_color(sched_in)) 1651a151a37aSJiri Olsa pid_color = COLOR_PIDS; 1652a151a37aSJiri Olsa 1653a151a37aSJiri Olsa color_fprintf(stdout, pid_color, "%s => %s:%d", 16548640da9fSChangbin Du tr->shortname, thread__comm_str(sched_in), sched_in->tid); 165599a3c3a9SChangbin Du tr->comm_changed = false; 16560ec04e16SIngo Molnar } 1657a116e05dSArnaldo Carvalho de Melo 165899623c62SJiri Olsa if (sched->map.comp && new_cpu) 16598cd91195SJiri Olsa color_fprintf(stdout, color, " (CPU %d)", this_cpu); 166099623c62SJiri Olsa 166173643bb6SJiri Olsa out: 16628cd91195SJiri Olsa color_fprintf(stdout, color, "\n"); 166399623c62SJiri Olsa 1664b91fc39fSArnaldo Carvalho de Melo thread__put(sched_in); 1665b91fc39fSArnaldo Carvalho de Melo 1666a116e05dSArnaldo Carvalho de Melo return 0; 16670ec04e16SIngo Molnar } 16680ec04e16SIngo Molnar 16690e9b07e5SArnaldo Carvalho de Melo static int process_sched_switch_event(struct perf_tool *tool, 167032dcd021SJiri Olsa struct evsel *evsel, 1671ee29be62SArnaldo Carvalho de Melo struct perf_sample *sample, 16724218e673SArnaldo Carvalho de Melo struct machine *machine) 1673419ab0d6SFrederic Weisbecker { 16740e9b07e5SArnaldo Carvalho de Melo struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1675a116e05dSArnaldo Carvalho de Melo int this_cpu = sample->cpu, err = 0; 1676efc0cdc9SArnaldo Carvalho de Melo u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), 1677efc0cdc9SArnaldo Carvalho de Melo next_pid = evsel__intval(evsel, sample, "next_pid"); 1678419ab0d6SFrederic Weisbecker 16790e9b07e5SArnaldo Carvalho de Melo if (sched->curr_pid[this_cpu] != (u32)-1) { 1680c8a37751SIngo Molnar /* 1681c8a37751SIngo Molnar * Are we trying to switch away a PID that is 1682c8a37751SIngo Molnar * not current? 1683c8a37751SIngo Molnar */ 16842b7fcbc5SArnaldo Carvalho de Melo if (sched->curr_pid[this_cpu] != prev_pid) 16850e9b07e5SArnaldo Carvalho de Melo sched->nr_context_switch_bugs++; 1686c8a37751SIngo Molnar } 1687c8a37751SIngo Molnar 16889ec3f4e4SArnaldo Carvalho de Melo if (sched->tp_handler->switch_event) 16899ec3f4e4SArnaldo Carvalho de Melo err = sched->tp_handler->switch_event(sched, evsel, sample, machine); 16902b7fcbc5SArnaldo Carvalho de Melo 16912b7fcbc5SArnaldo Carvalho de Melo sched->curr_pid[this_cpu] = next_pid; 1692a116e05dSArnaldo Carvalho de Melo return err; 1693419ab0d6SFrederic Weisbecker } 1694419ab0d6SFrederic Weisbecker 16950e9b07e5SArnaldo Carvalho de Melo static int process_sched_runtime_event(struct perf_tool *tool, 169632dcd021SJiri Olsa struct evsel *evsel, 1697ee29be62SArnaldo Carvalho de Melo struct perf_sample *sample, 16984218e673SArnaldo Carvalho de Melo struct machine *machine) 169939aeb52fSmingo { 17000e9b07e5SArnaldo Carvalho de Melo struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 170139aeb52fSmingo 17029ec3f4e4SArnaldo Carvalho de Melo if (sched->tp_handler->runtime_event) 17039ec3f4e4SArnaldo Carvalho de Melo return sched->tp_handler->runtime_event(sched, evsel, sample, machine); 170439aeb52fSmingo 1705a116e05dSArnaldo Carvalho de Melo return 0; 1706ec156764SIngo Molnar } 1707ec156764SIngo Molnar 1708cb627505SDavid Ahern static int perf_sched__process_fork_event(struct perf_tool *tool, 1709cb627505SDavid Ahern union perf_event *event, 17102b7fcbc5SArnaldo Carvalho de Melo struct perf_sample *sample, 1711cb627505SDavid Ahern struct machine *machine) 17122b7fcbc5SArnaldo Carvalho de Melo { 17132b7fcbc5SArnaldo Carvalho de Melo struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 17142b7fcbc5SArnaldo Carvalho de Melo 17154d39c89fSIngo Molnar /* run the fork event through the perf machinery */ 1716cb627505SDavid Ahern perf_event__process_fork(tool, event, sample, machine); 1717cb627505SDavid Ahern 1718cb627505SDavid Ahern /* and then run additional processing needed for this command */ 17199ec3f4e4SArnaldo Carvalho de Melo if (sched->tp_handler->fork_event) 1720cb627505SDavid Ahern return sched->tp_handler->fork_event(sched, event, machine); 17212b7fcbc5SArnaldo Carvalho de Melo 17222b7fcbc5SArnaldo Carvalho de Melo return 0; 17232b7fcbc5SArnaldo Carvalho de Melo } 17242b7fcbc5SArnaldo Carvalho de Melo 17250e9b07e5SArnaldo Carvalho de Melo static int process_sched_migrate_task_event(struct perf_tool *tool, 172632dcd021SJiri Olsa struct evsel *evsel, 1727ee29be62SArnaldo Carvalho de Melo struct perf_sample *sample, 17284218e673SArnaldo Carvalho de Melo struct machine *machine) 172955ffb7a6SMike Galbraith { 17300e9b07e5SArnaldo Carvalho de Melo struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 173155ffb7a6SMike Galbraith 17329ec3f4e4SArnaldo Carvalho de Melo if (sched->tp_handler->migrate_task_event) 17339ec3f4e4SArnaldo Carvalho de Melo return sched->tp_handler->migrate_task_event(sched, evsel, sample, machine); 173455ffb7a6SMike Galbraith 17352b7fcbc5SArnaldo Carvalho de Melo return 0; 173655ffb7a6SMike Galbraith } 173755ffb7a6SMike Galbraith 1738a116e05dSArnaldo Carvalho de Melo typedef int (*tracepoint_handler)(struct perf_tool *tool, 173932dcd021SJiri Olsa struct evsel *evsel, 1740ee29be62SArnaldo Carvalho de Melo struct perf_sample *sample, 17414218e673SArnaldo Carvalho de Melo struct machine *machine); 1742ec156764SIngo Molnar 17431d037ca1SIrina Tirdea static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused, 17441d037ca1SIrina Tirdea union perf_event *event __maybe_unused, 17458115d60cSArnaldo Carvalho de Melo struct perf_sample *sample, 174632dcd021SJiri Olsa struct evsel *evsel, 1747743eb868SArnaldo Carvalho de Melo struct machine *machine) 17480a02ad93SIngo Molnar { 1749a116e05dSArnaldo Carvalho de Melo int err = 0; 1750a80deb62SArnaldo Carvalho de Melo 1751744a9719SArnaldo Carvalho de Melo if (evsel->handler != NULL) { 1752744a9719SArnaldo Carvalho de Melo tracepoint_handler f = evsel->handler; 17532b7fcbc5SArnaldo Carvalho de Melo err = f(tool, evsel, sample, machine); 1754ee29be62SArnaldo Carvalho de Melo } 17550a02ad93SIngo Molnar 1756a116e05dSArnaldo Carvalho de Melo return err; 17570a02ad93SIngo Molnar } 17580a02ad93SIngo Molnar 175999a3c3a9SChangbin Du static int perf_sched__process_comm(struct perf_tool *tool __maybe_unused, 176099a3c3a9SChangbin Du union perf_event *event, 176199a3c3a9SChangbin Du struct perf_sample *sample, 176299a3c3a9SChangbin Du struct machine *machine) 176399a3c3a9SChangbin Du { 176499a3c3a9SChangbin Du struct thread *thread; 176599a3c3a9SChangbin Du struct thread_runtime *tr; 176699a3c3a9SChangbin Du int err; 176799a3c3a9SChangbin Du 176899a3c3a9SChangbin Du err = perf_event__process_comm(tool, event, sample, machine); 176999a3c3a9SChangbin Du if (err) 177099a3c3a9SChangbin Du return err; 177199a3c3a9SChangbin Du 177299a3c3a9SChangbin Du thread = machine__find_thread(machine, sample->pid, sample->tid); 177399a3c3a9SChangbin Du if (!thread) { 177499a3c3a9SChangbin Du pr_err("Internal error: can't find thread\n"); 177599a3c3a9SChangbin Du return -1; 177699a3c3a9SChangbin Du } 177799a3c3a9SChangbin Du 177899a3c3a9SChangbin Du tr = thread__get_runtime(thread); 177999a3c3a9SChangbin Du if (tr == NULL) { 178099a3c3a9SChangbin Du thread__put(thread); 178199a3c3a9SChangbin Du return -1; 178299a3c3a9SChangbin Du } 178399a3c3a9SChangbin Du 178499a3c3a9SChangbin Du tr->comm_changed = true; 178599a3c3a9SChangbin Du thread__put(thread); 178699a3c3a9SChangbin Du 178799a3c3a9SChangbin Du return 0; 178899a3c3a9SChangbin Du } 178999a3c3a9SChangbin Du 1790ae536acfSArnaldo Carvalho de Melo static int perf_sched__read_events(struct perf_sched *sched) 17910a02ad93SIngo Molnar { 179232dcd021SJiri Olsa const struct evsel_str_handler handlers[] = { 1793ee29be62SArnaldo Carvalho de Melo { "sched:sched_switch", process_sched_switch_event, }, 1794ee29be62SArnaldo Carvalho de Melo { "sched:sched_stat_runtime", process_sched_runtime_event, }, 1795ee29be62SArnaldo Carvalho de Melo { "sched:sched_wakeup", process_sched_wakeup_event, }, 1796ee29be62SArnaldo Carvalho de Melo { "sched:sched_wakeup_new", process_sched_wakeup_event, }, 1797ee29be62SArnaldo Carvalho de Melo { "sched:sched_migrate_task", process_sched_migrate_task_event, }, 1798ee29be62SArnaldo Carvalho de Melo }; 1799da378962SArnaldo Carvalho de Melo struct perf_session *session; 18008ceb41d7SJiri Olsa struct perf_data data = { 1801f5fc1412SJiri Olsa .path = input_name, 1802f5fc1412SJiri Olsa .mode = PERF_DATA_MODE_READ, 1803f0dd330fSYunlong Song .force = sched->force, 1804f5fc1412SJiri Olsa }; 1805ae536acfSArnaldo Carvalho de Melo int rc = -1; 1806da378962SArnaldo Carvalho de Melo 18072681bd85SNamhyung Kim session = perf_session__new(&data, &sched->tool); 18086ef81c55SMamatha Inamdar if (IS_ERR(session)) { 18096ef81c55SMamatha Inamdar pr_debug("Error creating perf session"); 18106ef81c55SMamatha Inamdar return PTR_ERR(session); 1811a116e05dSArnaldo Carvalho de Melo } 181294c744b6SArnaldo Carvalho de Melo 18130a7e6d1bSNamhyung Kim symbol__init(&session->header.env); 181404934106SNamhyung Kim 1815a116e05dSArnaldo Carvalho de Melo if (perf_session__set_tracepoints_handlers(session, handlers)) 1816a116e05dSArnaldo Carvalho de Melo goto out_delete; 1817ee29be62SArnaldo Carvalho de Melo 1818cee75ac7SArnaldo Carvalho de Melo if (perf_session__has_traces(session, "record -R")) { 1819b7b61cbeSArnaldo Carvalho de Melo int err = perf_session__process_events(session); 1820a116e05dSArnaldo Carvalho de Melo if (err) { 1821a116e05dSArnaldo Carvalho de Melo pr_err("Failed to process events, error %d", err); 1822a116e05dSArnaldo Carvalho de Melo goto out_delete; 1823a116e05dSArnaldo Carvalho de Melo } 18244c09bafaSJiri Olsa 182575be989aSArnaldo Carvalho de Melo sched->nr_events = session->evlist->stats.nr_events[0]; 182675be989aSArnaldo Carvalho de Melo sched->nr_lost_events = session->evlist->stats.total_lost; 182775be989aSArnaldo Carvalho de Melo sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; 1828cee75ac7SArnaldo Carvalho de Melo } 1829d549c769SArnaldo Carvalho de Melo 1830ae536acfSArnaldo Carvalho de Melo rc = 0; 1831a116e05dSArnaldo Carvalho de Melo out_delete: 1832a116e05dSArnaldo Carvalho de Melo perf_session__delete(session); 1833ae536acfSArnaldo Carvalho de Melo return rc; 18340a02ad93SIngo Molnar } 18350a02ad93SIngo Molnar 183649394a2aSDavid Ahern /* 183749394a2aSDavid Ahern * scheduling times are printed as msec.usec 183849394a2aSDavid Ahern */ 183949394a2aSDavid Ahern static inline void print_sched_time(unsigned long long nsecs, int width) 184049394a2aSDavid Ahern { 184149394a2aSDavid Ahern unsigned long msecs; 184249394a2aSDavid Ahern unsigned long usecs; 184349394a2aSDavid Ahern 184449394a2aSDavid Ahern msecs = nsecs / NSEC_PER_MSEC; 184549394a2aSDavid Ahern nsecs -= msecs * NSEC_PER_MSEC; 184649394a2aSDavid Ahern usecs = nsecs / NSEC_PER_USEC; 184749394a2aSDavid Ahern printf("%*lu.%03lu ", width, msecs, usecs); 184849394a2aSDavid Ahern } 184949394a2aSDavid Ahern 185049394a2aSDavid Ahern /* 185149394a2aSDavid Ahern * returns runtime data for event, allocating memory for it the 185249394a2aSDavid Ahern * first time it is used. 185349394a2aSDavid Ahern */ 18543b7313f2SArnaldo Carvalho de Melo static struct evsel_runtime *evsel__get_runtime(struct evsel *evsel) 185549394a2aSDavid Ahern { 185649394a2aSDavid Ahern struct evsel_runtime *r = evsel->priv; 185749394a2aSDavid Ahern 185849394a2aSDavid Ahern if (r == NULL) { 185949394a2aSDavid Ahern r = zalloc(sizeof(struct evsel_runtime)); 186049394a2aSDavid Ahern evsel->priv = r; 186149394a2aSDavid Ahern } 186249394a2aSDavid Ahern 186349394a2aSDavid Ahern return r; 186449394a2aSDavid Ahern } 186549394a2aSDavid Ahern 186649394a2aSDavid Ahern /* 186749394a2aSDavid Ahern * save last time event was seen per cpu 186849394a2aSDavid Ahern */ 18693b7313f2SArnaldo Carvalho de Melo static void evsel__save_time(struct evsel *evsel, u64 timestamp, u32 cpu) 187049394a2aSDavid Ahern { 18713b7313f2SArnaldo Carvalho de Melo struct evsel_runtime *r = evsel__get_runtime(evsel); 187249394a2aSDavid Ahern 187349394a2aSDavid Ahern if (r == NULL) 187449394a2aSDavid Ahern return; 187549394a2aSDavid Ahern 187649394a2aSDavid Ahern if ((cpu >= r->ncpu) || (r->last_time == NULL)) { 187749394a2aSDavid Ahern int i, n = __roundup_pow_of_two(cpu+1); 187849394a2aSDavid Ahern void *p = r->last_time; 187949394a2aSDavid Ahern 188049394a2aSDavid Ahern p = realloc(r->last_time, n * sizeof(u64)); 188149394a2aSDavid Ahern if (!p) 188249394a2aSDavid Ahern return; 188349394a2aSDavid Ahern 188449394a2aSDavid Ahern r->last_time = p; 188549394a2aSDavid Ahern for (i = r->ncpu; i < n; ++i) 188649394a2aSDavid Ahern r->last_time[i] = (u64) 0; 188749394a2aSDavid Ahern 188849394a2aSDavid Ahern r->ncpu = n; 188949394a2aSDavid Ahern } 189049394a2aSDavid Ahern 189149394a2aSDavid Ahern r->last_time[cpu] = timestamp; 189249394a2aSDavid Ahern } 189349394a2aSDavid Ahern 189449394a2aSDavid Ahern /* returns last time this event was seen on the given cpu */ 18953b7313f2SArnaldo Carvalho de Melo static u64 evsel__get_time(struct evsel *evsel, u32 cpu) 189649394a2aSDavid Ahern { 18973b7313f2SArnaldo Carvalho de Melo struct evsel_runtime *r = evsel__get_runtime(evsel); 189849394a2aSDavid Ahern 189949394a2aSDavid Ahern if ((r == NULL) || (r->last_time == NULL) || (cpu >= r->ncpu)) 190049394a2aSDavid Ahern return 0; 190149394a2aSDavid Ahern 190249394a2aSDavid Ahern return r->last_time[cpu]; 190349394a2aSDavid Ahern } 190449394a2aSDavid Ahern 19059b8087d7SNamhyung Kim static int comm_width = 30; 190649394a2aSDavid Ahern 190749394a2aSDavid Ahern static char *timehist_get_commstr(struct thread *thread) 190849394a2aSDavid Ahern { 190949394a2aSDavid Ahern static char str[32]; 191049394a2aSDavid Ahern const char *comm = thread__comm_str(thread); 191149394a2aSDavid Ahern pid_t tid = thread->tid; 191249394a2aSDavid Ahern pid_t pid = thread->pid_; 191349394a2aSDavid Ahern int n; 191449394a2aSDavid Ahern 191549394a2aSDavid Ahern if (pid == 0) 191649394a2aSDavid Ahern n = scnprintf(str, sizeof(str), "%s", comm); 191749394a2aSDavid Ahern 191849394a2aSDavid Ahern else if (tid != pid) 191949394a2aSDavid Ahern n = scnprintf(str, sizeof(str), "%s[%d/%d]", comm, tid, pid); 192049394a2aSDavid Ahern 192149394a2aSDavid Ahern else 192249394a2aSDavid Ahern n = scnprintf(str, sizeof(str), "%s[%d]", comm, tid); 192349394a2aSDavid Ahern 192449394a2aSDavid Ahern if (n > comm_width) 192549394a2aSDavid Ahern comm_width = n; 192649394a2aSDavid Ahern 192749394a2aSDavid Ahern return str; 192849394a2aSDavid Ahern } 192949394a2aSDavid Ahern 1930a407b067SDavid Ahern static void timehist_header(struct perf_sched *sched) 193149394a2aSDavid Ahern { 1932a407b067SDavid Ahern u32 ncpus = sched->max_cpu + 1; 1933a407b067SDavid Ahern u32 i, j; 1934a407b067SDavid Ahern 193549394a2aSDavid Ahern printf("%15s %6s ", "time", "cpu"); 193649394a2aSDavid Ahern 1937a407b067SDavid Ahern if (sched->show_cpu_visual) { 1938a407b067SDavid Ahern printf(" "); 1939a407b067SDavid Ahern for (i = 0, j = 0; i < ncpus; ++i) { 1940a407b067SDavid Ahern printf("%x", j++); 1941a407b067SDavid Ahern if (j > 15) 1942a407b067SDavid Ahern j = 0; 1943a407b067SDavid Ahern } 1944a407b067SDavid Ahern printf(" "); 1945a407b067SDavid Ahern } 1946a407b067SDavid Ahern 19470e6758e8SNamhyung Kim printf(" %-*s %9s %9s %9s", comm_width, 194849394a2aSDavid Ahern "task name", "wait time", "sch delay", "run time"); 194949394a2aSDavid Ahern 1950414e050cSNamhyung Kim if (sched->show_state) 1951414e050cSNamhyung Kim printf(" %s", "state"); 1952414e050cSNamhyung Kim 195349394a2aSDavid Ahern printf("\n"); 195449394a2aSDavid Ahern 195549394a2aSDavid Ahern /* 195649394a2aSDavid Ahern * units row 195749394a2aSDavid Ahern */ 195849394a2aSDavid Ahern printf("%15s %-6s ", "", ""); 195949394a2aSDavid Ahern 1960a407b067SDavid Ahern if (sched->show_cpu_visual) 1961a407b067SDavid Ahern printf(" %*s ", ncpus, ""); 1962a407b067SDavid Ahern 1963414e050cSNamhyung Kim printf(" %-*s %9s %9s %9s", comm_width, 19640e6758e8SNamhyung Kim "[tid/pid]", "(msec)", "(msec)", "(msec)"); 196549394a2aSDavid Ahern 1966414e050cSNamhyung Kim if (sched->show_state) 1967414e050cSNamhyung Kim printf(" %5s", ""); 1968414e050cSNamhyung Kim 1969414e050cSNamhyung Kim printf("\n"); 1970414e050cSNamhyung Kim 197149394a2aSDavid Ahern /* 197249394a2aSDavid Ahern * separator 197349394a2aSDavid Ahern */ 197449394a2aSDavid Ahern printf("%.15s %.6s ", graph_dotted_line, graph_dotted_line); 197549394a2aSDavid Ahern 1976a407b067SDavid Ahern if (sched->show_cpu_visual) 1977a407b067SDavid Ahern printf(" %.*s ", ncpus, graph_dotted_line); 1978a407b067SDavid Ahern 19790e6758e8SNamhyung Kim printf(" %.*s %.9s %.9s %.9s", comm_width, 198049394a2aSDavid Ahern graph_dotted_line, graph_dotted_line, graph_dotted_line, 198149394a2aSDavid Ahern graph_dotted_line); 198249394a2aSDavid Ahern 1983414e050cSNamhyung Kim if (sched->show_state) 1984414e050cSNamhyung Kim printf(" %.5s", graph_dotted_line); 1985414e050cSNamhyung Kim 198649394a2aSDavid Ahern printf("\n"); 198749394a2aSDavid Ahern } 198849394a2aSDavid Ahern 1989414e050cSNamhyung Kim static char task_state_char(struct thread *thread, int state) 1990414e050cSNamhyung Kim { 1991414e050cSNamhyung Kim static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; 1992414e050cSNamhyung Kim unsigned bit = state ? ffs(state) : 0; 1993414e050cSNamhyung Kim 1994414e050cSNamhyung Kim /* 'I' for idle */ 1995414e050cSNamhyung Kim if (thread->tid == 0) 1996414e050cSNamhyung Kim return 'I'; 1997414e050cSNamhyung Kim 1998414e050cSNamhyung Kim return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?'; 1999414e050cSNamhyung Kim } 2000414e050cSNamhyung Kim 2001fc1469f1SDavid Ahern static void timehist_print_sample(struct perf_sched *sched, 200232dcd021SJiri Olsa struct evsel *evsel, 2003fc1469f1SDavid Ahern struct perf_sample *sample, 20046c973c90SDavid Ahern struct addr_location *al, 2005853b7407SDavid Ahern struct thread *thread, 2006414e050cSNamhyung Kim u64 t, int state) 200749394a2aSDavid Ahern { 200849394a2aSDavid Ahern struct thread_runtime *tr = thread__priv(thread); 2009efc0cdc9SArnaldo Carvalho de Melo const char *next_comm = evsel__strval(evsel, sample, "next_comm"); 2010efc0cdc9SArnaldo Carvalho de Melo const u32 next_pid = evsel__intval(evsel, sample, "next_pid"); 2011a407b067SDavid Ahern u32 max_cpus = sched->max_cpu + 1; 201249394a2aSDavid Ahern char tstr[64]; 2013292c4a8fSBrendan Gregg char nstr[30]; 2014941bdea7SNamhyung Kim u64 wait_time; 201549394a2aSDavid Ahern 2016c30d630dSDavid Ahern if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 2017c30d630dSDavid Ahern return; 2018c30d630dSDavid Ahern 2019853b7407SDavid Ahern timestamp__scnprintf_usec(t, tstr, sizeof(tstr)); 202049394a2aSDavid Ahern printf("%15s [%04d] ", tstr, sample->cpu); 202149394a2aSDavid Ahern 2022a407b067SDavid Ahern if (sched->show_cpu_visual) { 2023a407b067SDavid Ahern u32 i; 2024a407b067SDavid Ahern char c; 2025a407b067SDavid Ahern 2026a407b067SDavid Ahern printf(" "); 2027a407b067SDavid Ahern for (i = 0; i < max_cpus; ++i) { 2028a407b067SDavid Ahern /* flag idle times with 'i'; others are sched events */ 2029a407b067SDavid Ahern if (i == sample->cpu) 2030a407b067SDavid Ahern c = (thread->tid == 0) ? 'i' : 's'; 2031a407b067SDavid Ahern else 2032a407b067SDavid Ahern c = ' '; 2033a407b067SDavid Ahern printf("%c", c); 2034a407b067SDavid Ahern } 2035a407b067SDavid Ahern printf(" "); 2036a407b067SDavid Ahern } 2037a407b067SDavid Ahern 203849394a2aSDavid Ahern printf(" %-*s ", comm_width, timehist_get_commstr(thread)); 203949394a2aSDavid Ahern 2040941bdea7SNamhyung Kim wait_time = tr->dt_sleep + tr->dt_iowait + tr->dt_preempt; 2041941bdea7SNamhyung Kim print_sched_time(wait_time, 6); 2042941bdea7SNamhyung Kim 204349394a2aSDavid Ahern print_sched_time(tr->dt_delay, 6); 204449394a2aSDavid Ahern print_sched_time(tr->dt_run, 6); 2045fc1469f1SDavid Ahern 2046414e050cSNamhyung Kim if (sched->show_state) 2047414e050cSNamhyung Kim printf(" %5c ", task_state_char(thread, state)); 2048414e050cSNamhyung Kim 2049292c4a8fSBrendan Gregg if (sched->show_next) { 2050292c4a8fSBrendan Gregg snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid); 2051292c4a8fSBrendan Gregg printf(" %-*s", comm_width, nstr); 2052292c4a8fSBrendan Gregg } 2053292c4a8fSBrendan Gregg 2054292c4a8fSBrendan Gregg if (sched->show_wakeups && !sched->show_next) 2055fc1469f1SDavid Ahern printf(" %-*s", comm_width, ""); 2056fc1469f1SDavid Ahern 20576c973c90SDavid Ahern if (thread->tid == 0) 20586c973c90SDavid Ahern goto out; 20596c973c90SDavid Ahern 20606c973c90SDavid Ahern if (sched->show_callchain) 20616c973c90SDavid Ahern printf(" "); 20626c973c90SDavid Ahern 20636c973c90SDavid Ahern sample__fprintf_sym(sample, al, 0, 20646c973c90SDavid Ahern EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE | 20652d9bbf6eSNamhyung Kim EVSEL__PRINT_CALLCHAIN_ARROW | 20662d9bbf6eSNamhyung Kim EVSEL__PRINT_SKIP_IGNORED, 20679620bc36SArnaldo Carvalho de Melo &callchain_cursor, symbol_conf.bt_stop_list, stdout); 20686c973c90SDavid Ahern 20696c973c90SDavid Ahern out: 207049394a2aSDavid Ahern printf("\n"); 207149394a2aSDavid Ahern } 207249394a2aSDavid Ahern 207349394a2aSDavid Ahern /* 207449394a2aSDavid Ahern * Explanation of delta-time stats: 207549394a2aSDavid Ahern * 207649394a2aSDavid Ahern * t = time of current schedule out event 207749394a2aSDavid Ahern * tprev = time of previous sched out event 207849394a2aSDavid Ahern * also time of schedule-in event for current task 207949394a2aSDavid Ahern * last_time = time of last sched change event for current task 208049394a2aSDavid Ahern * (i.e, time process was last scheduled out) 208149394a2aSDavid Ahern * ready_to_run = time of wakeup for current task 208249394a2aSDavid Ahern * 208349394a2aSDavid Ahern * -----|------------|------------|------------|------ 208449394a2aSDavid Ahern * last ready tprev t 208549394a2aSDavid Ahern * time to run 208649394a2aSDavid Ahern * 208749394a2aSDavid Ahern * |-------- dt_wait --------| 208849394a2aSDavid Ahern * |- dt_delay -|-- dt_run --| 208949394a2aSDavid Ahern * 209049394a2aSDavid Ahern * dt_run = run time of current task 209149394a2aSDavid Ahern * dt_wait = time between last schedule out event for task and tprev 209249394a2aSDavid Ahern * represents time spent off the cpu 209349394a2aSDavid Ahern * dt_delay = time between wakeup and schedule-in of task 209449394a2aSDavid Ahern */ 209549394a2aSDavid Ahern 209649394a2aSDavid Ahern static void timehist_update_runtime_stats(struct thread_runtime *r, 209749394a2aSDavid Ahern u64 t, u64 tprev) 209849394a2aSDavid Ahern { 209949394a2aSDavid Ahern r->dt_delay = 0; 2100941bdea7SNamhyung Kim r->dt_sleep = 0; 2101941bdea7SNamhyung Kim r->dt_iowait = 0; 2102941bdea7SNamhyung Kim r->dt_preempt = 0; 210349394a2aSDavid Ahern r->dt_run = 0; 2104941bdea7SNamhyung Kim 210549394a2aSDavid Ahern if (tprev) { 210649394a2aSDavid Ahern r->dt_run = t - tprev; 210749394a2aSDavid Ahern if (r->ready_to_run) { 210849394a2aSDavid Ahern if (r->ready_to_run > tprev) 210949394a2aSDavid Ahern pr_debug("time travel: wakeup time for task > previous sched_switch event\n"); 211049394a2aSDavid Ahern else 211149394a2aSDavid Ahern r->dt_delay = tprev - r->ready_to_run; 211249394a2aSDavid Ahern } 211349394a2aSDavid Ahern 211449394a2aSDavid Ahern if (r->last_time > tprev) 211549394a2aSDavid Ahern pr_debug("time travel: last sched out time for task > previous sched_switch event\n"); 2116941bdea7SNamhyung Kim else if (r->last_time) { 2117941bdea7SNamhyung Kim u64 dt_wait = tprev - r->last_time; 2118941bdea7SNamhyung Kim 2119941bdea7SNamhyung Kim if (r->last_state == TASK_RUNNING) 2120941bdea7SNamhyung Kim r->dt_preempt = dt_wait; 2121941bdea7SNamhyung Kim else if (r->last_state == TASK_UNINTERRUPTIBLE) 2122941bdea7SNamhyung Kim r->dt_iowait = dt_wait; 2123941bdea7SNamhyung Kim else 2124941bdea7SNamhyung Kim r->dt_sleep = dt_wait; 2125941bdea7SNamhyung Kim } 212649394a2aSDavid Ahern } 212749394a2aSDavid Ahern 212849394a2aSDavid Ahern update_stats(&r->run_stats, r->dt_run); 2129587782c5SNamhyung Kim 213049394a2aSDavid Ahern r->total_run_time += r->dt_run; 2131587782c5SNamhyung Kim r->total_delay_time += r->dt_delay; 2132587782c5SNamhyung Kim r->total_sleep_time += r->dt_sleep; 2133587782c5SNamhyung Kim r->total_iowait_time += r->dt_iowait; 2134587782c5SNamhyung Kim r->total_preempt_time += r->dt_preempt; 213549394a2aSDavid Ahern } 213649394a2aSDavid Ahern 213796039c7cSNamhyung Kim static bool is_idle_sample(struct perf_sample *sample, 213832dcd021SJiri Olsa struct evsel *evsel) 213996039c7cSNamhyung Kim { 214096039c7cSNamhyung Kim /* pid 0 == swapper == idle task */ 21418ab2e96dSArnaldo Carvalho de Melo if (strcmp(evsel__name(evsel), "sched:sched_switch") == 0) 2142efc0cdc9SArnaldo Carvalho de Melo return evsel__intval(evsel, sample, "prev_pid") == 0; 214396039c7cSNamhyung Kim 214496039c7cSNamhyung Kim return sample->pid == 0; 214596039c7cSNamhyung Kim } 214696039c7cSNamhyung Kim 214796039c7cSNamhyung Kim static void save_task_callchain(struct perf_sched *sched, 21486c973c90SDavid Ahern struct perf_sample *sample, 214932dcd021SJiri Olsa struct evsel *evsel, 21506c973c90SDavid Ahern struct machine *machine) 215149394a2aSDavid Ahern { 21526c973c90SDavid Ahern struct callchain_cursor *cursor = &callchain_cursor; 215396039c7cSNamhyung Kim struct thread *thread; 21546c973c90SDavid Ahern 21556c973c90SDavid Ahern /* want main thread for process - has maps */ 21566c973c90SDavid Ahern thread = machine__findnew_thread(machine, sample->pid, sample->pid); 21576c973c90SDavid Ahern if (thread == NULL) { 21586c973c90SDavid Ahern pr_debug("Failed to get thread for pid %d.\n", sample->pid); 215996039c7cSNamhyung Kim return; 21606c973c90SDavid Ahern } 21616c973c90SDavid Ahern 21624c50563dSArnaldo Carvalho de Melo if (!sched->show_callchain || sample->callchain == NULL) 216396039c7cSNamhyung Kim return; 21646c973c90SDavid Ahern 21656c973c90SDavid Ahern if (thread__resolve_callchain(thread, cursor, evsel, sample, 21668388deb3SNamhyung Kim NULL, NULL, sched->max_stack + 2) != 0) { 2167bb963e16SNamhyung Kim if (verbose > 0) 216862d94b00SArnaldo Carvalho de Melo pr_err("Failed to resolve callchain. Skipping\n"); 21696c973c90SDavid Ahern 217096039c7cSNamhyung Kim return; 21716c973c90SDavid Ahern } 2172cdeb01bfSNamhyung Kim 21736c973c90SDavid Ahern callchain_cursor_commit(cursor); 2174cdeb01bfSNamhyung Kim 2175cdeb01bfSNamhyung Kim while (true) { 2176cdeb01bfSNamhyung Kim struct callchain_cursor_node *node; 2177cdeb01bfSNamhyung Kim struct symbol *sym; 2178cdeb01bfSNamhyung Kim 2179cdeb01bfSNamhyung Kim node = callchain_cursor_current(cursor); 2180cdeb01bfSNamhyung Kim if (node == NULL) 2181cdeb01bfSNamhyung Kim break; 2182cdeb01bfSNamhyung Kim 21835f0fef8aSArnaldo Carvalho de Melo sym = node->ms.sym; 2184a7c3899cSArnaldo Carvalho de Melo if (sym) { 2185cdeb01bfSNamhyung Kim if (!strcmp(sym->name, "schedule") || 2186cdeb01bfSNamhyung Kim !strcmp(sym->name, "__schedule") || 2187cdeb01bfSNamhyung Kim !strcmp(sym->name, "preempt_schedule")) 2188cdeb01bfSNamhyung Kim sym->ignore = 1; 2189cdeb01bfSNamhyung Kim } 2190cdeb01bfSNamhyung Kim 2191cdeb01bfSNamhyung Kim callchain_cursor_advance(cursor); 2192cdeb01bfSNamhyung Kim } 219349394a2aSDavid Ahern } 219449394a2aSDavid Ahern 21953bc2fa9cSNamhyung Kim static int init_idle_thread(struct thread *thread) 21963bc2fa9cSNamhyung Kim { 21973bc2fa9cSNamhyung Kim struct idle_thread_runtime *itr; 21983bc2fa9cSNamhyung Kim 21993bc2fa9cSNamhyung Kim thread__set_comm(thread, idle_comm, 0); 22003bc2fa9cSNamhyung Kim 22013bc2fa9cSNamhyung Kim itr = zalloc(sizeof(*itr)); 22023bc2fa9cSNamhyung Kim if (itr == NULL) 22033bc2fa9cSNamhyung Kim return -ENOMEM; 22043bc2fa9cSNamhyung Kim 22053bc2fa9cSNamhyung Kim init_stats(&itr->tr.run_stats); 22063bc2fa9cSNamhyung Kim callchain_init(&itr->callchain); 22073bc2fa9cSNamhyung Kim callchain_cursor_reset(&itr->cursor); 22083bc2fa9cSNamhyung Kim thread__set_priv(thread, itr); 22093bc2fa9cSNamhyung Kim 22103bc2fa9cSNamhyung Kim return 0; 22113bc2fa9cSNamhyung Kim } 22123bc2fa9cSNamhyung Kim 221349394a2aSDavid Ahern /* 221449394a2aSDavid Ahern * Track idle stats per cpu by maintaining a local thread 221549394a2aSDavid Ahern * struct for the idle task on each cpu. 221649394a2aSDavid Ahern */ 221749394a2aSDavid Ahern static int init_idle_threads(int ncpu) 221849394a2aSDavid Ahern { 22193bc2fa9cSNamhyung Kim int i, ret; 222049394a2aSDavid Ahern 222149394a2aSDavid Ahern idle_threads = zalloc(ncpu * sizeof(struct thread *)); 222249394a2aSDavid Ahern if (!idle_threads) 222349394a2aSDavid Ahern return -ENOMEM; 222449394a2aSDavid Ahern 2225b336352bSNamhyung Kim idle_max_cpu = ncpu; 222649394a2aSDavid Ahern 222749394a2aSDavid Ahern /* allocate the actual thread struct if needed */ 222849394a2aSDavid Ahern for (i = 0; i < ncpu; ++i) { 222949394a2aSDavid Ahern idle_threads[i] = thread__new(0, 0); 223049394a2aSDavid Ahern if (idle_threads[i] == NULL) 223149394a2aSDavid Ahern return -ENOMEM; 223249394a2aSDavid Ahern 22333bc2fa9cSNamhyung Kim ret = init_idle_thread(idle_threads[i]); 22343bc2fa9cSNamhyung Kim if (ret < 0) 22353bc2fa9cSNamhyung Kim return ret; 223649394a2aSDavid Ahern } 223749394a2aSDavid Ahern 223849394a2aSDavid Ahern return 0; 223949394a2aSDavid Ahern } 224049394a2aSDavid Ahern 224149394a2aSDavid Ahern static void free_idle_threads(void) 224249394a2aSDavid Ahern { 224349394a2aSDavid Ahern int i; 224449394a2aSDavid Ahern 224549394a2aSDavid Ahern if (idle_threads == NULL) 224649394a2aSDavid Ahern return; 224749394a2aSDavid Ahern 2248b336352bSNamhyung Kim for (i = 0; i < idle_max_cpu; ++i) { 224949394a2aSDavid Ahern if ((idle_threads[i])) 225049394a2aSDavid Ahern thread__delete(idle_threads[i]); 225149394a2aSDavid Ahern } 225249394a2aSDavid Ahern 225349394a2aSDavid Ahern free(idle_threads); 225449394a2aSDavid Ahern } 225549394a2aSDavid Ahern 225649394a2aSDavid Ahern static struct thread *get_idle_thread(int cpu) 225749394a2aSDavid Ahern { 225849394a2aSDavid Ahern /* 225949394a2aSDavid Ahern * expand/allocate array of pointers to local thread 226049394a2aSDavid Ahern * structs if needed 226149394a2aSDavid Ahern */ 226249394a2aSDavid Ahern if ((cpu >= idle_max_cpu) || (idle_threads == NULL)) { 226349394a2aSDavid Ahern int i, j = __roundup_pow_of_two(cpu+1); 226449394a2aSDavid Ahern void *p; 226549394a2aSDavid Ahern 226649394a2aSDavid Ahern p = realloc(idle_threads, j * sizeof(struct thread *)); 226749394a2aSDavid Ahern if (!p) 226849394a2aSDavid Ahern return NULL; 226949394a2aSDavid Ahern 227049394a2aSDavid Ahern idle_threads = (struct thread **) p; 2271b336352bSNamhyung Kim for (i = idle_max_cpu; i < j; ++i) 227249394a2aSDavid Ahern idle_threads[i] = NULL; 227349394a2aSDavid Ahern 227449394a2aSDavid Ahern idle_max_cpu = j; 227549394a2aSDavid Ahern } 227649394a2aSDavid Ahern 227749394a2aSDavid Ahern /* allocate a new thread struct if needed */ 227849394a2aSDavid Ahern if (idle_threads[cpu] == NULL) { 227949394a2aSDavid Ahern idle_threads[cpu] = thread__new(0, 0); 228049394a2aSDavid Ahern 228149394a2aSDavid Ahern if (idle_threads[cpu]) { 22823bc2fa9cSNamhyung Kim if (init_idle_thread(idle_threads[cpu]) < 0) 22833bc2fa9cSNamhyung Kim return NULL; 228449394a2aSDavid Ahern } 228549394a2aSDavid Ahern } 228649394a2aSDavid Ahern 228749394a2aSDavid Ahern return idle_threads[cpu]; 228849394a2aSDavid Ahern } 228949394a2aSDavid Ahern 22904c50563dSArnaldo Carvalho de Melo static void save_idle_callchain(struct perf_sched *sched, 22914c50563dSArnaldo Carvalho de Melo struct idle_thread_runtime *itr, 2292699b5b92SNamhyung Kim struct perf_sample *sample) 2293699b5b92SNamhyung Kim { 22944c50563dSArnaldo Carvalho de Melo if (!sched->show_callchain || sample->callchain == NULL) 2295699b5b92SNamhyung Kim return; 2296699b5b92SNamhyung Kim 2297699b5b92SNamhyung Kim callchain_cursor__copy(&itr->cursor, &callchain_cursor); 2298699b5b92SNamhyung Kim } 2299699b5b92SNamhyung Kim 23006c973c90SDavid Ahern static struct thread *timehist_get_thread(struct perf_sched *sched, 23016c973c90SDavid Ahern struct perf_sample *sample, 230249394a2aSDavid Ahern struct machine *machine, 230332dcd021SJiri Olsa struct evsel *evsel) 230449394a2aSDavid Ahern { 230549394a2aSDavid Ahern struct thread *thread; 230649394a2aSDavid Ahern 230796039c7cSNamhyung Kim if (is_idle_sample(sample, evsel)) { 230849394a2aSDavid Ahern thread = get_idle_thread(sample->cpu); 230949394a2aSDavid Ahern if (thread == NULL) 231049394a2aSDavid Ahern pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); 231149394a2aSDavid Ahern 231249394a2aSDavid Ahern } else { 23135d92d96aSNamhyung Kim /* there were samples with tid 0 but non-zero pid */ 23145d92d96aSNamhyung Kim thread = machine__findnew_thread(machine, sample->pid, 23155d92d96aSNamhyung Kim sample->tid ?: sample->pid); 231649394a2aSDavid Ahern if (thread == NULL) { 231749394a2aSDavid Ahern pr_debug("Failed to get thread for tid %d. skipping sample.\n", 231849394a2aSDavid Ahern sample->tid); 231949394a2aSDavid Ahern } 232096039c7cSNamhyung Kim 232196039c7cSNamhyung Kim save_task_callchain(sched, sample, evsel, machine); 2322699b5b92SNamhyung Kim if (sched->idle_hist) { 2323699b5b92SNamhyung Kim struct thread *idle; 2324699b5b92SNamhyung Kim struct idle_thread_runtime *itr; 2325699b5b92SNamhyung Kim 2326699b5b92SNamhyung Kim idle = get_idle_thread(sample->cpu); 2327699b5b92SNamhyung Kim if (idle == NULL) { 2328699b5b92SNamhyung Kim pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); 2329699b5b92SNamhyung Kim return NULL; 2330699b5b92SNamhyung Kim } 2331699b5b92SNamhyung Kim 2332699b5b92SNamhyung Kim itr = thread__priv(idle); 2333699b5b92SNamhyung Kim if (itr == NULL) 2334699b5b92SNamhyung Kim return NULL; 2335699b5b92SNamhyung Kim 2336699b5b92SNamhyung Kim itr->last_thread = thread; 2337699b5b92SNamhyung Kim 2338699b5b92SNamhyung Kim /* copy task callchain when entering to idle */ 2339efc0cdc9SArnaldo Carvalho de Melo if (evsel__intval(evsel, sample, "next_pid") == 0) 23404c50563dSArnaldo Carvalho de Melo save_idle_callchain(sched, itr, sample); 2341699b5b92SNamhyung Kim } 234249394a2aSDavid Ahern } 234349394a2aSDavid Ahern 234449394a2aSDavid Ahern return thread; 234549394a2aSDavid Ahern } 234649394a2aSDavid Ahern 234752df138cSDavid Ahern static bool timehist_skip_sample(struct perf_sched *sched, 2348a4b2b6f5SNamhyung Kim struct thread *thread, 234932dcd021SJiri Olsa struct evsel *evsel, 2350a4b2b6f5SNamhyung Kim struct perf_sample *sample) 235149394a2aSDavid Ahern { 235249394a2aSDavid Ahern bool rc = false; 235349394a2aSDavid Ahern 235452df138cSDavid Ahern if (thread__is_filtered(thread)) { 235549394a2aSDavid Ahern rc = true; 235652df138cSDavid Ahern sched->skipped_samples++; 235752df138cSDavid Ahern } 235849394a2aSDavid Ahern 2359a4b2b6f5SNamhyung Kim if (sched->idle_hist) { 23608ab2e96dSArnaldo Carvalho de Melo if (strcmp(evsel__name(evsel), "sched:sched_switch")) 2361a4b2b6f5SNamhyung Kim rc = true; 2362efc0cdc9SArnaldo Carvalho de Melo else if (evsel__intval(evsel, sample, "prev_pid") != 0 && 2363efc0cdc9SArnaldo Carvalho de Melo evsel__intval(evsel, sample, "next_pid") != 0) 2364a4b2b6f5SNamhyung Kim rc = true; 2365a4b2b6f5SNamhyung Kim } 2366a4b2b6f5SNamhyung Kim 236749394a2aSDavid Ahern return rc; 236849394a2aSDavid Ahern } 236949394a2aSDavid Ahern 2370fc1469f1SDavid Ahern static void timehist_print_wakeup_event(struct perf_sched *sched, 237132dcd021SJiri Olsa struct evsel *evsel, 2372fc1469f1SDavid Ahern struct perf_sample *sample, 2373fc1469f1SDavid Ahern struct machine *machine, 2374fc1469f1SDavid Ahern struct thread *awakened) 2375fc1469f1SDavid Ahern { 2376fc1469f1SDavid Ahern struct thread *thread; 2377fc1469f1SDavid Ahern char tstr[64]; 2378fc1469f1SDavid Ahern 2379fc1469f1SDavid Ahern thread = machine__findnew_thread(machine, sample->pid, sample->tid); 2380fc1469f1SDavid Ahern if (thread == NULL) 2381fc1469f1SDavid Ahern return; 2382fc1469f1SDavid Ahern 2383fc1469f1SDavid Ahern /* show wakeup unless both awakee and awaker are filtered */ 2384a4b2b6f5SNamhyung Kim if (timehist_skip_sample(sched, thread, evsel, sample) && 2385a4b2b6f5SNamhyung Kim timehist_skip_sample(sched, awakened, evsel, sample)) { 2386fc1469f1SDavid Ahern return; 2387fc1469f1SDavid Ahern } 2388fc1469f1SDavid Ahern 2389fc1469f1SDavid Ahern timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); 2390fc1469f1SDavid Ahern printf("%15s [%04d] ", tstr, sample->cpu); 2391a407b067SDavid Ahern if (sched->show_cpu_visual) 2392a407b067SDavid Ahern printf(" %*s ", sched->max_cpu + 1, ""); 2393fc1469f1SDavid Ahern 2394fc1469f1SDavid Ahern printf(" %-*s ", comm_width, timehist_get_commstr(thread)); 2395fc1469f1SDavid Ahern 2396fc1469f1SDavid Ahern /* dt spacer */ 2397fc1469f1SDavid Ahern printf(" %9s %9s %9s ", "", "", ""); 2398fc1469f1SDavid Ahern 2399fc1469f1SDavid Ahern printf("awakened: %s", timehist_get_commstr(awakened)); 2400fc1469f1SDavid Ahern 2401fc1469f1SDavid Ahern printf("\n"); 2402fc1469f1SDavid Ahern } 2403fc1469f1SDavid Ahern 2404d566a9c2SDavid Ahern static int timehist_sched_wakeup_ignore(struct perf_tool *tool __maybe_unused, 2405d566a9c2SDavid Ahern union perf_event *event __maybe_unused, 2406d566a9c2SDavid Ahern struct evsel *evsel __maybe_unused, 2407d566a9c2SDavid Ahern struct perf_sample *sample __maybe_unused, 2408d566a9c2SDavid Ahern struct machine *machine __maybe_unused) 2409d566a9c2SDavid Ahern { 2410d566a9c2SDavid Ahern return 0; 2411d566a9c2SDavid Ahern } 2412d566a9c2SDavid Ahern 2413fc1469f1SDavid Ahern static int timehist_sched_wakeup_event(struct perf_tool *tool, 241449394a2aSDavid Ahern union perf_event *event __maybe_unused, 241532dcd021SJiri Olsa struct evsel *evsel, 241649394a2aSDavid Ahern struct perf_sample *sample, 241749394a2aSDavid Ahern struct machine *machine) 241849394a2aSDavid Ahern { 2419fc1469f1SDavid Ahern struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 242049394a2aSDavid Ahern struct thread *thread; 242149394a2aSDavid Ahern struct thread_runtime *tr = NULL; 242249394a2aSDavid Ahern /* want pid of awakened task not pid in sample */ 2423efc0cdc9SArnaldo Carvalho de Melo const u32 pid = evsel__intval(evsel, sample, "pid"); 242449394a2aSDavid Ahern 242549394a2aSDavid Ahern thread = machine__findnew_thread(machine, 0, pid); 242649394a2aSDavid Ahern if (thread == NULL) 242749394a2aSDavid Ahern return -1; 242849394a2aSDavid Ahern 242949394a2aSDavid Ahern tr = thread__get_runtime(thread); 243049394a2aSDavid Ahern if (tr == NULL) 243149394a2aSDavid Ahern return -1; 243249394a2aSDavid Ahern 243349394a2aSDavid Ahern if (tr->ready_to_run == 0) 243449394a2aSDavid Ahern tr->ready_to_run = sample->time; 243549394a2aSDavid Ahern 2436fc1469f1SDavid Ahern /* show wakeups if requested */ 2437853b7407SDavid Ahern if (sched->show_wakeups && 2438853b7407SDavid Ahern !perf_time__skip_sample(&sched->ptime, sample->time)) 2439a4b2b6f5SNamhyung Kim timehist_print_wakeup_event(sched, evsel, sample, machine, thread); 2440fc1469f1SDavid Ahern 244149394a2aSDavid Ahern return 0; 244249394a2aSDavid Ahern } 244349394a2aSDavid Ahern 2444350f54faSDavid Ahern static void timehist_print_migration_event(struct perf_sched *sched, 244532dcd021SJiri Olsa struct evsel *evsel, 2446350f54faSDavid Ahern struct perf_sample *sample, 2447350f54faSDavid Ahern struct machine *machine, 2448350f54faSDavid Ahern struct thread *migrated) 2449350f54faSDavid Ahern { 2450350f54faSDavid Ahern struct thread *thread; 2451350f54faSDavid Ahern char tstr[64]; 2452350f54faSDavid Ahern u32 max_cpus = sched->max_cpu + 1; 2453350f54faSDavid Ahern u32 ocpu, dcpu; 2454350f54faSDavid Ahern 2455350f54faSDavid Ahern if (sched->summary_only) 2456350f54faSDavid Ahern return; 2457350f54faSDavid Ahern 2458350f54faSDavid Ahern max_cpus = sched->max_cpu + 1; 2459efc0cdc9SArnaldo Carvalho de Melo ocpu = evsel__intval(evsel, sample, "orig_cpu"); 2460efc0cdc9SArnaldo Carvalho de Melo dcpu = evsel__intval(evsel, sample, "dest_cpu"); 2461350f54faSDavid Ahern 2462350f54faSDavid Ahern thread = machine__findnew_thread(machine, sample->pid, sample->tid); 2463350f54faSDavid Ahern if (thread == NULL) 2464350f54faSDavid Ahern return; 2465350f54faSDavid Ahern 2466a4b2b6f5SNamhyung Kim if (timehist_skip_sample(sched, thread, evsel, sample) && 2467a4b2b6f5SNamhyung Kim timehist_skip_sample(sched, migrated, evsel, sample)) { 2468350f54faSDavid Ahern return; 2469350f54faSDavid Ahern } 2470350f54faSDavid Ahern 2471350f54faSDavid Ahern timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); 2472350f54faSDavid Ahern printf("%15s [%04d] ", tstr, sample->cpu); 2473350f54faSDavid Ahern 2474350f54faSDavid Ahern if (sched->show_cpu_visual) { 2475350f54faSDavid Ahern u32 i; 2476350f54faSDavid Ahern char c; 2477350f54faSDavid Ahern 2478350f54faSDavid Ahern printf(" "); 2479350f54faSDavid Ahern for (i = 0; i < max_cpus; ++i) { 2480350f54faSDavid Ahern c = (i == sample->cpu) ? 'm' : ' '; 2481350f54faSDavid Ahern printf("%c", c); 2482350f54faSDavid Ahern } 2483350f54faSDavid Ahern printf(" "); 2484350f54faSDavid Ahern } 2485350f54faSDavid Ahern 2486350f54faSDavid Ahern printf(" %-*s ", comm_width, timehist_get_commstr(thread)); 2487350f54faSDavid Ahern 2488350f54faSDavid Ahern /* dt spacer */ 2489350f54faSDavid Ahern printf(" %9s %9s %9s ", "", "", ""); 2490350f54faSDavid Ahern 2491350f54faSDavid Ahern printf("migrated: %s", timehist_get_commstr(migrated)); 2492350f54faSDavid Ahern printf(" cpu %d => %d", ocpu, dcpu); 2493350f54faSDavid Ahern 2494350f54faSDavid Ahern printf("\n"); 2495350f54faSDavid Ahern } 2496350f54faSDavid Ahern 2497350f54faSDavid Ahern static int timehist_migrate_task_event(struct perf_tool *tool, 2498350f54faSDavid Ahern union perf_event *event __maybe_unused, 249932dcd021SJiri Olsa struct evsel *evsel, 2500350f54faSDavid Ahern struct perf_sample *sample, 2501350f54faSDavid Ahern struct machine *machine) 2502350f54faSDavid Ahern { 2503350f54faSDavid Ahern struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 2504350f54faSDavid Ahern struct thread *thread; 2505350f54faSDavid Ahern struct thread_runtime *tr = NULL; 2506350f54faSDavid Ahern /* want pid of migrated task not pid in sample */ 2507efc0cdc9SArnaldo Carvalho de Melo const u32 pid = evsel__intval(evsel, sample, "pid"); 2508350f54faSDavid Ahern 2509350f54faSDavid Ahern thread = machine__findnew_thread(machine, 0, pid); 2510350f54faSDavid Ahern if (thread == NULL) 2511350f54faSDavid Ahern return -1; 2512350f54faSDavid Ahern 2513350f54faSDavid Ahern tr = thread__get_runtime(thread); 2514350f54faSDavid Ahern if (tr == NULL) 2515350f54faSDavid Ahern return -1; 2516350f54faSDavid Ahern 2517350f54faSDavid Ahern tr->migrations++; 2518350f54faSDavid Ahern 2519350f54faSDavid Ahern /* show migrations if requested */ 2520350f54faSDavid Ahern timehist_print_migration_event(sched, evsel, sample, machine, thread); 2521350f54faSDavid Ahern 2522350f54faSDavid Ahern return 0; 2523350f54faSDavid Ahern } 2524350f54faSDavid Ahern 252552df138cSDavid Ahern static int timehist_sched_change_event(struct perf_tool *tool, 252649394a2aSDavid Ahern union perf_event *event, 252732dcd021SJiri Olsa struct evsel *evsel, 252849394a2aSDavid Ahern struct perf_sample *sample, 252949394a2aSDavid Ahern struct machine *machine) 253049394a2aSDavid Ahern { 2531fc1469f1SDavid Ahern struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 2532853b7407SDavid Ahern struct perf_time_interval *ptime = &sched->ptime; 253349394a2aSDavid Ahern struct addr_location al; 253449394a2aSDavid Ahern struct thread *thread; 253549394a2aSDavid Ahern struct thread_runtime *tr = NULL; 2536853b7407SDavid Ahern u64 tprev, t = sample->time; 253749394a2aSDavid Ahern int rc = 0; 2538efc0cdc9SArnaldo Carvalho de Melo int state = evsel__intval(evsel, sample, "prev_state"); 253949394a2aSDavid Ahern 254049394a2aSDavid Ahern if (machine__resolve(machine, &al, sample) < 0) { 254149394a2aSDavid Ahern pr_err("problem processing %d event. skipping it\n", 254249394a2aSDavid Ahern event->header.type); 254349394a2aSDavid Ahern rc = -1; 254449394a2aSDavid Ahern goto out; 254549394a2aSDavid Ahern } 254649394a2aSDavid Ahern 25476c973c90SDavid Ahern thread = timehist_get_thread(sched, sample, machine, evsel); 254849394a2aSDavid Ahern if (thread == NULL) { 254949394a2aSDavid Ahern rc = -1; 255049394a2aSDavid Ahern goto out; 255149394a2aSDavid Ahern } 255249394a2aSDavid Ahern 2553a4b2b6f5SNamhyung Kim if (timehist_skip_sample(sched, thread, evsel, sample)) 255449394a2aSDavid Ahern goto out; 255549394a2aSDavid Ahern 255649394a2aSDavid Ahern tr = thread__get_runtime(thread); 255749394a2aSDavid Ahern if (tr == NULL) { 255849394a2aSDavid Ahern rc = -1; 255949394a2aSDavid Ahern goto out; 256049394a2aSDavid Ahern } 256149394a2aSDavid Ahern 25623b7313f2SArnaldo Carvalho de Melo tprev = evsel__get_time(evsel, sample->cpu); 256349394a2aSDavid Ahern 2564853b7407SDavid Ahern /* 2565853b7407SDavid Ahern * If start time given: 2566853b7407SDavid Ahern * - sample time is under window user cares about - skip sample 2567853b7407SDavid Ahern * - tprev is under window user cares about - reset to start of window 2568853b7407SDavid Ahern */ 2569853b7407SDavid Ahern if (ptime->start && ptime->start > t) 2570853b7407SDavid Ahern goto out; 2571853b7407SDavid Ahern 2572bdd75729SNamhyung Kim if (tprev && ptime->start > tprev) 2573853b7407SDavid Ahern tprev = ptime->start; 2574853b7407SDavid Ahern 2575853b7407SDavid Ahern /* 2576853b7407SDavid Ahern * If end time given: 2577853b7407SDavid Ahern * - previous sched event is out of window - we are done 2578853b7407SDavid Ahern * - sample time is beyond window user cares about - reset it 2579853b7407SDavid Ahern * to close out stats for time window interest 2580853b7407SDavid Ahern */ 2581853b7407SDavid Ahern if (ptime->end) { 2582853b7407SDavid Ahern if (tprev > ptime->end) 2583853b7407SDavid Ahern goto out; 2584853b7407SDavid Ahern 2585853b7407SDavid Ahern if (t > ptime->end) 2586853b7407SDavid Ahern t = ptime->end; 2587853b7407SDavid Ahern } 2588853b7407SDavid Ahern 258907235f84SNamhyung Kim if (!sched->idle_hist || thread->tid == 0) { 2590a74eaf16SDavid Ahern if (!cpu_list || test_bit(sample->cpu, cpu_bitmap)) 2591853b7407SDavid Ahern timehist_update_runtime_stats(tr, t, tprev); 2592853b7407SDavid Ahern 259307235f84SNamhyung Kim if (sched->idle_hist) { 259407235f84SNamhyung Kim struct idle_thread_runtime *itr = (void *)tr; 259507235f84SNamhyung Kim struct thread_runtime *last_tr; 259607235f84SNamhyung Kim 259707235f84SNamhyung Kim BUG_ON(thread->tid != 0); 259807235f84SNamhyung Kim 259907235f84SNamhyung Kim if (itr->last_thread == NULL) 260007235f84SNamhyung Kim goto out; 260107235f84SNamhyung Kim 260207235f84SNamhyung Kim /* add current idle time as last thread's runtime */ 260307235f84SNamhyung Kim last_tr = thread__get_runtime(itr->last_thread); 260407235f84SNamhyung Kim if (last_tr == NULL) 260507235f84SNamhyung Kim goto out; 260607235f84SNamhyung Kim 260707235f84SNamhyung Kim timehist_update_runtime_stats(last_tr, t, tprev); 260807235f84SNamhyung Kim /* 260907235f84SNamhyung Kim * remove delta time of last thread as it's not updated 261007235f84SNamhyung Kim * and otherwise it will show an invalid value next 261107235f84SNamhyung Kim * time. we only care total run time and run stat. 261207235f84SNamhyung Kim */ 261307235f84SNamhyung Kim last_tr->dt_run = 0; 261407235f84SNamhyung Kim last_tr->dt_delay = 0; 2615941bdea7SNamhyung Kim last_tr->dt_sleep = 0; 2616941bdea7SNamhyung Kim last_tr->dt_iowait = 0; 2617941bdea7SNamhyung Kim last_tr->dt_preempt = 0; 261807235f84SNamhyung Kim 2619ba957ebbSNamhyung Kim if (itr->cursor.nr) 2620ba957ebbSNamhyung Kim callchain_append(&itr->callchain, &itr->cursor, t - tprev); 2621ba957ebbSNamhyung Kim 262207235f84SNamhyung Kim itr->last_thread = NULL; 262307235f84SNamhyung Kim } 262407235f84SNamhyung Kim } 262507235f84SNamhyung Kim 262652df138cSDavid Ahern if (!sched->summary_only) 2627292c4a8fSBrendan Gregg timehist_print_sample(sched, evsel, sample, &al, thread, t, state); 262849394a2aSDavid Ahern 262949394a2aSDavid Ahern out: 26309396c9cbSNamhyung Kim if (sched->hist_time.start == 0 && t >= ptime->start) 26319396c9cbSNamhyung Kim sched->hist_time.start = t; 26329396c9cbSNamhyung Kim if (ptime->end == 0 || t <= ptime->end) 26339396c9cbSNamhyung Kim sched->hist_time.end = t; 26349396c9cbSNamhyung Kim 263549394a2aSDavid Ahern if (tr) { 263649394a2aSDavid Ahern /* time of this sched_switch event becomes last time task seen */ 263749394a2aSDavid Ahern tr->last_time = sample->time; 263849394a2aSDavid Ahern 2639941bdea7SNamhyung Kim /* last state is used to determine where to account wait time */ 2640414e050cSNamhyung Kim tr->last_state = state; 2641941bdea7SNamhyung Kim 264249394a2aSDavid Ahern /* sched out event for task so reset ready to run time */ 264349394a2aSDavid Ahern tr->ready_to_run = 0; 264449394a2aSDavid Ahern } 264549394a2aSDavid Ahern 26463b7313f2SArnaldo Carvalho de Melo evsel__save_time(evsel, sample->time, sample->cpu); 264749394a2aSDavid Ahern 264849394a2aSDavid Ahern return rc; 264949394a2aSDavid Ahern } 265049394a2aSDavid Ahern 265149394a2aSDavid Ahern static int timehist_sched_switch_event(struct perf_tool *tool, 265249394a2aSDavid Ahern union perf_event *event, 265332dcd021SJiri Olsa struct evsel *evsel, 265449394a2aSDavid Ahern struct perf_sample *sample, 265549394a2aSDavid Ahern struct machine *machine __maybe_unused) 265649394a2aSDavid Ahern { 265749394a2aSDavid Ahern return timehist_sched_change_event(tool, event, evsel, sample, machine); 265849394a2aSDavid Ahern } 265949394a2aSDavid Ahern 266049394a2aSDavid Ahern static int process_lost(struct perf_tool *tool __maybe_unused, 266149394a2aSDavid Ahern union perf_event *event, 266249394a2aSDavid Ahern struct perf_sample *sample, 266349394a2aSDavid Ahern struct machine *machine __maybe_unused) 266449394a2aSDavid Ahern { 266549394a2aSDavid Ahern char tstr[64]; 266649394a2aSDavid Ahern 266749394a2aSDavid Ahern timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); 266849394a2aSDavid Ahern printf("%15s ", tstr); 26695290ed69SJiri Olsa printf("lost %" PRI_lu64 " events on cpu %d\n", event->lost.lost, sample->cpu); 267049394a2aSDavid Ahern 267149394a2aSDavid Ahern return 0; 267249394a2aSDavid Ahern } 267349394a2aSDavid Ahern 267449394a2aSDavid Ahern 267552df138cSDavid Ahern static void print_thread_runtime(struct thread *t, 267652df138cSDavid Ahern struct thread_runtime *r) 267752df138cSDavid Ahern { 267852df138cSDavid Ahern double mean = avg_stats(&r->run_stats); 267952df138cSDavid Ahern float stddev; 268052df138cSDavid Ahern 268152df138cSDavid Ahern printf("%*s %5d %9" PRIu64 " ", 268252df138cSDavid Ahern comm_width, timehist_get_commstr(t), t->ppid, 268352df138cSDavid Ahern (u64) r->run_stats.n); 268452df138cSDavid Ahern 268552df138cSDavid Ahern print_sched_time(r->total_run_time, 8); 268652df138cSDavid Ahern stddev = rel_stddev_stats(stddev_stats(&r->run_stats), mean); 268752df138cSDavid Ahern print_sched_time(r->run_stats.min, 6); 268852df138cSDavid Ahern printf(" "); 268952df138cSDavid Ahern print_sched_time((u64) mean, 6); 269052df138cSDavid Ahern printf(" "); 269152df138cSDavid Ahern print_sched_time(r->run_stats.max, 6); 269252df138cSDavid Ahern printf(" "); 269352df138cSDavid Ahern printf("%5.2f", stddev); 2694350f54faSDavid Ahern printf(" %5" PRIu64, r->migrations); 269552df138cSDavid Ahern printf("\n"); 269652df138cSDavid Ahern } 269752df138cSDavid Ahern 2698587782c5SNamhyung Kim static void print_thread_waittime(struct thread *t, 2699587782c5SNamhyung Kim struct thread_runtime *r) 2700587782c5SNamhyung Kim { 2701587782c5SNamhyung Kim printf("%*s %5d %9" PRIu64 " ", 2702587782c5SNamhyung Kim comm_width, timehist_get_commstr(t), t->ppid, 2703587782c5SNamhyung Kim (u64) r->run_stats.n); 2704587782c5SNamhyung Kim 2705587782c5SNamhyung Kim print_sched_time(r->total_run_time, 8); 2706587782c5SNamhyung Kim print_sched_time(r->total_sleep_time, 6); 2707587782c5SNamhyung Kim printf(" "); 2708587782c5SNamhyung Kim print_sched_time(r->total_iowait_time, 6); 2709587782c5SNamhyung Kim printf(" "); 2710587782c5SNamhyung Kim print_sched_time(r->total_preempt_time, 6); 2711587782c5SNamhyung Kim printf(" "); 2712587782c5SNamhyung Kim print_sched_time(r->total_delay_time, 6); 2713587782c5SNamhyung Kim printf("\n"); 2714587782c5SNamhyung Kim } 2715587782c5SNamhyung Kim 271652df138cSDavid Ahern struct total_run_stats { 2717587782c5SNamhyung Kim struct perf_sched *sched; 271852df138cSDavid Ahern u64 sched_count; 271952df138cSDavid Ahern u64 task_count; 272052df138cSDavid Ahern u64 total_run_time; 272152df138cSDavid Ahern }; 272252df138cSDavid Ahern 272352df138cSDavid Ahern static int __show_thread_runtime(struct thread *t, void *priv) 272452df138cSDavid Ahern { 272552df138cSDavid Ahern struct total_run_stats *stats = priv; 272652df138cSDavid Ahern struct thread_runtime *r; 272752df138cSDavid Ahern 272852df138cSDavid Ahern if (thread__is_filtered(t)) 272952df138cSDavid Ahern return 0; 273052df138cSDavid Ahern 273152df138cSDavid Ahern r = thread__priv(t); 273252df138cSDavid Ahern if (r && r->run_stats.n) { 273352df138cSDavid Ahern stats->task_count++; 273452df138cSDavid Ahern stats->sched_count += r->run_stats.n; 273552df138cSDavid Ahern stats->total_run_time += r->total_run_time; 2736587782c5SNamhyung Kim 2737587782c5SNamhyung Kim if (stats->sched->show_state) 2738587782c5SNamhyung Kim print_thread_waittime(t, r); 2739587782c5SNamhyung Kim else 274052df138cSDavid Ahern print_thread_runtime(t, r); 274152df138cSDavid Ahern } 274252df138cSDavid Ahern 274352df138cSDavid Ahern return 0; 274452df138cSDavid Ahern } 274552df138cSDavid Ahern 274652df138cSDavid Ahern static int show_thread_runtime(struct thread *t, void *priv) 274752df138cSDavid Ahern { 274852df138cSDavid Ahern if (t->dead) 274952df138cSDavid Ahern return 0; 275052df138cSDavid Ahern 275152df138cSDavid Ahern return __show_thread_runtime(t, priv); 275252df138cSDavid Ahern } 275352df138cSDavid Ahern 275452df138cSDavid Ahern static int show_deadthread_runtime(struct thread *t, void *priv) 275552df138cSDavid Ahern { 275652df138cSDavid Ahern if (!t->dead) 275752df138cSDavid Ahern return 0; 275852df138cSDavid Ahern 275952df138cSDavid Ahern return __show_thread_runtime(t, priv); 276052df138cSDavid Ahern } 276152df138cSDavid Ahern 2762ba957ebbSNamhyung Kim static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node) 2763ba957ebbSNamhyung Kim { 2764ba957ebbSNamhyung Kim const char *sep = " <- "; 2765ba957ebbSNamhyung Kim struct callchain_list *chain; 2766ba957ebbSNamhyung Kim size_t ret = 0; 2767ba957ebbSNamhyung Kim char bf[1024]; 2768ba957ebbSNamhyung Kim bool first; 2769ba957ebbSNamhyung Kim 2770ba957ebbSNamhyung Kim if (node == NULL) 2771ba957ebbSNamhyung Kim return 0; 2772ba957ebbSNamhyung Kim 2773ba957ebbSNamhyung Kim ret = callchain__fprintf_folded(fp, node->parent); 2774ba957ebbSNamhyung Kim first = (ret == 0); 2775ba957ebbSNamhyung Kim 2776ba957ebbSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 2777ba957ebbSNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 2778ba957ebbSNamhyung Kim continue; 2779ba957ebbSNamhyung Kim if (chain->ms.sym && chain->ms.sym->ignore) 2780ba957ebbSNamhyung Kim continue; 2781ba957ebbSNamhyung Kim ret += fprintf(fp, "%s%s", first ? "" : sep, 2782ba957ebbSNamhyung Kim callchain_list__sym_name(chain, bf, sizeof(bf), 2783ba957ebbSNamhyung Kim false)); 2784ba957ebbSNamhyung Kim first = false; 2785ba957ebbSNamhyung Kim } 2786ba957ebbSNamhyung Kim 2787ba957ebbSNamhyung Kim return ret; 2788ba957ebbSNamhyung Kim } 2789ba957ebbSNamhyung Kim 2790cb4c13a5SDavidlohr Bueso static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root) 2791ba957ebbSNamhyung Kim { 2792ba957ebbSNamhyung Kim size_t ret = 0; 2793ba957ebbSNamhyung Kim FILE *fp = stdout; 2794ba957ebbSNamhyung Kim struct callchain_node *chain; 2795cb4c13a5SDavidlohr Bueso struct rb_node *rb_node = rb_first_cached(root); 2796ba957ebbSNamhyung Kim 2797ba957ebbSNamhyung Kim printf(" %16s %8s %s\n", "Idle time (msec)", "Count", "Callchains"); 2798ba957ebbSNamhyung Kim printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line, 2799ba957ebbSNamhyung Kim graph_dotted_line); 2800ba957ebbSNamhyung Kim 2801ba957ebbSNamhyung Kim while (rb_node) { 2802ba957ebbSNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 2803ba957ebbSNamhyung Kim rb_node = rb_next(rb_node); 2804ba957ebbSNamhyung Kim 2805ba957ebbSNamhyung Kim ret += fprintf(fp, " "); 2806ba957ebbSNamhyung Kim print_sched_time(chain->hit, 12); 2807ba957ebbSNamhyung Kim ret += 16; /* print_sched_time returns 2nd arg + 4 */ 2808ba957ebbSNamhyung Kim ret += fprintf(fp, " %8d ", chain->count); 2809ba957ebbSNamhyung Kim ret += callchain__fprintf_folded(fp, chain); 2810ba957ebbSNamhyung Kim ret += fprintf(fp, "\n"); 2811ba957ebbSNamhyung Kim } 2812ba957ebbSNamhyung Kim 2813ba957ebbSNamhyung Kim return ret; 2814ba957ebbSNamhyung Kim } 2815ba957ebbSNamhyung Kim 281652df138cSDavid Ahern static void timehist_print_summary(struct perf_sched *sched, 281752df138cSDavid Ahern struct perf_session *session) 281852df138cSDavid Ahern { 281952df138cSDavid Ahern struct machine *m = &session->machines.host; 282052df138cSDavid Ahern struct total_run_stats totals; 282152df138cSDavid Ahern u64 task_count; 282252df138cSDavid Ahern struct thread *t; 282352df138cSDavid Ahern struct thread_runtime *r; 282452df138cSDavid Ahern int i; 28259396c9cbSNamhyung Kim u64 hist_time = sched->hist_time.end - sched->hist_time.start; 282652df138cSDavid Ahern 282752df138cSDavid Ahern memset(&totals, 0, sizeof(totals)); 2828587782c5SNamhyung Kim totals.sched = sched; 282952df138cSDavid Ahern 283007235f84SNamhyung Kim if (sched->idle_hist) { 283107235f84SNamhyung Kim printf("\nIdle-time summary\n"); 283207235f84SNamhyung Kim printf("%*s parent sched-out ", comm_width, "comm"); 283307235f84SNamhyung Kim printf(" idle-time min-idle avg-idle max-idle stddev migrations\n"); 2834587782c5SNamhyung Kim } else if (sched->show_state) { 2835587782c5SNamhyung Kim printf("\nWait-time summary\n"); 2836587782c5SNamhyung Kim printf("%*s parent sched-in ", comm_width, "comm"); 2837587782c5SNamhyung Kim printf(" run-time sleep iowait preempt delay\n"); 283807235f84SNamhyung Kim } else { 283952df138cSDavid Ahern printf("\nRuntime summary\n"); 284052df138cSDavid Ahern printf("%*s parent sched-in ", comm_width, "comm"); 2841350f54faSDavid Ahern printf(" run-time min-run avg-run max-run stddev migrations\n"); 284207235f84SNamhyung Kim } 284352df138cSDavid Ahern printf("%*s (count) ", comm_width, ""); 2844587782c5SNamhyung Kim printf(" (msec) (msec) (msec) (msec) %s\n", 2845587782c5SNamhyung Kim sched->show_state ? "(msec)" : "%"); 2846350f54faSDavid Ahern printf("%.117s\n", graph_dotted_line); 284752df138cSDavid Ahern 284852df138cSDavid Ahern machine__for_each_thread(m, show_thread_runtime, &totals); 284952df138cSDavid Ahern task_count = totals.task_count; 285052df138cSDavid Ahern if (!task_count) 285152df138cSDavid Ahern printf("<no still running tasks>\n"); 285252df138cSDavid Ahern 285352df138cSDavid Ahern printf("\nTerminated tasks:\n"); 285452df138cSDavid Ahern machine__for_each_thread(m, show_deadthread_runtime, &totals); 285552df138cSDavid Ahern if (task_count == totals.task_count) 285652df138cSDavid Ahern printf("<no terminated tasks>\n"); 285752df138cSDavid Ahern 285852df138cSDavid Ahern /* CPU idle stats not tracked when samples were skipped */ 285907235f84SNamhyung Kim if (sched->skipped_samples && !sched->idle_hist) 286052df138cSDavid Ahern return; 286152df138cSDavid Ahern 286252df138cSDavid Ahern printf("\nIdle stats:\n"); 2863b336352bSNamhyung Kim for (i = 0; i < idle_max_cpu; ++i) { 2864a74eaf16SDavid Ahern if (cpu_list && !test_bit(i, cpu_bitmap)) 2865a74eaf16SDavid Ahern continue; 2866a74eaf16SDavid Ahern 286752df138cSDavid Ahern t = idle_threads[i]; 286852df138cSDavid Ahern if (!t) 286952df138cSDavid Ahern continue; 287052df138cSDavid Ahern 287152df138cSDavid Ahern r = thread__priv(t); 287252df138cSDavid Ahern if (r && r->run_stats.n) { 287352df138cSDavid Ahern totals.sched_count += r->run_stats.n; 287452df138cSDavid Ahern printf(" CPU %2d idle for ", i); 287552df138cSDavid Ahern print_sched_time(r->total_run_time, 6); 28769396c9cbSNamhyung Kim printf(" msec (%6.2f%%)\n", 100.0 * r->total_run_time / hist_time); 287752df138cSDavid Ahern } else 287852df138cSDavid Ahern printf(" CPU %2d idle entire time window\n", i); 287952df138cSDavid Ahern } 288052df138cSDavid Ahern 28814c50563dSArnaldo Carvalho de Melo if (sched->idle_hist && sched->show_callchain) { 2882ba957ebbSNamhyung Kim callchain_param.mode = CHAIN_FOLDED; 2883ba957ebbSNamhyung Kim callchain_param.value = CCVAL_PERIOD; 2884ba957ebbSNamhyung Kim 2885ba957ebbSNamhyung Kim callchain_register_param(&callchain_param); 2886ba957ebbSNamhyung Kim 2887ba957ebbSNamhyung Kim printf("\nIdle stats by callchain:\n"); 2888ba957ebbSNamhyung Kim for (i = 0; i < idle_max_cpu; ++i) { 2889ba957ebbSNamhyung Kim struct idle_thread_runtime *itr; 2890ba957ebbSNamhyung Kim 2891ba957ebbSNamhyung Kim t = idle_threads[i]; 2892ba957ebbSNamhyung Kim if (!t) 2893ba957ebbSNamhyung Kim continue; 2894ba957ebbSNamhyung Kim 2895ba957ebbSNamhyung Kim itr = thread__priv(t); 2896ba957ebbSNamhyung Kim if (itr == NULL) 2897ba957ebbSNamhyung Kim continue; 2898ba957ebbSNamhyung Kim 2899cb4c13a5SDavidlohr Bueso callchain_param.sort(&itr->sorted_root.rb_root, &itr->callchain, 2900ba957ebbSNamhyung Kim 0, &callchain_param); 2901ba957ebbSNamhyung Kim 2902ba957ebbSNamhyung Kim printf(" CPU %2d:", i); 2903ba957ebbSNamhyung Kim print_sched_time(itr->tr.total_run_time, 6); 2904ba957ebbSNamhyung Kim printf(" msec\n"); 2905ba957ebbSNamhyung Kim timehist_print_idlehist_callchain(&itr->sorted_root); 2906ba957ebbSNamhyung Kim printf("\n"); 2907ba957ebbSNamhyung Kim } 2908ba957ebbSNamhyung Kim } 2909ba957ebbSNamhyung Kim 291052df138cSDavid Ahern printf("\n" 291152df138cSDavid Ahern " Total number of unique tasks: %" PRIu64 "\n" 29129396c9cbSNamhyung Kim "Total number of context switches: %" PRIu64 "\n", 291352df138cSDavid Ahern totals.task_count, totals.sched_count); 291452df138cSDavid Ahern 29159396c9cbSNamhyung Kim printf(" Total run time (msec): "); 291652df138cSDavid Ahern print_sched_time(totals.total_run_time, 2); 291752df138cSDavid Ahern printf("\n"); 29189396c9cbSNamhyung Kim 29199396c9cbSNamhyung Kim printf(" Total scheduling time (msec): "); 29209396c9cbSNamhyung Kim print_sched_time(hist_time, 2); 29219396c9cbSNamhyung Kim printf(" (x %d)\n", sched->max_cpu); 292252df138cSDavid Ahern } 292352df138cSDavid Ahern 292449394a2aSDavid Ahern typedef int (*sched_handler)(struct perf_tool *tool, 292549394a2aSDavid Ahern union perf_event *event, 292632dcd021SJiri Olsa struct evsel *evsel, 292749394a2aSDavid Ahern struct perf_sample *sample, 292849394a2aSDavid Ahern struct machine *machine); 292949394a2aSDavid Ahern 293049394a2aSDavid Ahern static int perf_timehist__process_sample(struct perf_tool *tool, 293149394a2aSDavid Ahern union perf_event *event, 293249394a2aSDavid Ahern struct perf_sample *sample, 293332dcd021SJiri Olsa struct evsel *evsel, 293449394a2aSDavid Ahern struct machine *machine) 293549394a2aSDavid Ahern { 293649394a2aSDavid Ahern struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 293749394a2aSDavid Ahern int err = 0; 293849394a2aSDavid Ahern int this_cpu = sample->cpu; 293949394a2aSDavid Ahern 294049394a2aSDavid Ahern if (this_cpu > sched->max_cpu) 294149394a2aSDavid Ahern sched->max_cpu = this_cpu; 294249394a2aSDavid Ahern 294349394a2aSDavid Ahern if (evsel->handler != NULL) { 294449394a2aSDavid Ahern sched_handler f = evsel->handler; 294549394a2aSDavid Ahern 294649394a2aSDavid Ahern err = f(tool, event, evsel, sample, machine); 294749394a2aSDavid Ahern } 294849394a2aSDavid Ahern 294949394a2aSDavid Ahern return err; 295049394a2aSDavid Ahern } 295149394a2aSDavid Ahern 29526c973c90SDavid Ahern static int timehist_check_attr(struct perf_sched *sched, 295363503dbaSJiri Olsa struct evlist *evlist) 29546c973c90SDavid Ahern { 295532dcd021SJiri Olsa struct evsel *evsel; 29566c973c90SDavid Ahern struct evsel_runtime *er; 29576c973c90SDavid Ahern 2958ce9036a6SJiri Olsa list_for_each_entry(evsel, &evlist->core.entries, core.node) { 29593b7313f2SArnaldo Carvalho de Melo er = evsel__get_runtime(evsel); 29606c973c90SDavid Ahern if (er == NULL) { 29616c973c90SDavid Ahern pr_err("Failed to allocate memory for evsel runtime data\n"); 29626c973c90SDavid Ahern return -1; 29636c973c90SDavid Ahern } 29646c973c90SDavid Ahern 296527de9b2bSArnaldo Carvalho de Melo if (sched->show_callchain && !evsel__has_callchain(evsel)) { 29666c973c90SDavid Ahern pr_info("Samples do not have callchains.\n"); 29676c973c90SDavid Ahern sched->show_callchain = 0; 29686c973c90SDavid Ahern symbol_conf.use_callchain = 0; 29696c973c90SDavid Ahern } 29706c973c90SDavid Ahern } 29716c973c90SDavid Ahern 29726c973c90SDavid Ahern return 0; 29736c973c90SDavid Ahern } 29746c973c90SDavid Ahern 297549394a2aSDavid Ahern static int perf_sched__timehist(struct perf_sched *sched) 297649394a2aSDavid Ahern { 2977d566a9c2SDavid Ahern struct evsel_str_handler handlers[] = { 297849394a2aSDavid Ahern { "sched:sched_switch", timehist_sched_switch_event, }, 297949394a2aSDavid Ahern { "sched:sched_wakeup", timehist_sched_wakeup_event, }, 2980d566a9c2SDavid Ahern { "sched:sched_waking", timehist_sched_wakeup_event, }, 298149394a2aSDavid Ahern { "sched:sched_wakeup_new", timehist_sched_wakeup_event, }, 298249394a2aSDavid Ahern }; 298332dcd021SJiri Olsa const struct evsel_str_handler migrate_handlers[] = { 2984350f54faSDavid Ahern { "sched:sched_migrate_task", timehist_migrate_task_event, }, 2985350f54faSDavid Ahern }; 29868ceb41d7SJiri Olsa struct perf_data data = { 298749394a2aSDavid Ahern .path = input_name, 298849394a2aSDavid Ahern .mode = PERF_DATA_MODE_READ, 29896fa94258SNamhyung Kim .force = sched->force, 299049394a2aSDavid Ahern }; 299149394a2aSDavid Ahern 299249394a2aSDavid Ahern struct perf_session *session; 299363503dbaSJiri Olsa struct evlist *evlist; 299449394a2aSDavid Ahern int err = -1; 299549394a2aSDavid Ahern 299649394a2aSDavid Ahern /* 299749394a2aSDavid Ahern * event handlers for timehist option 299849394a2aSDavid Ahern */ 299949394a2aSDavid Ahern sched->tool.sample = perf_timehist__process_sample; 300049394a2aSDavid Ahern sched->tool.mmap = perf_event__process_mmap; 300149394a2aSDavid Ahern sched->tool.comm = perf_event__process_comm; 300249394a2aSDavid Ahern sched->tool.exit = perf_event__process_exit; 300349394a2aSDavid Ahern sched->tool.fork = perf_event__process_fork; 300449394a2aSDavid Ahern sched->tool.lost = process_lost; 300549394a2aSDavid Ahern sched->tool.attr = perf_event__process_attr; 300649394a2aSDavid Ahern sched->tool.tracing_data = perf_event__process_tracing_data; 300749394a2aSDavid Ahern sched->tool.build_id = perf_event__process_build_id; 300849394a2aSDavid Ahern 300949394a2aSDavid Ahern sched->tool.ordered_events = true; 301049394a2aSDavid Ahern sched->tool.ordering_requires_timestamps = true; 301149394a2aSDavid Ahern 30126c973c90SDavid Ahern symbol_conf.use_callchain = sched->show_callchain; 30136c973c90SDavid Ahern 30142681bd85SNamhyung Kim session = perf_session__new(&data, &sched->tool); 30156ef81c55SMamatha Inamdar if (IS_ERR(session)) 30166ef81c55SMamatha Inamdar return PTR_ERR(session); 301749394a2aSDavid Ahern 3018c30d630dSDavid Ahern if (cpu_list) { 3019c30d630dSDavid Ahern err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); 3020c30d630dSDavid Ahern if (err < 0) 3021c30d630dSDavid Ahern goto out; 3022c30d630dSDavid Ahern } 3023c30d630dSDavid Ahern 302452df138cSDavid Ahern evlist = session->evlist; 302552df138cSDavid Ahern 302649394a2aSDavid Ahern symbol__init(&session->header.env); 302749394a2aSDavid Ahern 3028853b7407SDavid Ahern if (perf_time__parse_str(&sched->ptime, sched->time_str) != 0) { 3029853b7407SDavid Ahern pr_err("Invalid time string\n"); 3030853b7407SDavid Ahern return -EINVAL; 3031853b7407SDavid Ahern } 3032853b7407SDavid Ahern 30336c973c90SDavid Ahern if (timehist_check_attr(sched, evlist) != 0) 30346c973c90SDavid Ahern goto out; 30356c973c90SDavid Ahern 303649394a2aSDavid Ahern setup_pager(); 303749394a2aSDavid Ahern 3038d566a9c2SDavid Ahern /* prefer sched_waking if it is captured */ 3039b02736f7SArnaldo Carvalho de Melo if (evlist__find_tracepoint_by_name(session->evlist, "sched:sched_waking")) 3040d566a9c2SDavid Ahern handlers[1].handler = timehist_sched_wakeup_ignore; 3041d566a9c2SDavid Ahern 304249394a2aSDavid Ahern /* setup per-evsel handlers */ 304349394a2aSDavid Ahern if (perf_session__set_tracepoints_handlers(session, handlers)) 304449394a2aSDavid Ahern goto out; 304549394a2aSDavid Ahern 3046f45bf8d3SDavid Ahern /* sched_switch event at a minimum needs to exist */ 3047b02736f7SArnaldo Carvalho de Melo if (!evlist__find_tracepoint_by_name(session->evlist, "sched:sched_switch")) { 3048f45bf8d3SDavid Ahern pr_err("No sched_switch events found. Have you run 'perf sched record'?\n"); 304949394a2aSDavid Ahern goto out; 3050f45bf8d3SDavid Ahern } 305149394a2aSDavid Ahern 3052350f54faSDavid Ahern if (sched->show_migrations && 3053350f54faSDavid Ahern perf_session__set_tracepoints_handlers(session, migrate_handlers)) 3054350f54faSDavid Ahern goto out; 3055350f54faSDavid Ahern 305649394a2aSDavid Ahern /* pre-allocate struct for per-CPU idle stats */ 305749394a2aSDavid Ahern sched->max_cpu = session->header.env.nr_cpus_online; 305849394a2aSDavid Ahern if (sched->max_cpu == 0) 305949394a2aSDavid Ahern sched->max_cpu = 4; 306049394a2aSDavid Ahern if (init_idle_threads(sched->max_cpu)) 306149394a2aSDavid Ahern goto out; 306249394a2aSDavid Ahern 306352df138cSDavid Ahern /* summary_only implies summary option, but don't overwrite summary if set */ 306452df138cSDavid Ahern if (sched->summary_only) 306552df138cSDavid Ahern sched->summary = sched->summary_only; 306652df138cSDavid Ahern 306752df138cSDavid Ahern if (!sched->summary_only) 3068a407b067SDavid Ahern timehist_header(sched); 306949394a2aSDavid Ahern 307049394a2aSDavid Ahern err = perf_session__process_events(session); 307149394a2aSDavid Ahern if (err) { 307249394a2aSDavid Ahern pr_err("Failed to process events, error %d", err); 307349394a2aSDavid Ahern goto out; 307449394a2aSDavid Ahern } 307549394a2aSDavid Ahern 307652df138cSDavid Ahern sched->nr_events = evlist->stats.nr_events[0]; 307752df138cSDavid Ahern sched->nr_lost_events = evlist->stats.total_lost; 307852df138cSDavid Ahern sched->nr_lost_chunks = evlist->stats.nr_events[PERF_RECORD_LOST]; 307952df138cSDavid Ahern 308052df138cSDavid Ahern if (sched->summary) 308152df138cSDavid Ahern timehist_print_summary(sched, session); 308252df138cSDavid Ahern 308349394a2aSDavid Ahern out: 308449394a2aSDavid Ahern free_idle_threads(); 308549394a2aSDavid Ahern perf_session__delete(session); 308649394a2aSDavid Ahern 308749394a2aSDavid Ahern return err; 308849394a2aSDavid Ahern } 308949394a2aSDavid Ahern 309049394a2aSDavid Ahern 30910e9b07e5SArnaldo Carvalho de Melo static void print_bad_events(struct perf_sched *sched) 30920ec04e16SIngo Molnar { 30930e9b07e5SArnaldo Carvalho de Melo if (sched->nr_unordered_timestamps && sched->nr_timestamps) { 30940ec04e16SIngo Molnar printf(" INFO: %.3f%% unordered timestamps (%ld out of %ld)\n", 30950e9b07e5SArnaldo Carvalho de Melo (double)sched->nr_unordered_timestamps/(double)sched->nr_timestamps*100.0, 30960e9b07e5SArnaldo Carvalho de Melo sched->nr_unordered_timestamps, sched->nr_timestamps); 30970ec04e16SIngo Molnar } 30980e9b07e5SArnaldo Carvalho de Melo if (sched->nr_lost_events && sched->nr_events) { 30990ec04e16SIngo Molnar printf(" INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n", 31000e9b07e5SArnaldo Carvalho de Melo (double)sched->nr_lost_events/(double)sched->nr_events * 100.0, 31010e9b07e5SArnaldo Carvalho de Melo sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks); 31020ec04e16SIngo Molnar } 31030e9b07e5SArnaldo Carvalho de Melo if (sched->nr_context_switch_bugs && sched->nr_timestamps) { 31040ec04e16SIngo Molnar printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)", 31050e9b07e5SArnaldo Carvalho de Melo (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0, 31060e9b07e5SArnaldo Carvalho de Melo sched->nr_context_switch_bugs, sched->nr_timestamps); 31070e9b07e5SArnaldo Carvalho de Melo if (sched->nr_lost_events) 31080ec04e16SIngo Molnar printf(" (due to lost events?)"); 31090ec04e16SIngo Molnar printf("\n"); 31100ec04e16SIngo Molnar } 31110ec04e16SIngo Molnar } 31120ec04e16SIngo Molnar 3113cb4c13a5SDavidlohr Bueso static void __merge_work_atoms(struct rb_root_cached *root, struct work_atoms *data) 31142f80dd44SJosef Bacik { 3115cb4c13a5SDavidlohr Bueso struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL; 31162f80dd44SJosef Bacik struct work_atoms *this; 31172f80dd44SJosef Bacik const char *comm = thread__comm_str(data->thread), *this_comm; 3118cb4c13a5SDavidlohr Bueso bool leftmost = true; 31192f80dd44SJosef Bacik 31202f80dd44SJosef Bacik while (*new) { 31212f80dd44SJosef Bacik int cmp; 31222f80dd44SJosef Bacik 31232f80dd44SJosef Bacik this = container_of(*new, struct work_atoms, node); 31242f80dd44SJosef Bacik parent = *new; 31252f80dd44SJosef Bacik 31262f80dd44SJosef Bacik this_comm = thread__comm_str(this->thread); 31272f80dd44SJosef Bacik cmp = strcmp(comm, this_comm); 31282f80dd44SJosef Bacik if (cmp > 0) { 31292f80dd44SJosef Bacik new = &((*new)->rb_left); 31302f80dd44SJosef Bacik } else if (cmp < 0) { 31312f80dd44SJosef Bacik new = &((*new)->rb_right); 3132cb4c13a5SDavidlohr Bueso leftmost = false; 31332f80dd44SJosef Bacik } else { 31342f80dd44SJosef Bacik this->num_merged++; 31352f80dd44SJosef Bacik this->total_runtime += data->total_runtime; 31362f80dd44SJosef Bacik this->nb_atoms += data->nb_atoms; 31372f80dd44SJosef Bacik this->total_lat += data->total_lat; 31382f80dd44SJosef Bacik list_splice(&data->work_list, &this->work_list); 31392f80dd44SJosef Bacik if (this->max_lat < data->max_lat) { 31402f80dd44SJosef Bacik this->max_lat = data->max_lat; 3141dc000c45SJoel Fernandes (Google) this->max_lat_start = data->max_lat_start; 3142dc000c45SJoel Fernandes (Google) this->max_lat_end = data->max_lat_end; 31432f80dd44SJosef Bacik } 31442f80dd44SJosef Bacik zfree(&data); 31452f80dd44SJosef Bacik return; 31462f80dd44SJosef Bacik } 31472f80dd44SJosef Bacik } 31482f80dd44SJosef Bacik 31492f80dd44SJosef Bacik data->num_merged++; 31502f80dd44SJosef Bacik rb_link_node(&data->node, parent, new); 3151cb4c13a5SDavidlohr Bueso rb_insert_color_cached(&data->node, root, leftmost); 31522f80dd44SJosef Bacik } 31532f80dd44SJosef Bacik 31542f80dd44SJosef Bacik static void perf_sched__merge_lat(struct perf_sched *sched) 31552f80dd44SJosef Bacik { 31562f80dd44SJosef Bacik struct work_atoms *data; 31572f80dd44SJosef Bacik struct rb_node *node; 31582f80dd44SJosef Bacik 31592f80dd44SJosef Bacik if (sched->skip_merge) 31602f80dd44SJosef Bacik return; 31612f80dd44SJosef Bacik 3162cb4c13a5SDavidlohr Bueso while ((node = rb_first_cached(&sched->atom_root))) { 3163cb4c13a5SDavidlohr Bueso rb_erase_cached(node, &sched->atom_root); 31642f80dd44SJosef Bacik data = rb_entry(node, struct work_atoms, node); 31652f80dd44SJosef Bacik __merge_work_atoms(&sched->merged_atom_root, data); 31662f80dd44SJosef Bacik } 31672f80dd44SJosef Bacik } 31682f80dd44SJosef Bacik 31690e9b07e5SArnaldo Carvalho de Melo static int perf_sched__lat(struct perf_sched *sched) 31700ec04e16SIngo Molnar { 31710ec04e16SIngo Molnar struct rb_node *next; 31720ec04e16SIngo Molnar 31730ec04e16SIngo Molnar setup_pager(); 3174ad9def7cSDavid Ahern 3175ae536acfSArnaldo Carvalho de Melo if (perf_sched__read_events(sched)) 3176a116e05dSArnaldo Carvalho de Melo return -1; 3177ad9def7cSDavid Ahern 31782f80dd44SJosef Bacik perf_sched__merge_lat(sched); 31790e9b07e5SArnaldo Carvalho de Melo perf_sched__sort_lat(sched); 31800ec04e16SIngo Molnar 3181dc000c45SJoel Fernandes (Google) printf("\n -------------------------------------------------------------------------------------------------------------------------------------------\n"); 3182dc000c45SJoel Fernandes (Google) printf(" Task | Runtime ms | Switches | Avg delay ms | Max delay ms | Max delay start | Max delay end |\n"); 3183dc000c45SJoel Fernandes (Google) printf(" -------------------------------------------------------------------------------------------------------------------------------------------\n"); 31840ec04e16SIngo Molnar 3185cb4c13a5SDavidlohr Bueso next = rb_first_cached(&sched->sorted_atom_root); 31860ec04e16SIngo Molnar 31870ec04e16SIngo Molnar while (next) { 31880ec04e16SIngo Molnar struct work_atoms *work_list; 31890ec04e16SIngo Molnar 31900ec04e16SIngo Molnar work_list = rb_entry(next, struct work_atoms, node); 31910e9b07e5SArnaldo Carvalho de Melo output_lat_thread(sched, work_list); 31920ec04e16SIngo Molnar next = rb_next(next); 3193ae536acfSArnaldo Carvalho de Melo thread__zput(work_list->thread); 31940ec04e16SIngo Molnar } 31950ec04e16SIngo Molnar 319680790e0bSRamkumar Ramachandra printf(" -----------------------------------------------------------------------------------------------------------------\n"); 31979486aa38SArnaldo Carvalho de Melo printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n", 31984fc76e49SArnaldo Carvalho de Melo (double)sched->all_runtime / NSEC_PER_MSEC, sched->all_count); 31990ec04e16SIngo Molnar 32000ec04e16SIngo Molnar printf(" ---------------------------------------------------\n"); 32010ec04e16SIngo Molnar 32020e9b07e5SArnaldo Carvalho de Melo print_bad_events(sched); 32030ec04e16SIngo Molnar printf("\n"); 32040ec04e16SIngo Molnar 3205a116e05dSArnaldo Carvalho de Melo return 0; 32060ec04e16SIngo Molnar } 32070ec04e16SIngo Molnar 320899623c62SJiri Olsa static int setup_map_cpus(struct perf_sched *sched) 32090ec04e16SIngo Molnar { 3210f854839bSJiri Olsa struct perf_cpu_map *map; 321173643bb6SJiri Olsa 32120e9b07e5SArnaldo Carvalho de Melo sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); 321340749d0fSIngo Molnar 321499623c62SJiri Olsa if (sched->map.comp) { 321599623c62SJiri Olsa sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int)); 3216cf294f24SJiri Olsa if (!sched->map.comp_cpus) 3217cf294f24SJiri Olsa return -1; 321899623c62SJiri Olsa } 321999623c62SJiri Olsa 322073643bb6SJiri Olsa if (!sched->map.cpus_str) 322173643bb6SJiri Olsa return 0; 322273643bb6SJiri Olsa 32239c3516d1SJiri Olsa map = perf_cpu_map__new(sched->map.cpus_str); 322473643bb6SJiri Olsa if (!map) { 322573643bb6SJiri Olsa pr_err("failed to get cpus map from %s\n", sched->map.cpus_str); 322673643bb6SJiri Olsa return -1; 322773643bb6SJiri Olsa } 322873643bb6SJiri Olsa 322973643bb6SJiri Olsa sched->map.cpus = map; 323099623c62SJiri Olsa return 0; 323199623c62SJiri Olsa } 323299623c62SJiri Olsa 3233a151a37aSJiri Olsa static int setup_color_pids(struct perf_sched *sched) 3234a151a37aSJiri Olsa { 32359749b90eSJiri Olsa struct perf_thread_map *map; 3236a151a37aSJiri Olsa 3237a151a37aSJiri Olsa if (!sched->map.color_pids_str) 3238a151a37aSJiri Olsa return 0; 3239a151a37aSJiri Olsa 3240a151a37aSJiri Olsa map = thread_map__new_by_tid_str(sched->map.color_pids_str); 3241a151a37aSJiri Olsa if (!map) { 3242a151a37aSJiri Olsa pr_err("failed to get thread map from %s\n", sched->map.color_pids_str); 3243a151a37aSJiri Olsa return -1; 3244a151a37aSJiri Olsa } 3245a151a37aSJiri Olsa 3246a151a37aSJiri Olsa sched->map.color_pids = map; 3247a151a37aSJiri Olsa return 0; 3248a151a37aSJiri Olsa } 3249a151a37aSJiri Olsa 3250cf294f24SJiri Olsa static int setup_color_cpus(struct perf_sched *sched) 3251cf294f24SJiri Olsa { 3252f854839bSJiri Olsa struct perf_cpu_map *map; 3253cf294f24SJiri Olsa 3254cf294f24SJiri Olsa if (!sched->map.color_cpus_str) 3255cf294f24SJiri Olsa return 0; 3256cf294f24SJiri Olsa 32579c3516d1SJiri Olsa map = perf_cpu_map__new(sched->map.color_cpus_str); 3258cf294f24SJiri Olsa if (!map) { 3259cf294f24SJiri Olsa pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str); 3260cf294f24SJiri Olsa return -1; 3261cf294f24SJiri Olsa } 3262cf294f24SJiri Olsa 3263cf294f24SJiri Olsa sched->map.color_cpus = map; 3264cf294f24SJiri Olsa return 0; 3265cf294f24SJiri Olsa } 3266cf294f24SJiri Olsa 326799623c62SJiri Olsa static int perf_sched__map(struct perf_sched *sched) 326899623c62SJiri Olsa { 326999623c62SJiri Olsa if (setup_map_cpus(sched)) 327099623c62SJiri Olsa return -1; 327199623c62SJiri Olsa 3272a151a37aSJiri Olsa if (setup_color_pids(sched)) 3273a151a37aSJiri Olsa return -1; 3274a151a37aSJiri Olsa 3275cf294f24SJiri Olsa if (setup_color_cpus(sched)) 3276cf294f24SJiri Olsa return -1; 3277cf294f24SJiri Olsa 32780ec04e16SIngo Molnar setup_pager(); 3279ae536acfSArnaldo Carvalho de Melo if (perf_sched__read_events(sched)) 3280a116e05dSArnaldo Carvalho de Melo return -1; 32810e9b07e5SArnaldo Carvalho de Melo print_bad_events(sched); 3282a116e05dSArnaldo Carvalho de Melo return 0; 32830ec04e16SIngo Molnar } 32840ec04e16SIngo Molnar 32850e9b07e5SArnaldo Carvalho de Melo static int perf_sched__replay(struct perf_sched *sched) 32860ec04e16SIngo Molnar { 32870ec04e16SIngo Molnar unsigned long i; 32880ec04e16SIngo Molnar 32890e9b07e5SArnaldo Carvalho de Melo calibrate_run_measurement_overhead(sched); 32900e9b07e5SArnaldo Carvalho de Melo calibrate_sleep_measurement_overhead(sched); 32910ec04e16SIngo Molnar 32920e9b07e5SArnaldo Carvalho de Melo test_calibrations(sched); 32930ec04e16SIngo Molnar 3294ae536acfSArnaldo Carvalho de Melo if (perf_sched__read_events(sched)) 3295a116e05dSArnaldo Carvalho de Melo return -1; 32960ec04e16SIngo Molnar 32970e9b07e5SArnaldo Carvalho de Melo printf("nr_run_events: %ld\n", sched->nr_run_events); 32980e9b07e5SArnaldo Carvalho de Melo printf("nr_sleep_events: %ld\n", sched->nr_sleep_events); 32990e9b07e5SArnaldo Carvalho de Melo printf("nr_wakeup_events: %ld\n", sched->nr_wakeup_events); 33000ec04e16SIngo Molnar 33010e9b07e5SArnaldo Carvalho de Melo if (sched->targetless_wakeups) 33020e9b07e5SArnaldo Carvalho de Melo printf("target-less wakeups: %ld\n", sched->targetless_wakeups); 33030e9b07e5SArnaldo Carvalho de Melo if (sched->multitarget_wakeups) 33040e9b07e5SArnaldo Carvalho de Melo printf("multi-target wakeups: %ld\n", sched->multitarget_wakeups); 33050e9b07e5SArnaldo Carvalho de Melo if (sched->nr_run_events_optimized) 33060ec04e16SIngo Molnar printf("run atoms optimized: %ld\n", 33070e9b07e5SArnaldo Carvalho de Melo sched->nr_run_events_optimized); 33080ec04e16SIngo Molnar 33090e9b07e5SArnaldo Carvalho de Melo print_task_traces(sched); 33100e9b07e5SArnaldo Carvalho de Melo add_cross_task_wakeups(sched); 33110ec04e16SIngo Molnar 33120e9b07e5SArnaldo Carvalho de Melo create_tasks(sched); 33130ec04e16SIngo Molnar printf("------------------------------------------------------------\n"); 33140e9b07e5SArnaldo Carvalho de Melo for (i = 0; i < sched->replay_repeat; i++) 33150e9b07e5SArnaldo Carvalho de Melo run_one_test(sched); 3316a116e05dSArnaldo Carvalho de Melo 3317a116e05dSArnaldo Carvalho de Melo return 0; 33180ec04e16SIngo Molnar } 33190ec04e16SIngo Molnar 33200e9b07e5SArnaldo Carvalho de Melo static void setup_sorting(struct perf_sched *sched, const struct option *options, 33210e9b07e5SArnaldo Carvalho de Melo const char * const usage_msg[]) 3322daa1d7a5SFrederic Weisbecker { 33230e9b07e5SArnaldo Carvalho de Melo char *tmp, *tok, *str = strdup(sched->sort_order); 3324daa1d7a5SFrederic Weisbecker 3325daa1d7a5SFrederic Weisbecker for (tok = strtok_r(str, ", ", &tmp); 3326daa1d7a5SFrederic Weisbecker tok; tok = strtok_r(NULL, ", ", &tmp)) { 33270e9b07e5SArnaldo Carvalho de Melo if (sort_dimension__add(tok, &sched->sort_list) < 0) { 3328c7118369SNamhyung Kim usage_with_options_msg(usage_msg, options, 3329c7118369SNamhyung Kim "Unknown --sort key: `%s'", tok); 3330daa1d7a5SFrederic Weisbecker } 3331daa1d7a5SFrederic Weisbecker } 3332daa1d7a5SFrederic Weisbecker 3333daa1d7a5SFrederic Weisbecker free(str); 3334daa1d7a5SFrederic Weisbecker 33350e9b07e5SArnaldo Carvalho de Melo sort_dimension__add("pid", &sched->cmp_pid); 3336daa1d7a5SFrederic Weisbecker } 3337daa1d7a5SFrederic Weisbecker 3338b0f00855SYang Jihong static bool schedstat_events_exposed(void) 3339b0f00855SYang Jihong { 3340b0f00855SYang Jihong /* 3341b0f00855SYang Jihong * Select "sched:sched_stat_wait" event to check 3342b0f00855SYang Jihong * whether schedstat tracepoints are exposed. 3343b0f00855SYang Jihong */ 3344b0f00855SYang Jihong return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ? 3345b0f00855SYang Jihong false : true; 3346b0f00855SYang Jihong } 3347b0f00855SYang Jihong 33480e9b07e5SArnaldo Carvalho de Melo static int __cmd_record(int argc, const char **argv) 33490e9b07e5SArnaldo Carvalho de Melo { 33500e9b07e5SArnaldo Carvalho de Melo unsigned int rec_argc, i, j; 33510e9b07e5SArnaldo Carvalho de Melo const char **rec_argv; 33520e9b07e5SArnaldo Carvalho de Melo const char * const record_args[] = { 33531fc35b29SIngo Molnar "record", 33541fc35b29SIngo Molnar "-a", 33551fc35b29SIngo Molnar "-R", 3356dc02bf71SIngo Molnar "-m", "1024", 33571fc35b29SIngo Molnar "-c", "1", 33589710118bSStephane Eranian "-e", "sched:sched_switch", 33599710118bSStephane Eranian "-e", "sched:sched_stat_runtime", 33609710118bSStephane Eranian "-e", "sched:sched_process_fork", 33617fff9597SDongsheng "-e", "sched:sched_wakeup_new", 33629710118bSStephane Eranian "-e", "sched:sched_migrate_task", 33631fc35b29SIngo Molnar }; 3364b0f00855SYang Jihong 3365b0f00855SYang Jihong /* 3366b0f00855SYang Jihong * The tracepoints trace_sched_stat_{wait, sleep, iowait} 3367b0f00855SYang Jihong * are not exposed to user if CONFIG_SCHEDSTATS is not set, 3368b0f00855SYang Jihong * to prevent "perf sched record" execution failure, determine 3369b0f00855SYang Jihong * whether to record schedstat events according to actual situation. 3370b0f00855SYang Jihong */ 3371b0f00855SYang Jihong const char * const schedstat_args[] = { 3372b0f00855SYang Jihong "-e", "sched:sched_stat_wait", 3373b0f00855SYang Jihong "-e", "sched:sched_stat_sleep", 3374b0f00855SYang Jihong "-e", "sched:sched_stat_iowait", 3375b0f00855SYang Jihong }; 3376b0f00855SYang Jihong unsigned int schedstat_argc = schedstat_events_exposed() ? 3377b0f00855SYang Jihong ARRAY_SIZE(schedstat_args) : 0; 3378b0f00855SYang Jihong 3379d566a9c2SDavid Ahern struct tep_event *waking_event; 33801fc35b29SIngo Molnar 3381d566a9c2SDavid Ahern /* 3382d566a9c2SDavid Ahern * +2 for either "-e", "sched:sched_wakeup" or 3383d566a9c2SDavid Ahern * "-e", "sched:sched_waking" 3384d566a9c2SDavid Ahern */ 3385b0f00855SYang Jihong rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1; 33861fc35b29SIngo Molnar rec_argv = calloc(rec_argc + 1, sizeof(char *)); 33871fc35b29SIngo Molnar 3388e462dc55SArnaldo Carvalho de Melo if (rec_argv == NULL) 3389ce47dc56SChris Samuel return -ENOMEM; 3390ce47dc56SChris Samuel 33911fc35b29SIngo Molnar for (i = 0; i < ARRAY_SIZE(record_args); i++) 33921fc35b29SIngo Molnar rec_argv[i] = strdup(record_args[i]); 33931fc35b29SIngo Molnar 3394d566a9c2SDavid Ahern rec_argv[i++] = "-e"; 3395d566a9c2SDavid Ahern waking_event = trace_event__tp_format("sched", "sched_waking"); 3396d566a9c2SDavid Ahern if (!IS_ERR(waking_event)) 3397d566a9c2SDavid Ahern rec_argv[i++] = strdup("sched:sched_waking"); 3398d566a9c2SDavid Ahern else 3399d566a9c2SDavid Ahern rec_argv[i++] = strdup("sched:sched_wakeup"); 3400d566a9c2SDavid Ahern 3401b0f00855SYang Jihong for (j = 0; j < schedstat_argc; j++) 3402b0f00855SYang Jihong rec_argv[i++] = strdup(schedstat_args[j]); 3403b0f00855SYang Jihong 34041fc35b29SIngo Molnar for (j = 1; j < (unsigned int)argc; j++, i++) 34051fc35b29SIngo Molnar rec_argv[i] = argv[j]; 34061fc35b29SIngo Molnar 34071fc35b29SIngo Molnar BUG_ON(i != rec_argc); 34081fc35b29SIngo Molnar 3409b0ad8ea6SArnaldo Carvalho de Melo return cmd_record(i, rec_argv); 34101fc35b29SIngo Molnar } 34111fc35b29SIngo Molnar 3412b0ad8ea6SArnaldo Carvalho de Melo int cmd_sched(int argc, const char **argv) 34138a39df8fSAdrian Hunter { 341449b8e2beSRasmus Villemoes static const char default_sort_order[] = "avg, max, switch, runtime"; 34158a39df8fSAdrian Hunter struct perf_sched sched = { 34160e9b07e5SArnaldo Carvalho de Melo .tool = { 34170e9b07e5SArnaldo Carvalho de Melo .sample = perf_sched__process_tracepoint_sample, 341899a3c3a9SChangbin Du .comm = perf_sched__process_comm, 3419f3b3614aSHari Bathini .namespaces = perf_event__process_namespaces, 34200e9b07e5SArnaldo Carvalho de Melo .lost = perf_event__process_lost, 3421cb627505SDavid Ahern .fork = perf_sched__process_fork_event, 34220a8cb85cSJiri Olsa .ordered_events = true, 34230e9b07e5SArnaldo Carvalho de Melo }, 34240e9b07e5SArnaldo Carvalho de Melo .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), 34250e9b07e5SArnaldo Carvalho de Melo .sort_list = LIST_HEAD_INIT(sched.sort_list), 34260e9b07e5SArnaldo Carvalho de Melo .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, 34270e9b07e5SArnaldo Carvalho de Melo .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, 34280e9b07e5SArnaldo Carvalho de Melo .sort_order = default_sort_order, 34290e9b07e5SArnaldo Carvalho de Melo .replay_repeat = 10, 34300e9b07e5SArnaldo Carvalho de Melo .profile_cpu = -1, 34310e9b07e5SArnaldo Carvalho de Melo .next_shortname1 = 'A', 34320e9b07e5SArnaldo Carvalho de Melo .next_shortname2 = '0', 34332f80dd44SJosef Bacik .skip_merge = 0, 34346c973c90SDavid Ahern .show_callchain = 1, 34356c973c90SDavid Ahern .max_stack = 5, 34360e9b07e5SArnaldo Carvalho de Melo }; 343777f02f44SNamhyung Kim const struct option sched_options[] = { 343877f02f44SNamhyung Kim OPT_STRING('i', "input", &input_name, "file", 343977f02f44SNamhyung Kim "input file name"), 344077f02f44SNamhyung Kim OPT_INCR('v', "verbose", &verbose, 344177f02f44SNamhyung Kim "be more verbose (show symbol address, etc)"), 344277f02f44SNamhyung Kim OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 344377f02f44SNamhyung Kim "dump raw trace in ASCII"), 34446fa94258SNamhyung Kim OPT_BOOLEAN('f', "force", &sched.force, "don't complain, do it"), 344577f02f44SNamhyung Kim OPT_END() 344677f02f44SNamhyung Kim }; 34470e9b07e5SArnaldo Carvalho de Melo const struct option latency_options[] = { 34480e9b07e5SArnaldo Carvalho de Melo OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", 34490e9b07e5SArnaldo Carvalho de Melo "sort by key(s): runtime, switch, avg, max"), 34500e9b07e5SArnaldo Carvalho de Melo OPT_INTEGER('C', "CPU", &sched.profile_cpu, 34510e9b07e5SArnaldo Carvalho de Melo "CPU to profile on"), 34522f80dd44SJosef Bacik OPT_BOOLEAN('p', "pids", &sched.skip_merge, 34532f80dd44SJosef Bacik "latency stats per pid instead of per comm"), 345477f02f44SNamhyung Kim OPT_PARENT(sched_options) 34550e9b07e5SArnaldo Carvalho de Melo }; 34560e9b07e5SArnaldo Carvalho de Melo const struct option replay_options[] = { 34570e9b07e5SArnaldo Carvalho de Melo OPT_UINTEGER('r', "repeat", &sched.replay_repeat, 34580e9b07e5SArnaldo Carvalho de Melo "repeat the workload replay N times (-1: infinite)"), 345977f02f44SNamhyung Kim OPT_PARENT(sched_options) 34600e9b07e5SArnaldo Carvalho de Melo }; 346199623c62SJiri Olsa const struct option map_options[] = { 346299623c62SJiri Olsa OPT_BOOLEAN(0, "compact", &sched.map.comp, 346399623c62SJiri Olsa "map output in compact mode"), 3464a151a37aSJiri Olsa OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids", 3465a151a37aSJiri Olsa "highlight given pids in map"), 3466cf294f24SJiri Olsa OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus", 3467cf294f24SJiri Olsa "highlight given CPUs in map"), 346873643bb6SJiri Olsa OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus", 346973643bb6SJiri Olsa "display given CPUs in map"), 347077f02f44SNamhyung Kim OPT_PARENT(sched_options) 347199623c62SJiri Olsa }; 347249394a2aSDavid Ahern const struct option timehist_options[] = { 347349394a2aSDavid Ahern OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 347449394a2aSDavid Ahern "file", "vmlinux pathname"), 347549394a2aSDavid Ahern OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 347649394a2aSDavid Ahern "file", "kallsyms pathname"), 34776c973c90SDavid Ahern OPT_BOOLEAN('g', "call-graph", &sched.show_callchain, 34786c973c90SDavid Ahern "Display call chains if present (default on)"), 34796c973c90SDavid Ahern OPT_UINTEGER(0, "max-stack", &sched.max_stack, 34806c973c90SDavid Ahern "Maximum number of functions to display backtrace."), 348149394a2aSDavid Ahern OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 348249394a2aSDavid Ahern "Look for files with symbols relative to this directory"), 348352df138cSDavid Ahern OPT_BOOLEAN('s', "summary", &sched.summary_only, 348452df138cSDavid Ahern "Show only syscall summary with statistics"), 348552df138cSDavid Ahern OPT_BOOLEAN('S', "with-summary", &sched.summary, 348652df138cSDavid Ahern "Show all syscalls and summary with statistics"), 3487fc1469f1SDavid Ahern OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), 3488292c4a8fSBrendan Gregg OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"), 3489350f54faSDavid Ahern OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), 3490a407b067SDavid Ahern OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), 349107235f84SNamhyung Kim OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"), 3492853b7407SDavid Ahern OPT_STRING(0, "time", &sched.time_str, "str", 3493853b7407SDavid Ahern "Time span for analysis (start,stop)"), 3494414e050cSNamhyung Kim OPT_BOOLEAN(0, "state", &sched.show_state, "Show task state when sched-out"), 34950f59d7a3SDavid Ahern OPT_STRING('p', "pid", &symbol_conf.pid_list_str, "pid[,pid...]", 34960f59d7a3SDavid Ahern "analyze events only for given process id(s)"), 34970f59d7a3SDavid Ahern OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]", 34980f59d7a3SDavid Ahern "analyze events only for given thread id(s)"), 3499c30d630dSDavid Ahern OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 350049394a2aSDavid Ahern OPT_PARENT(sched_options) 350149394a2aSDavid Ahern }; 350249394a2aSDavid Ahern 35030e9b07e5SArnaldo Carvalho de Melo const char * const latency_usage[] = { 35040e9b07e5SArnaldo Carvalho de Melo "perf sched latency [<options>]", 35050e9b07e5SArnaldo Carvalho de Melo NULL 35060e9b07e5SArnaldo Carvalho de Melo }; 35070e9b07e5SArnaldo Carvalho de Melo const char * const replay_usage[] = { 35080e9b07e5SArnaldo Carvalho de Melo "perf sched replay [<options>]", 35090e9b07e5SArnaldo Carvalho de Melo NULL 35100e9b07e5SArnaldo Carvalho de Melo }; 351199623c62SJiri Olsa const char * const map_usage[] = { 351299623c62SJiri Olsa "perf sched map [<options>]", 351399623c62SJiri Olsa NULL 351499623c62SJiri Olsa }; 351549394a2aSDavid Ahern const char * const timehist_usage[] = { 351649394a2aSDavid Ahern "perf sched timehist [<options>]", 351749394a2aSDavid Ahern NULL 351849394a2aSDavid Ahern }; 3519a83edb2dSRamkumar Ramachandra const char *const sched_subcommands[] = { "record", "latency", "map", 352049394a2aSDavid Ahern "replay", "script", 352149394a2aSDavid Ahern "timehist", NULL }; 3522a83edb2dSRamkumar Ramachandra const char *sched_usage[] = { 3523a83edb2dSRamkumar Ramachandra NULL, 35240e9b07e5SArnaldo Carvalho de Melo NULL 35250e9b07e5SArnaldo Carvalho de Melo }; 35260e9b07e5SArnaldo Carvalho de Melo struct trace_sched_handler lat_ops = { 35270e9b07e5SArnaldo Carvalho de Melo .wakeup_event = latency_wakeup_event, 35280e9b07e5SArnaldo Carvalho de Melo .switch_event = latency_switch_event, 35290e9b07e5SArnaldo Carvalho de Melo .runtime_event = latency_runtime_event, 35300e9b07e5SArnaldo Carvalho de Melo .migrate_task_event = latency_migrate_task_event, 35310e9b07e5SArnaldo Carvalho de Melo }; 35320e9b07e5SArnaldo Carvalho de Melo struct trace_sched_handler map_ops = { 35330e9b07e5SArnaldo Carvalho de Melo .switch_event = map_switch_event, 35340e9b07e5SArnaldo Carvalho de Melo }; 35350e9b07e5SArnaldo Carvalho de Melo struct trace_sched_handler replay_ops = { 35360e9b07e5SArnaldo Carvalho de Melo .wakeup_event = replay_wakeup_event, 35370e9b07e5SArnaldo Carvalho de Melo .switch_event = replay_switch_event, 35380e9b07e5SArnaldo Carvalho de Melo .fork_event = replay_fork_event, 35390e9b07e5SArnaldo Carvalho de Melo }; 3540156a2b02SAdrian Hunter unsigned int i; 35417cc72553SJames Clark int ret; 3542156a2b02SAdrian Hunter 3543156a2b02SAdrian Hunter for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++) 3544156a2b02SAdrian Hunter sched.curr_pid[i] = -1; 35450e9b07e5SArnaldo Carvalho de Melo 3546a83edb2dSRamkumar Ramachandra argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands, 3547a83edb2dSRamkumar Ramachandra sched_usage, PARSE_OPT_STOP_AT_NON_OPTION); 3548f2858d8aSIngo Molnar if (!argc) 3549f2858d8aSIngo Molnar usage_with_options(sched_usage, sched_options); 3550f2858d8aSIngo Molnar 3551c0777c5aSXiao Guangrong /* 3552133dc4c3SIngo Molnar * Aliased to 'perf script' for now: 3553c0777c5aSXiao Guangrong */ 3554133dc4c3SIngo Molnar if (!strcmp(argv[0], "script")) 3555b0ad8ea6SArnaldo Carvalho de Melo return cmd_script(argc, argv); 3556c0777c5aSXiao Guangrong 35571fc35b29SIngo Molnar if (!strncmp(argv[0], "rec", 3)) { 35581fc35b29SIngo Molnar return __cmd_record(argc, argv); 35591fc35b29SIngo Molnar } else if (!strncmp(argv[0], "lat", 3)) { 35600e9b07e5SArnaldo Carvalho de Melo sched.tp_handler = &lat_ops; 3561f2858d8aSIngo Molnar if (argc > 1) { 3562f2858d8aSIngo Molnar argc = parse_options(argc, argv, latency_options, latency_usage, 0); 3563f2858d8aSIngo Molnar if (argc) 3564f2858d8aSIngo Molnar usage_with_options(latency_usage, latency_options); 3565f2858d8aSIngo Molnar } 35660e9b07e5SArnaldo Carvalho de Melo setup_sorting(&sched, latency_options, latency_usage); 35670e9b07e5SArnaldo Carvalho de Melo return perf_sched__lat(&sched); 35680ec04e16SIngo Molnar } else if (!strcmp(argv[0], "map")) { 356999623c62SJiri Olsa if (argc) { 3570a151a37aSJiri Olsa argc = parse_options(argc, argv, map_options, map_usage, 0); 357199623c62SJiri Olsa if (argc) 357299623c62SJiri Olsa usage_with_options(map_usage, map_options); 357399623c62SJiri Olsa } 35740e9b07e5SArnaldo Carvalho de Melo sched.tp_handler = &map_ops; 35750e9b07e5SArnaldo Carvalho de Melo setup_sorting(&sched, latency_options, latency_usage); 35760e9b07e5SArnaldo Carvalho de Melo return perf_sched__map(&sched); 3577f2858d8aSIngo Molnar } else if (!strncmp(argv[0], "rep", 3)) { 35780e9b07e5SArnaldo Carvalho de Melo sched.tp_handler = &replay_ops; 35790a02ad93SIngo Molnar if (argc) { 3580f2858d8aSIngo Molnar argc = parse_options(argc, argv, replay_options, replay_usage, 0); 3581f2858d8aSIngo Molnar if (argc) 3582f2858d8aSIngo Molnar usage_with_options(replay_usage, replay_options); 3583f2858d8aSIngo Molnar } 35840e9b07e5SArnaldo Carvalho de Melo return perf_sched__replay(&sched); 358549394a2aSDavid Ahern } else if (!strcmp(argv[0], "timehist")) { 358649394a2aSDavid Ahern if (argc) { 358749394a2aSDavid Ahern argc = parse_options(argc, argv, timehist_options, 358849394a2aSDavid Ahern timehist_usage, 0); 358949394a2aSDavid Ahern if (argc) 359049394a2aSDavid Ahern usage_with_options(timehist_usage, timehist_options); 359149394a2aSDavid Ahern } 3592292c4a8fSBrendan Gregg if ((sched.show_wakeups || sched.show_next) && 3593292c4a8fSBrendan Gregg sched.summary_only) { 3594292c4a8fSBrendan Gregg pr_err(" Error: -s and -[n|w] are mutually exclusive.\n"); 3595fc1469f1SDavid Ahern parse_options_usage(timehist_usage, timehist_options, "s", true); 3596292c4a8fSBrendan Gregg if (sched.show_wakeups) 3597fc1469f1SDavid Ahern parse_options_usage(NULL, timehist_options, "w", true); 3598292c4a8fSBrendan Gregg if (sched.show_next) 3599292c4a8fSBrendan Gregg parse_options_usage(NULL, timehist_options, "n", true); 3600fc1469f1SDavid Ahern return -EINVAL; 3601fc1469f1SDavid Ahern } 36027cc72553SJames Clark ret = symbol__validate_sym_arguments(); 36037cc72553SJames Clark if (ret) 36047cc72553SJames Clark return ret; 3605fc1469f1SDavid Ahern 360649394a2aSDavid Ahern return perf_sched__timehist(&sched); 3607f2858d8aSIngo Molnar } else { 3608f2858d8aSIngo Molnar usage_with_options(sched_usage, sched_options); 36090a02ad93SIngo Molnar } 36100a02ad93SIngo Molnar 3611ec156764SIngo Molnar return 0; 36120a02ad93SIngo Molnar } 3613