1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "builtin.h"
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "perf.h"
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/util.h"
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/evlist.h"
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/cache.h"
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/evsel.h"
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/symbol.h"
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/thread.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/header.h"
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/session.h"
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/tool.h"
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/parse-options.h"
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/trace-event.h"
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util/debug.h"
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/prctl.h>
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/resource.h>
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <semaphore.h>
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <pthread.h>
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <math.h>
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define PR_SET_NAME		15               /* Set process name */
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define MAX_CPUS		4096
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define COMM_LEN		20
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define SYM_LEN			129
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define MAX_PID			65536
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct sched_atom;
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct task_desc {
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long		nr;
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long		pid;
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char			comm[COMM_LEN];
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long		nr_events;
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long		curr_event;
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sched_atom	**atoms;
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_t		thread;
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sem_t			sleep_sem;
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sem_t			ready_for_work;
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sem_t			work_done_sem;
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			cpu_usage;
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengenum sched_event_type {
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	SCHED_EVENT_RUN,
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	SCHED_EVENT_SLEEP,
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	SCHED_EVENT_WAKEUP,
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	SCHED_EVENT_MIGRATION,
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct sched_atom {
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	enum sched_event_type	type;
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int			specific_wait;
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			timestamp;
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			duration;
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long		nr;
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sem_t			*wait_sem;
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc	*wakee;
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define TASK_STATE_TO_CHAR_STR "RSDTtZX"
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengenum thread_state {
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	THREAD_SLEEPING = 0,
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	THREAD_WAIT_CPU,
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	THREAD_SCHED_IN,
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	THREAD_IGNORE
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct work_atom {
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct list_head	list;
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	enum thread_state	state;
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			sched_out_time;
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			wake_up_time;
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			sched_in_time;
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			runtime;
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct work_atoms {
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct list_head	work_list;
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread		*thread;
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node		node;
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			max_lat;
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			max_lat_at;
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			total_lat;
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			nb_atoms;
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			total_runtime;
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengtypedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct perf_sched;
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct trace_sched_handler {
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int (*switch_event)(struct perf_sched *sched, struct perf_evsel *evsel,
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    struct perf_sample *sample, struct machine *machine);
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int (*runtime_event)(struct perf_sched *sched, struct perf_evsel *evsel,
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     struct perf_sample *sample, struct machine *machine);
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    struct perf_sample *sample, struct machine *machine);
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int (*fork_event)(struct perf_sched *sched, union perf_event *event,
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			  struct machine *machine);
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int (*migrate_task_event)(struct perf_sched *sched,
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct perf_evsel *evsel,
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct perf_sample *sample,
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct machine *machine);
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct perf_sched {
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_tool tool;
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char	 *sort_order;
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_tasks;
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *pid_to_task[MAX_PID];
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc **tasks;
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct trace_sched_handler *tp_handler;
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_t	 start_work_mutex;
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_t	 work_done_wait_mutex;
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		 profile_cpu;
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Track the current task - that way we can know whether there's any
134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * weird events, such as a task being switched away that is not current.
135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int		 max_cpu;
137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32		 curr_pid[MAX_CPUS];
138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread	 *curr_thread[MAX_CPUS];
139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char		 next_shortname1;
140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char		 next_shortname2;
141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned int	 replay_repeat;
142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_run_events;
143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_sleep_events;
144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_wakeup_events;
145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_sleep_corrections;
146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_run_events_optimized;
147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 targetless_wakeups;
148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 multitarget_wakeups;
149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_runs;
150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_timestamps;
151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_unordered_timestamps;
152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_state_machine_bugs;
153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_context_switch_bugs;
154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_events;
155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_lost_chunks;
156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long	 nr_lost_events;
157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 run_measurement_overhead;
158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 sleep_measurement_overhead;
159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 start_time;
160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 cpu_usage;
161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 runavg_cpu_usage;
162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 parent_cpu_usage;
163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 runavg_parent_cpu_usage;
164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 sum_runtime;
165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 sum_fluct;
166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 run_avg;
167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 all_runtime;
168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 all_count;
169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64		 cpu_last_switched[MAX_CPUS];
170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_root	 atom_root, sorted_atom_root;
171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct list_head sort_list, cmp_pid;
172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 get_nsecs(void)
175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1760da480317e158a520d3128d45ed070c048a07187Ben Cheng#ifndef __APPLE__
177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct timespec ts;
178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	clock_gettime(CLOCK_MONOTONIC, &ts);
180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
1820da480317e158a520d3128d45ed070c048a07187Ben Cheng#else
1830da480317e158a520d3128d45ed070c048a07187Ben Cheng	perror("get_nsecs not supported on MacOS");
1840da480317e158a520d3128d45ed070c048a07187Ben Cheng	return 0;
1850da480317e158a520d3128d45ed070c048a07187Ben Cheng#endif
186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void burn_nsecs(struct perf_sched *sched, u64 nsecs)
189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 T0 = get_nsecs(), T1;
191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	do {
193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		T1 = get_nsecs();
194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} while (T1 + sched->run_measurement_overhead < T0 + nsecs);
195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void sleep_nsecs(u64 nsecs)
198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct timespec ts;
200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ts.tv_nsec = nsecs % 999999999;
202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ts.tv_sec = nsecs / 999999999;
203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	nanosleep(&ts, NULL);
205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void calibrate_run_measurement_overhead(struct perf_sched *sched)
208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 T0, T1, delta, min_delta = 1000000000ULL;
210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < 10; i++) {
213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		T0 = get_nsecs();
214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		burn_nsecs(sched, 0);
215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		T1 = get_nsecs();
216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = T1-T0;
217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		min_delta = min(min_delta, delta);
218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->run_measurement_overhead = min_delta;
220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void calibrate_sleep_measurement_overhead(struct perf_sched *sched)
225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 T0, T1, delta, min_delta = 1000000000ULL;
227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < 10; i++) {
230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		T0 = get_nsecs();
231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sleep_nsecs(10000);
232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		T1 = get_nsecs();
233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = T1-T0;
234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		min_delta = min(min_delta, delta);
235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	min_delta -= 10000;
237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->sleep_measurement_overhead = min_delta;
238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct sched_atom *
243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengget_new_event(struct task_desc *task, u64 timestamp)
244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sched_atom *event = zalloc(sizeof(*event));
246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long idx = task->nr_events;
247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t size;
248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->timestamp = timestamp;
250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->nr = idx;
251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task->nr_events++;
253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size = sizeof(struct sched_atom *) * task->nr_events;
254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task->atoms = realloc(task->atoms, size);
255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(!task->atoms);
256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task->atoms[idx] = event;
258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return event;
260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct sched_atom *last_event(struct task_desc *task)
263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!task->nr_events)
265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return NULL;
266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return task->atoms[task->nr_events - 1];
268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void add_sched_event_run(struct perf_sched *sched, struct task_desc *task,
271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				u64 timestamp, u64 duration)
272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sched_atom *event, *curr_event = last_event(task);
274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * optimize an existing RUN event by merging this one
277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * to it:
278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_run_events_optimized++;
281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		curr_event->duration += duration;
282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event = get_new_event(task, timestamp);
286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->type = SCHED_EVENT_RUN;
288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->duration = duration;
289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_run_events++;
291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *task,
294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   u64 timestamp, struct task_desc *wakee)
295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sched_atom *event, *wakee_event;
297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event = get_new_event(task, timestamp);
299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->type = SCHED_EVENT_WAKEUP;
300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->wakee = wakee;
301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	wakee_event = last_event(wakee);
303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->targetless_wakeups++;
305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (wakee_event->wait_sem) {
308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->multitarget_wakeups++;
309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sem_init(wakee_event->wait_sem, 0, 0);
314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	wakee_event->specific_wait = 1;
315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->wait_sem = wakee_event->wait_sem;
316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_wakeup_events++;
318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task,
321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  u64 timestamp, u64 task_state __maybe_unused)
322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sched_atom *event = get_new_event(task, timestamp);
324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	event->type = SCHED_EVENT_SLEEP;
326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_sleep_events++;
328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct task_desc *register_pid(struct perf_sched *sched,
331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      unsigned long pid, const char *comm)
332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *task;
334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(pid >= MAX_PID);
336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task = sched->pid_to_task[pid];
338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (task)
340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return task;
341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task = zalloc(sizeof(*task));
343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task->pid = pid;
344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	task->nr = sched->nr_tasks;
345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	strcpy(task->comm, comm);
346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * every task starts in sleeping state - this gets ignored
348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * if there's no wakeup pointing to this sleep state:
349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_sched_event_sleep(sched, task, 0, 0);
351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->pid_to_task[pid] = task;
353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_tasks++;
354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_task *));
355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(!sched->tasks);
356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->tasks[task->nr] = task;
357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (verbose)
359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("registered task #%ld, PID %ld (%s)\n", sched->nr_tasks, pid, comm);
360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return task;
362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void print_task_traces(struct perf_sched *sched)
366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *task;
368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long i;
369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->nr_tasks; i++) {
371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task = sched->tasks[i];
372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			task->nr, task->comm, task->pid, task->nr_events);
374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void add_cross_task_wakeups(struct perf_sched *sched)
378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *task1, *task2;
380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long i, j;
381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->nr_tasks; i++) {
383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task1 = sched->tasks[i];
384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		j = i + 1;
385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (j == sched->nr_tasks)
386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			j = 0;
387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task2 = sched->tasks[j];
388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		add_sched_event_wakeup(sched, task1, 0, task2);
389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void perf_sched__process_event(struct perf_sched *sched,
393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct sched_atom *atom)
394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret = 0;
396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	switch (atom->type) {
398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case SCHED_EVENT_RUN:
399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			burn_nsecs(sched, atom->duration);
400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case SCHED_EVENT_SLEEP:
402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (atom->wait_sem)
403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ret = sem_wait(atom->wait_sem);
404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			BUG_ON(ret);
405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case SCHED_EVENT_WAKEUP:
407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (atom->wait_sem)
408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				ret = sem_post(atom->wait_sem);
409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			BUG_ON(ret);
410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case SCHED_EVENT_MIGRATION:
412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		default:
414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			BUG_ON(1);
415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 get_cpu_usage_nsec_parent(void)
419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rusage ru;
421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 sum;
422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int err;
423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	err = getrusage(RUSAGE_SELF, &ru);
425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(err);
426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sum =  ru.ru_utime.tv_sec*1e9 + ru.ru_utime.tv_usec*1e3;
428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sum += ru.ru_stime.tv_sec*1e9 + ru.ru_stime.tv_usec*1e3;
429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return sum;
431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int self_open_counters(void)
434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_event_attr attr;
436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int fd;
437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(&attr, 0, sizeof(attr));
439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	attr.type = PERF_TYPE_SOFTWARE;
441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	attr.config = PERF_COUNT_SW_TASK_CLOCK;
442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (fd < 0)
446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("Error: sys_perf_event_open() syscall returned "
447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		       "with %d (%s)\n", fd, strerror(errno));
448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return fd;
449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 get_cpu_usage_nsec_self(int fd)
452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 runtime;
454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret;
455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = read(fd, &runtime, sizeof(runtime));
457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret != sizeof(runtime));
458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return runtime;
460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct sched_thread_parms {
463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc  *task;
464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched;
465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void *thread_func(void *ctx)
468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
4690da480317e158a520d3128d45ed070c048a07187Ben Cheng#ifndef __APPLE__
470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sched_thread_parms *parms = ctx;
471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *this_task = parms->task;
472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched = parms->sched;
473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 cpu_usage_0, cpu_usage_1;
474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long i, ret;
475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char comm2[22];
476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int fd;
477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(parms);
479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sprintf(comm2, ":%s", this_task->comm);
481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	prctl(PR_SET_NAME, comm2);
482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fd = self_open_counters();
483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (fd < 0)
484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return NULL;
485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengagain:
486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = sem_post(&this_task->ready_for_work);
487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = pthread_mutex_lock(&sched->start_work_mutex);
489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = pthread_mutex_unlock(&sched->start_work_mutex);
491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	cpu_usage_0 = get_cpu_usage_nsec_self(fd);
494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < this_task->nr_events; i++) {
496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		this_task->curr_event = i;
497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		perf_sched__process_event(sched, this_task->atoms[i]);
498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	cpu_usage_1 = get_cpu_usage_nsec_self(fd);
501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = sem_post(&this_task->work_done_sem);
503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = pthread_mutex_unlock(&sched->work_done_wait_mutex);
508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	goto again;
5110da480317e158a520d3128d45ed070c048a07187Ben Cheng#else
5120da480317e158a520d3128d45ed070c048a07187Ben Cheng	perror("thread_func not supported on MacOS");
5130da480317e158a520d3128d45ed070c048a07187Ben Cheng	return NULL;
5140da480317e158a520d3128d45ed070c048a07187Ben Cheng#endif
515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void create_tasks(struct perf_sched *sched)
518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *task;
520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_attr_t attr;
521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long i;
522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int err;
523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	err = pthread_attr_init(&attr);
525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(err);
526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	err = pthread_attr_setstacksize(&attr,
527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			(size_t) max(16 * 1024, PTHREAD_STACK_MIN));
528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(err);
529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	err = pthread_mutex_lock(&sched->start_work_mutex);
530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(err);
531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	err = pthread_mutex_lock(&sched->work_done_wait_mutex);
532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(err);
533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->nr_tasks; i++) {
534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct sched_thread_parms *parms = malloc(sizeof(*parms));
535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		BUG_ON(parms == NULL);
536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		parms->task = task = sched->tasks[i];
537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		parms->sched = sched;
538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sem_init(&task->sleep_sem, 0, 0);
539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sem_init(&task->ready_for_work, 0, 0);
540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sem_init(&task->work_done_sem, 0, 0);
541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task->curr_event = 0;
542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		err = pthread_create(&task->thread, &attr, thread_func, parms);
543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		BUG_ON(err);
544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void wait_for_tasks(struct perf_sched *sched)
548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 cpu_usage_0, cpu_usage_1;
550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *task;
551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long i, ret;
552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->start_time = get_nsecs();
554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->cpu_usage = 0;
555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_unlock(&sched->work_done_wait_mutex);
556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->nr_tasks; i++) {
558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task = sched->tasks[i];
559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret = sem_wait(&task->ready_for_work);
560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		BUG_ON(ret);
561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sem_init(&task->ready_for_work, 0, 0);
562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	cpu_usage_0 = get_cpu_usage_nsec_parent();
567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pthread_mutex_unlock(&sched->start_work_mutex);
569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->nr_tasks; i++) {
571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task = sched->tasks[i];
572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret = sem_wait(&task->work_done_sem);
573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		BUG_ON(ret);
574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sem_init(&task->work_done_sem, 0, 0);
575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->cpu_usage += task->cpu_usage;
576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task->cpu_usage = 0;
577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	cpu_usage_1 = get_cpu_usage_nsec_parent();
580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!sched->runavg_cpu_usage)
581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->runavg_cpu_usage = sched->cpu_usage;
582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->runavg_cpu_usage = (sched->runavg_cpu_usage * 9 + sched->cpu_usage) / 10;
583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!sched->runavg_parent_cpu_usage)
586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->runavg_parent_cpu_usage = sched->parent_cpu_usage;
587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * 9 +
588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 sched->parent_cpu_usage)/10;
589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = pthread_mutex_lock(&sched->start_work_mutex);
591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(ret);
592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->nr_tasks; i++) {
594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task = sched->tasks[i];
595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sem_init(&task->sleep_sem, 0, 0);
596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		task->curr_event = 0;
597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void run_one_test(struct perf_sched *sched)
601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 T0, T1, delta, avg_delta, fluct;
603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	T0 = get_nsecs();
605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	wait_for_tasks(sched);
606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	T1 = get_nsecs();
607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	delta = T1 - T0;
609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->sum_runtime += delta;
610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_runs++;
611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	avg_delta = sched->sum_runtime / sched->nr_runs;
613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (delta < avg_delta)
614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		fluct = avg_delta - delta;
615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		fluct = delta - avg_delta;
617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->sum_fluct += fluct;
618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!sched->run_avg)
619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->run_avg = delta;
620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->run_avg = (sched->run_avg * 9 + delta) / 10;
621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0);
623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("ravg: %0.2f, ", (double)sched->run_avg / 1e6);
625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("cpu: %0.2f / %0.2f",
627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		(double)sched->cpu_usage / 1e6, (double)sched->runavg_cpu_usage / 1e6);
628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#if 0
630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * rusage statistics done by the parent, these are less
632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * accurate than the sched->sum_exec_runtime based statistics:
633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf(" [%0.2f / %0.2f]",
635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		(double)sched->parent_cpu_usage/1e6,
636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		(double)sched->runavg_parent_cpu_usage/1e6);
637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#endif
638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("\n");
640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->nr_sleep_corrections)
642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections);
643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_sleep_corrections = 0;
644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void test_calibrations(struct perf_sched *sched)
647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 T0, T1;
649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	T0 = get_nsecs();
651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	burn_nsecs(sched, 1e6);
652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	T1 = get_nsecs();
653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	T0 = get_nsecs();
657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sleep_nsecs(1e6);
658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	T1 = get_nsecs();
659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int
664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengreplay_wakeup_event(struct perf_sched *sched,
665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    struct perf_evsel *evsel, struct perf_sample *sample,
666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    struct machine *machine __maybe_unused)
667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *comm = perf_evsel__strval(evsel, sample, "comm");
669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 pid	 = perf_evsel__intval(evsel, sample, "pid");
670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *waker, *wakee;
671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (verbose) {
673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("sched_wakeup event %p\n", evsel);
674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf(" ... pid %d woke up %s/%d\n", sample->tid, comm, pid);
676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	waker = register_pid(sched, sample->tid, "<unknown>");
679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	wakee = register_pid(sched, pid, comm);
680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_sched_event_wakeup(sched, waker, sample->time, wakee);
682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int replay_switch_event(struct perf_sched *sched,
686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			       struct perf_evsel *evsel,
687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			       struct perf_sample *sample,
688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			       struct machine *machine __maybe_unused)
689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *prev_comm  = perf_evsel__strval(evsel, sample, "prev_comm"),
691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		   *next_comm  = perf_evsel__strval(evsel, sample, "next_comm");
692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  next_pid = perf_evsel__intval(evsel, sample, "next_pid");
694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct task_desc *prev, __maybe_unused *next;
696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 timestamp0, timestamp = sample->time;
697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int cpu = sample->cpu;
698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 delta;
699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (verbose)
701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("sched_switch event %p\n", evsel);
702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (cpu >= MAX_CPUS || cpu < 0)
704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	timestamp0 = sched->cpu_last_switched[cpu];
707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (timestamp0)
708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = timestamp - timestamp0;
709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = 0;
711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (delta < 0) {
713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 prev_comm, prev_pid, next_comm, next_pid, delta);
719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	prev = register_pid(sched, prev_pid, prev_comm);
721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	next = register_pid(sched, next_pid, next_comm);
722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->cpu_last_switched[cpu] = timestamp;
724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_sched_event_run(sched, prev, timestamp, delta);
726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_sched_event_sleep(sched, prev, timestamp, prev_state);
727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int replay_fork_event(struct perf_sched *sched,
732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     union perf_event *event,
733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     struct machine *machine)
734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread *child, *parent;
736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	child = machine__findnew_thread(machine, event->fork.pid,
738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					event->fork.tid);
739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	parent = machine__findnew_thread(machine, event->fork.ppid,
740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 event->fork.ptid);
741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (child == NULL || parent == NULL) {
743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("thread does not exist on fork event: child %p, parent %p\n",
744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 child, parent);
745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (verbose) {
749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("fork event\n");
750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("... parent: %s/%d\n", parent->comm, parent->tid);
751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("...  child: %s/%d\n", child->comm, child->tid);
752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	register_pid(sched, parent->tid, parent->comm);
755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	register_pid(sched, child->tid, child->comm);
756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct sort_dimension {
760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char		*name;
761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sort_fn_t		cmp;
762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct list_head	list;
763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int
766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengthread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sort_dimension *sort;
769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret = 0;
770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(list_empty(list));
772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_for_each_entry(sort, list, list) {
774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret = sort->cmp(l, r);
775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (ret)
776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return ret;
777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct work_atoms *
783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengthread_atoms_search(struct rb_root *root, struct thread *thread,
784e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 struct list_head *sort_list)
785e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
786e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *node = root->rb_node;
787e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atoms key = { .thread = thread };
788e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
789e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (node) {
790e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct work_atoms *atoms;
791e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int cmp;
792e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
793e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atoms = container_of(node, struct work_atoms, node);
794e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
795e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		cmp = thread_lat_cmp(sort_list, &key, atoms);
796e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (cmp > 0)
797e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			node = node->rb_left;
798e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else if (cmp < 0)
799e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			node = node->rb_right;
800e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else {
801e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			BUG_ON(thread != atoms->thread);
802e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return atoms;
803e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
804e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
805e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
806e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
807e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
808e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void
809e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__thread_latency_insert(struct rb_root *root, struct work_atoms *data,
810e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			 struct list_head *sort_list)
811e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
812e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node **new = &(root->rb_node), *parent = NULL;
813e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
814e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (*new) {
815e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct work_atoms *this;
816e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int cmp;
817e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
818e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		this = container_of(*new, struct work_atoms, node);
819e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		parent = *new;
820e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
821e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		cmp = thread_lat_cmp(sort_list, data, this);
822e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
823e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (cmp > 0)
824e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			new = &((*new)->rb_left);
825e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else
826e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			new = &((*new)->rb_right);
827e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
828e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
829e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rb_link_node(&data->node, parent, new);
830e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rb_insert_color(&data->node, root);
831e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
832e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
833e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
834e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
835e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atoms *atoms = zalloc(sizeof(*atoms));
836e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!atoms) {
837e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("No memory at %s\n", __func__);
838e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
839e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
840e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
841e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atoms->thread = thread;
842e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	INIT_LIST_HEAD(&atoms->work_list);
843e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	__thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
844e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
845e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
846e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
847e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic char sched_out_state(u64 prev_state)
848e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
849e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char *str = TASK_STATE_TO_CHAR_STR;
850e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
851e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return str[prev_state];
852e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
853e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
854e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int
855e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengadd_sched_out_event(struct work_atoms *atoms,
856e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    char run_state,
857e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    u64 timestamp)
858e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
859e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atom *atom = zalloc(sizeof(*atom));
860e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!atom) {
861e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("Non memory at %s", __func__);
862e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
863e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
864e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
865e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->sched_out_time = timestamp;
866e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
867e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (run_state == 'R') {
868e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atom->state = THREAD_WAIT_CPU;
869e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atom->wake_up_time = atom->sched_out_time;
870e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
871e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
872e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	list_add_tail(&atom->list, &atoms->work_list);
873e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
874e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
875e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
876e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void
877e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengadd_runtime_event(struct work_atoms *atoms, u64 delta,
878e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  u64 timestamp __maybe_unused)
879e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
880e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atom *atom;
881e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
882e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(list_empty(&atoms->work_list));
883e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
884e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
885e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
886e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->runtime += delta;
887e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atoms->total_runtime += delta;
888e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
889e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
890e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void
891e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengadd_sched_in_event(struct work_atoms *atoms, u64 timestamp)
892e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
893e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atom *atom;
894e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 delta;
895e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
896e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (list_empty(&atoms->work_list))
897e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
898e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
899e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
900e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
901e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (atom->state != THREAD_WAIT_CPU)
902e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
903e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
904e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (timestamp < atom->wake_up_time) {
905e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atom->state = THREAD_IGNORE;
906e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
907e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
908e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
909e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->state = THREAD_SCHED_IN;
910e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->sched_in_time = timestamp;
911e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
912e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	delta = atom->sched_in_time - atom->wake_up_time;
913e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atoms->total_lat += delta;
914e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (delta > atoms->max_lat) {
915e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atoms->max_lat = delta;
916e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atoms->max_lat_at = timestamp;
917e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
918e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atoms->nb_atoms++;
919e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
920e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
921e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int latency_switch_event(struct perf_sched *sched,
922e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct perf_evsel *evsel,
923e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct perf_sample *sample,
924e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct machine *machine)
925e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
926e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
927e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  next_pid = perf_evsel__intval(evsel, sample, "next_pid");
928e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
929e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atoms *out_events, *in_events;
930e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread *sched_out, *sched_in;
931e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 timestamp0, timestamp = sample->time;
932e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int cpu = sample->cpu;
933e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 delta;
934e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
935e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
936e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
937e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	timestamp0 = sched->cpu_last_switched[cpu];
938e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->cpu_last_switched[cpu] = timestamp;
939e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (timestamp0)
940e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = timestamp - timestamp0;
941e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
942e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = 0;
943e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
944e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (delta < 0) {
945e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
946e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
947e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
948e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
949e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched_out = machine__findnew_thread(machine, 0, prev_pid);
950e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched_in = machine__findnew_thread(machine, 0, next_pid);
951e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
952e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
953e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!out_events) {
954e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (thread_atoms_insert(sched, sched_out))
955e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
956e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
957e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!out_events) {
958e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_err("out-event: Internal tree error");
959e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
960e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
961e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
962e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (add_sched_out_event(out_events, sched_out_state(prev_state), timestamp))
963e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
964e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
965e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
966e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!in_events) {
967e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (thread_atoms_insert(sched, sched_in))
968e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
969e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
970e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!in_events) {
971e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_err("in-event: Internal tree error");
972e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
973e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
974e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/*
975e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 * Take came in we have not heard about yet,
976e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 * add in an initial atom in runnable state:
977e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 */
978e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (add_sched_out_event(in_events, 'R', timestamp))
979e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
980e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
981e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_sched_in_event(in_events, timestamp);
982e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
983e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
984e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
985e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
986e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int latency_runtime_event(struct perf_sched *sched,
987e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 struct perf_evsel *evsel,
988e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 struct perf_sample *sample,
989e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 struct machine *machine)
990e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
991e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 pid	   = perf_evsel__intval(evsel, sample, "pid");
992e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u64 runtime  = perf_evsel__intval(evsel, sample, "runtime");
993e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread *thread = machine__findnew_thread(machine, 0, pid);
994e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
995e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 timestamp = sample->time;
996e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int cpu = sample->cpu;
997e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
998e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
999e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!atoms) {
1000e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (thread_atoms_insert(sched, thread))
1001e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1002e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
1003e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!atoms) {
1004e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_err("in-event: Internal tree error");
1005e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1006e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1007e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (add_sched_out_event(atoms, 'R', timestamp))
1008e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1009e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1010e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1011e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_runtime_event(atoms, runtime, timestamp);
1012e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1013e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1014e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1015e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int latency_wakeup_event(struct perf_sched *sched,
1016e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct perf_evsel *evsel,
1017e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct perf_sample *sample,
1018e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				struct machine *machine)
1019e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1020e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 pid	  = perf_evsel__intval(evsel, sample, "pid"),
1021e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  success = perf_evsel__intval(evsel, sample, "success");
1022e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atoms *atoms;
1023e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atom *atom;
1024e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread *wakee;
1025e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 timestamp = sample->time;
1026e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1027e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* Note for later, it may be interesting to observe the failing cases */
1028e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!success)
1029e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
1030e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1031e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	wakee = machine__findnew_thread(machine, 0, pid);
1032e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1033e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!atoms) {
1034e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (thread_atoms_insert(sched, wakee))
1035e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1036e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1037e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!atoms) {
1038e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_err("wakeup-event: Internal tree error");
1039e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1040e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1041e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (add_sched_out_event(atoms, 'S', timestamp))
1042e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1043e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1044e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1045e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(list_empty(&atoms->work_list));
1046e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1047e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1048e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1049e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
1050e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * You WILL be missing events if you've recorded only
1051e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * one CPU, or are only looking at only one, so don't
1052e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * make useless noise.
1053e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
1054e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1055e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_state_machine_bugs++;
1056e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1057e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_timestamps++;
1058e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (atom->sched_out_time > timestamp) {
1059e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_unordered_timestamps++;
1060e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
1061e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1062e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1063e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->state = THREAD_WAIT_CPU;
1064e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->wake_up_time = timestamp;
1065e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1066e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1067e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1068e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int latency_migrate_task_event(struct perf_sched *sched,
1069e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct perf_evsel *evsel,
1070e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct perf_sample *sample,
1071e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct machine *machine)
1072e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1073e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 pid = perf_evsel__intval(evsel, sample, "pid");
1074e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 timestamp = sample->time;
1075e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atoms *atoms;
1076e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct work_atom *atom;
1077e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread *migrant;
1078e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1079e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
1080e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * Only need to worry about migration when profiling one CPU.
1081e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
1082e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->profile_cpu == -1)
1083e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
1084e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1085e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	migrant = machine__findnew_thread(machine, 0, pid);
1086e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1087e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!atoms) {
1088e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (thread_atoms_insert(sched, migrant))
1089e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1090e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		register_pid(sched, migrant->tid, migrant->comm);
1091e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1092e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!atoms) {
1093e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_err("migration-event: Internal tree error");
1094e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1095e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1096e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (add_sched_out_event(atoms, 'R', timestamp))
1097e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -1;
1098e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1099e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(list_empty(&atoms->work_list));
1101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->nr_timestamps++;
1106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (atom->sched_out_time > timestamp)
1108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_unordered_timestamps++;
1109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_list)
1114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
1116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret;
1117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 avg;
1118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!work_list->nb_atoms)
1120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
1121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
1122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * Ignore idle threads:
1123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
1124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!strcmp(work_list->thread->comm, "swapper"))
1125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return;
1126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->all_runtime += work_list->total_runtime;
1128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->all_count   += work_list->nb_atoms;
1129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = printf("  %s:%d ", work_list->thread->comm, work_list->thread->tid);
1131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < 24 - ret; i++)
1133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf(" ");
1134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	avg = work_list->total_lat / work_list->nb_atoms;
1136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	      (double)work_list->total_runtime / 1e6,
1139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 work_list->nb_atoms, (double)avg / 1e6,
1140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 (double)work_list->max_lat / 1e6,
1141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 (double)work_list->max_lat_at / 1e9);
1142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->thread->tid < r->thread->tid)
1147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->thread->tid > r->thread->tid)
1149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
1150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int avg_cmp(struct work_atoms *l, struct work_atoms *r)
1155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 avgl, avgr;
1157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!l->nb_atoms)
1159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!r->nb_atoms)
1162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
1163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	avgl = l->total_lat / l->nb_atoms;
1165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	avgr = r->total_lat / r->nb_atoms;
1166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (avgl < avgr)
1168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (avgl > avgr)
1170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
1171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int max_cmp(struct work_atoms *l, struct work_atoms *r)
1176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->max_lat < r->max_lat)
1178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->max_lat > r->max_lat)
1180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
1181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int switch_cmp(struct work_atoms *l, struct work_atoms *r)
1186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->nb_atoms < r->nb_atoms)
1188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->nb_atoms > r->nb_atoms)
1190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
1191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
1196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->total_runtime < r->total_runtime)
1198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (l->total_runtime > r->total_runtime)
1200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
1201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int sort_dimension__add(const char *tok, struct list_head *list)
1206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t i;
1208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	static struct sort_dimension avg_sort_dimension = {
1209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.name = "avg",
1210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.cmp  = avg_cmp,
1211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	static struct sort_dimension max_sort_dimension = {
1213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.name = "max",
1214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.cmp  = max_cmp,
1215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	static struct sort_dimension pid_sort_dimension = {
1217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.name = "pid",
1218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.cmp  = pid_cmp,
1219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	static struct sort_dimension runtime_sort_dimension = {
1221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.name = "runtime",
1222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.cmp  = runtime_cmp,
1223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	static struct sort_dimension switch_sort_dimension = {
1225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.name = "switch",
1226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.cmp  = switch_cmp,
1227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sort_dimension *available_sorts[] = {
1229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		&pid_sort_dimension,
1230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		&avg_sort_dimension,
1231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		&max_sort_dimension,
1232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		&switch_sort_dimension,
1233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		&runtime_sort_dimension,
1234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < ARRAY_SIZE(available_sorts); i++) {
1237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!strcmp(available_sorts[i]->name, tok)) {
1238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			list_add_tail(&available_sorts[i]->list, list);
1239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return 0;
1241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return -1;
1245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void perf_sched__sort_lat(struct perf_sched *sched)
1248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *node;
1250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (;;) {
1252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct work_atoms *data;
1253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		node = rb_first(&sched->atom_root);
1254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!node)
1255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
1256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		rb_erase(node, &sched->atom_root);
1258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		data = rb_entry(node, struct work_atoms, node);
1259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		__thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list);
1260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int process_sched_wakeup_event(struct perf_tool *tool,
1264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct perf_evsel *evsel,
1265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct perf_sample *sample,
1266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct machine *machine)
1267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->tp_handler->wakeup_event)
1271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return sched->tp_handler->wakeup_event(sched, evsel, sample, machine);
1272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    struct perf_sample *sample, struct machine *machine)
1278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
1280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread *sched_out __maybe_unused, *sched_in;
1282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int new_shortname;
1283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 timestamp0, timestamp = sample->time;
1284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	s64 delta;
1285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int cpu, this_cpu = sample->cpu;
1286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
1288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (this_cpu > sched->max_cpu)
1290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->max_cpu = this_cpu;
1291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	timestamp0 = sched->cpu_last_switched[this_cpu];
1293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->cpu_last_switched[this_cpu] = timestamp;
1294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (timestamp0)
1295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = timestamp - timestamp0;
1296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
1297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		delta = 0;
1298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (delta < 0) {
1300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched_out = machine__findnew_thread(machine, 0, prev_pid);
1305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched_in = machine__findnew_thread(machine, 0, next_pid);
1306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->curr_thread[this_cpu] = sched_in;
1308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("  ");
1310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	new_shortname = 0;
1312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!sched_in->shortname[0]) {
1313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched_in->shortname[0] = sched->next_shortname1;
1314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched_in->shortname[1] = sched->next_shortname2;
1315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sched->next_shortname1 < 'Z') {
1317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->next_shortname1++;
1318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else {
1319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->next_shortname1='A';
1320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (sched->next_shortname2 < '9') {
1321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sched->next_shortname2++;
1322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			} else {
1323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				sched->next_shortname2='0';
1324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			}
1325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		new_shortname = 1;
1327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (cpu = 0; cpu <= sched->max_cpu; cpu++) {
1330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (cpu != this_cpu)
1331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printf(" ");
1332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		else
1333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printf("*");
1334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sched->curr_thread[cpu]) {
1336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (sched->curr_thread[cpu]->tid)
1337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				printf("%2s ", sched->curr_thread[cpu]->shortname);
1338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			else
1339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				printf(".  ");
1340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		} else
1341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printf("   ");
1342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("  %12.6f secs ", (double)timestamp/1e9);
1345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (new_shortname) {
1346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("%s => %s:%d\n",
1347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched_in->shortname, sched_in->comm, sched_in->tid);
1348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
1349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("\n");
1350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int process_sched_switch_event(struct perf_tool *tool,
1356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct perf_evsel *evsel,
1357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct perf_sample *sample,
1358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				      struct machine *machine)
1359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int this_cpu = sample->cpu, err = 0;
1362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
1363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	    next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->curr_pid[this_cpu] != (u32)-1) {
1366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		/*
1367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 * Are we trying to switch away a PID that is
1368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 * not current?
1369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 */
1370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sched->curr_pid[this_cpu] != prev_pid)
1371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->nr_context_switch_bugs++;
1372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->tp_handler->switch_event)
1375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		err = sched->tp_handler->switch_event(sched, evsel, sample, machine);
1376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->curr_pid[this_cpu] = next_pid;
1378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return err;
1379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int process_sched_runtime_event(struct perf_tool *tool,
1382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       struct perf_evsel *evsel,
1383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       struct perf_sample *sample,
1384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       struct machine *machine)
1385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->tp_handler->runtime_event)
1389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return sched->tp_handler->runtime_event(sched, evsel, sample, machine);
1390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_sched__process_fork_event(struct perf_tool *tool,
1395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  union perf_event *event,
1396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  struct perf_sample *sample,
1397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  struct machine *machine)
1398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* run the fork event through the perf machineruy */
1402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_event__process_fork(tool, event, sample, machine);
1403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* and then run additional processing needed for this command */
1405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->tp_handler->fork_event)
1406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return sched->tp_handler->fork_event(sched, event, machine);
1407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int process_sched_migrate_task_event(struct perf_tool *tool,
1412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					    struct perf_evsel *evsel,
1413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					    struct perf_sample *sample,
1414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					    struct machine *machine)
1415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->tp_handler->migrate_task_event)
1419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return sched->tp_handler->migrate_task_event(sched, evsel, sample, machine);
1420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengtypedef int (*tracepoint_handler)(struct perf_tool *tool,
1425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct perf_evsel *evsel,
1426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct perf_sample *sample,
1427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  struct machine *machine);
1428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused,
1430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						 union perf_event *event __maybe_unused,
1431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						 struct perf_sample *sample,
1432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						 struct perf_evsel *evsel,
1433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						 struct machine *machine)
1434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int err = 0;
1436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	evsel->hists.stats.total_period += sample->period;
1438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (evsel->handler.func != NULL) {
1441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		tracepoint_handler f = evsel->handler.func;
1442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		err = f(tool, evsel, sample, machine);
1443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return err;
1446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_sched__read_events(struct perf_sched *sched,
1449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   struct perf_session **psession)
1450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct perf_evsel_str_handler handlers[] = {
1452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		{ "sched:sched_switch",	      process_sched_switch_event, },
1453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		{ "sched:sched_stat_runtime", process_sched_runtime_event, },
1454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		{ "sched:sched_wakeup",	      process_sched_wakeup_event, },
1455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		{ "sched:sched_wakeup_new",   process_sched_wakeup_event, },
1456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
1457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_session *session;
1459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool);
1461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (session == NULL) {
1462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("No Memory for session\n");
1463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_session__set_tracepoints_handlers(session, handlers))
1467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out_delete;
1468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_session__has_traces(session, "record -R")) {
1470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		int err = perf_session__process_events(session, &sched->tool);
1471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (err) {
1472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_err("Failed to process events, error %d", err);
1473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_delete;
1474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_events      = session->stats.nr_events[0];
1477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_lost_events = session->stats.total_lost;
1478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
1479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (psession)
1482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*psession = session;
1483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
1484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		perf_session__delete(session);
1485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_delete:
1489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_session__delete(session);
1490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return -1;
1491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void print_bad_events(struct perf_sched *sched)
1494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->nr_unordered_timestamps && sched->nr_timestamps) {
1496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("  INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
1497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			(double)sched->nr_unordered_timestamps/(double)sched->nr_timestamps*100.0,
1498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->nr_unordered_timestamps, sched->nr_timestamps);
1499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->nr_lost_events && sched->nr_events) {
1501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("  INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
1502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			(double)sched->nr_lost_events/(double)sched->nr_events * 100.0,
1503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks);
1504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->nr_state_machine_bugs && sched->nr_timestamps) {
1506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("  INFO: %.3f%% state machine bugs (%ld out of %ld)",
1507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			(double)sched->nr_state_machine_bugs/(double)sched->nr_timestamps*100.0,
1508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->nr_state_machine_bugs, sched->nr_timestamps);
1509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sched->nr_lost_events)
1510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printf(" (due to lost events?)");
1511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("\n");
1512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->nr_context_switch_bugs && sched->nr_timestamps) {
1514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("  INFO: %.3f%% context switch bugs (%ld out of %ld)",
1515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			(double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0,
1516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->nr_context_switch_bugs, sched->nr_timestamps);
1517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sched->nr_lost_events)
1518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			printf(" (due to lost events?)");
1519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("\n");
1520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_sched__lat(struct perf_sched *sched)
1524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *next;
1526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_session *session;
1527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	setup_pager();
1529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* save session -- references to threads are held in work_list */
1531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_sched__read_events(sched, &session))
1532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_sched__sort_lat(sched);
1535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("  Task                  |   Runtime ms  | Switches | Average delay ms | Maximum delay ms | Maximum delay at     |\n");
1538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf(" ---------------------------------------------------------------------------------------------------------------\n");
1539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	next = rb_first(&sched->sorted_atom_root);
1541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (next) {
1543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct work_atoms *work_list;
1544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		work_list = rb_entry(next, struct work_atoms, node);
1546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		output_lat_thread(sched, work_list);
1547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		next = rb_next(next);
1548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf(" -----------------------------------------------------------------------------------------\n");
1551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
1552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		(double)sched->all_runtime / 1e6, sched->all_count);
1553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf(" ---------------------------------------------------\n");
1555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	print_bad_events(sched);
1557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("\n");
1558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	perf_session__delete(session);
1560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_sched__map(struct perf_sched *sched)
1564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	setup_pager();
1568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_sched__read_events(sched, NULL))
1569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	print_bad_events(sched);
1571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int perf_sched__replay(struct perf_sched *sched)
1575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned long i;
1577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	calibrate_run_measurement_overhead(sched);
1579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	calibrate_sleep_measurement_overhead(sched);
1580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	test_calibrations(sched);
1582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (perf_sched__read_events(sched, NULL))
1584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
1585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("nr_run_events:        %ld\n", sched->nr_run_events);
1587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("nr_sleep_events:      %ld\n", sched->nr_sleep_events);
1588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("nr_wakeup_events:     %ld\n", sched->nr_wakeup_events);
1589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->targetless_wakeups)
1591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("target-less wakeups:  %ld\n", sched->targetless_wakeups);
1592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->multitarget_wakeups)
1593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("multi-target wakeups: %ld\n", sched->multitarget_wakeups);
1594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sched->nr_run_events_optimized)
1595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printf("run atoms optimized: %ld\n",
1596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			sched->nr_run_events_optimized);
1597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	print_task_traces(sched);
1599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	add_cross_task_wakeups(sched);
1600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	create_tasks(sched);
1602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	printf("------------------------------------------------------------\n");
1603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < sched->replay_repeat; i++)
1604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		run_one_test(sched);
1605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void setup_sorting(struct perf_sched *sched, const struct option *options,
1610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			  const char * const usage_msg[])
1611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char *tmp, *tok, *str = strdup(sched->sort_order);
1613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (tok = strtok_r(str, ", ", &tmp);
1615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			tok; tok = strtok_r(NULL, ", ", &tmp)) {
1616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sort_dimension__add(tok, &sched->sort_list) < 0) {
1617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			error("Unknown --sort key: `%s'", tok);
1618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			usage_with_options(usage_msg, options);
1619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(str);
1623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sort_dimension__add("pid", &sched->cmp_pid);
1625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int __cmd_record(int argc, const char **argv)
1628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned int rec_argc, i, j;
1630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char **rec_argv;
1631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char * const record_args[] = {
1632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"record",
1633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-a",
1634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-R",
1635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-m", "1024",
1636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-c", "1",
1637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_switch",
1638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_stat_wait",
1639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_stat_sleep",
1640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_stat_iowait",
1641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_stat_runtime",
1642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_process_fork",
1643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_wakeup",
1644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"-e", "sched:sched_migrate_task",
1645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rec_argv = calloc(rec_argc + 1, sizeof(char *));
1649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (rec_argv == NULL)
1651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -ENOMEM;
1652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < ARRAY_SIZE(record_args); i++)
1654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		rec_argv[i] = strdup(record_args[i]);
1655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (j = 1; j < (unsigned int)argc; j++, i++)
1657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		rec_argv[i] = argv[j];
1658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	BUG_ON(i != rec_argc);
1660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return cmd_record(i, rec_argv, NULL);
1662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic const char default_sort_order[] = "avg, max, switch, runtime";
1665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct perf_sched sched = {
1666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.tool = {
1667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.sample		 = perf_sched__process_tracepoint_sample,
1668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.comm		 = perf_event__process_comm,
1669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.lost		 = perf_event__process_lost,
1670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.fork		 = perf_sched__process_fork_event,
1671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.ordered_samples = true,
1672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	},
1673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.cmp_pid	      = LIST_HEAD_INIT(sched.cmp_pid),
1674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.sort_list	      = LIST_HEAD_INIT(sched.sort_list),
1675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
1676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.curr_pid	      = { [0 ... MAX_CPUS - 1] = -1 },
1678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.sort_order	      = default_sort_order,
1679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.replay_repeat	      = 10,
1680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.profile_cpu	      = -1,
1681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.next_shortname1      = 'A',
1682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.next_shortname2      = '0',
1683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
1684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
1687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct option latency_options[] = {
1688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
1689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		   "sort by key(s): runtime, switch, avg, max"),
1690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_INCR('v', "verbose", &verbose,
1691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "be more verbose (show symbol address, etc)"),
1692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_INTEGER('C', "CPU", &sched.profile_cpu,
1693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "CPU to profile on"),
1694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "dump raw trace in ASCII"),
1696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_END()
1697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct option replay_options[] = {
1699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_UINTEGER('r', "repeat", &sched.replay_repeat,
1700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		     "repeat the workload replay N times (-1: infinite)"),
1701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_INCR('v', "verbose", &verbose,
1702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "be more verbose (show symbol address, etc)"),
1703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "dump raw trace in ASCII"),
1705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_END()
1706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const struct option sched_options[] = {
1708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_STRING('i', "input", &input_name, "file",
1709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "input file name"),
1710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_INCR('v', "verbose", &verbose,
1711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "be more verbose (show symbol address, etc)"),
1712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    "dump raw trace in ASCII"),
1714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	OPT_END()
1715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char * const latency_usage[] = {
1717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"perf sched latency [<options>]",
1718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		NULL
1719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char * const replay_usage[] = {
1721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"perf sched replay [<options>]",
1722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		NULL
1723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	const char * const sched_usage[] = {
1725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		"perf sched [<options>] {record|latency|map|replay|script}",
1726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		NULL
1727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct trace_sched_handler lat_ops  = {
1729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.wakeup_event	    = latency_wakeup_event,
1730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.switch_event	    = latency_switch_event,
1731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.runtime_event	    = latency_runtime_event,
1732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.migrate_task_event = latency_migrate_task_event,
1733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct trace_sched_handler map_ops  = {
1735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.switch_event	    = map_switch_event,
1736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct trace_sched_handler replay_ops  = {
1738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.wakeup_event	    = replay_wakeup_event,
1739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.switch_event	    = replay_switch_event,
1740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.fork_event	    = replay_fork_event,
1741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
1742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	argc = parse_options(argc, argv, sched_options, sched_usage,
1744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     PARSE_OPT_STOP_AT_NON_OPTION);
1745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!argc)
1746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		usage_with_options(sched_usage, sched_options);
1747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
1749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * Aliased to 'perf script' for now:
1750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
1751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!strcmp(argv[0], "script"))
1752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return cmd_script(argc, argv, prefix);
1753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	symbol__init();
1755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!strncmp(argv[0], "rec", 3)) {
1756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return __cmd_record(argc, argv);
1757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else if (!strncmp(argv[0], "lat", 3)) {
1758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched.tp_handler = &lat_ops;
1759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (argc > 1) {
1760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			argc = parse_options(argc, argv, latency_options, latency_usage, 0);
1761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (argc)
1762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				usage_with_options(latency_usage, latency_options);
1763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		setup_sorting(&sched, latency_options, latency_usage);
1765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return perf_sched__lat(&sched);
1766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else if (!strcmp(argv[0], "map")) {
1767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched.tp_handler = &map_ops;
1768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		setup_sorting(&sched, latency_options, latency_usage);
1769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return perf_sched__map(&sched);
1770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else if (!strncmp(argv[0], "rep", 3)) {
1771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sched.tp_handler = &replay_ops;
1772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (argc) {
1773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			argc = parse_options(argc, argv, replay_options, replay_usage, 0);
1774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (argc)
1775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				usage_with_options(replay_usage, replay_options);
1776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
1777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return perf_sched__replay(&sched);
1778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else {
1779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		usage_with_options(sched_usage, sched_options);
1780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
1781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
1782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
1783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
1784