18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "builtin.h"
38c2ecf20Sopenharmony_ci#include "perf.h"
48c2ecf20Sopenharmony_ci#include "perf-sys.h"
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "util/cpumap.h"
78c2ecf20Sopenharmony_ci#include "util/evlist.h"
88c2ecf20Sopenharmony_ci#include "util/evsel.h"
98c2ecf20Sopenharmony_ci#include "util/evsel_fprintf.h"
108c2ecf20Sopenharmony_ci#include "util/symbol.h"
118c2ecf20Sopenharmony_ci#include "util/thread.h"
128c2ecf20Sopenharmony_ci#include "util/header.h"
138c2ecf20Sopenharmony_ci#include "util/session.h"
148c2ecf20Sopenharmony_ci#include "util/tool.h"
158c2ecf20Sopenharmony_ci#include "util/cloexec.h"
168c2ecf20Sopenharmony_ci#include "util/thread_map.h"
178c2ecf20Sopenharmony_ci#include "util/color.h"
188c2ecf20Sopenharmony_ci#include "util/stat.h"
198c2ecf20Sopenharmony_ci#include "util/string2.h"
208c2ecf20Sopenharmony_ci#include "util/callchain.h"
218c2ecf20Sopenharmony_ci#include "util/time-utils.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <subcmd/pager.h>
248c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
258c2ecf20Sopenharmony_ci#include "util/trace-event.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "util/debug.h"
288c2ecf20Sopenharmony_ci#include "util/event.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/kernel.h>
318c2ecf20Sopenharmony_ci#include <linux/log2.h>
328c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
338c2ecf20Sopenharmony_ci#include <sys/prctl.h>
348c2ecf20Sopenharmony_ci#include <sys/resource.h>
358c2ecf20Sopenharmony_ci#include <inttypes.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <errno.h>
388c2ecf20Sopenharmony_ci#include <semaphore.h>
398c2ecf20Sopenharmony_ci#include <pthread.h>
408c2ecf20Sopenharmony_ci#include <math.h>
418c2ecf20Sopenharmony_ci#include <api/fs/fs.h>
428c2ecf20Sopenharmony_ci#include <perf/cpumap.h>
438c2ecf20Sopenharmony_ci#include <linux/time64.h>
448c2ecf20Sopenharmony_ci#include <linux/err.h>
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include <linux/ctype.h>
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define PR_SET_NAME		15               /* Set process name */
498c2ecf20Sopenharmony_ci#define MAX_CPUS		4096
508c2ecf20Sopenharmony_ci#define COMM_LEN		20
518c2ecf20Sopenharmony_ci#define SYM_LEN			129
528c2ecf20Sopenharmony_ci#define MAX_PID			1024000
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic const char *cpu_list;
558c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistruct sched_atom;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct task_desc {
608c2ecf20Sopenharmony_ci	unsigned long		nr;
618c2ecf20Sopenharmony_ci	unsigned long		pid;
628c2ecf20Sopenharmony_ci	char			comm[COMM_LEN];
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	unsigned long		nr_events;
658c2ecf20Sopenharmony_ci	unsigned long		curr_event;
668c2ecf20Sopenharmony_ci	struct sched_atom	**atoms;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	pthread_t		thread;
698c2ecf20Sopenharmony_ci	sem_t			sleep_sem;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	sem_t			ready_for_work;
728c2ecf20Sopenharmony_ci	sem_t			work_done_sem;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	u64			cpu_usage;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cienum sched_event_type {
788c2ecf20Sopenharmony_ci	SCHED_EVENT_RUN,
798c2ecf20Sopenharmony_ci	SCHED_EVENT_SLEEP,
808c2ecf20Sopenharmony_ci	SCHED_EVENT_WAKEUP,
818c2ecf20Sopenharmony_ci	SCHED_EVENT_MIGRATION,
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistruct sched_atom {
858c2ecf20Sopenharmony_ci	enum sched_event_type	type;
868c2ecf20Sopenharmony_ci	int			specific_wait;
878c2ecf20Sopenharmony_ci	u64			timestamp;
888c2ecf20Sopenharmony_ci	u64			duration;
898c2ecf20Sopenharmony_ci	unsigned long		nr;
908c2ecf20Sopenharmony_ci	sem_t			*wait_sem;
918c2ecf20Sopenharmony_ci	struct task_desc	*wakee;
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* task state bitmask, copied from include/linux/sched.h */
978c2ecf20Sopenharmony_ci#define TASK_RUNNING		0
988c2ecf20Sopenharmony_ci#define TASK_INTERRUPTIBLE	1
998c2ecf20Sopenharmony_ci#define TASK_UNINTERRUPTIBLE	2
1008c2ecf20Sopenharmony_ci#define __TASK_STOPPED		4
1018c2ecf20Sopenharmony_ci#define __TASK_TRACED		8
1028c2ecf20Sopenharmony_ci/* in tsk->exit_state */
1038c2ecf20Sopenharmony_ci#define EXIT_DEAD		16
1048c2ecf20Sopenharmony_ci#define EXIT_ZOMBIE		32
1058c2ecf20Sopenharmony_ci#define EXIT_TRACE		(EXIT_ZOMBIE | EXIT_DEAD)
1068c2ecf20Sopenharmony_ci/* in tsk->state again */
1078c2ecf20Sopenharmony_ci#define TASK_DEAD		64
1088c2ecf20Sopenharmony_ci#define TASK_WAKEKILL		128
1098c2ecf20Sopenharmony_ci#define TASK_WAKING		256
1108c2ecf20Sopenharmony_ci#define TASK_PARKED		512
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cienum thread_state {
1138c2ecf20Sopenharmony_ci	THREAD_SLEEPING = 0,
1148c2ecf20Sopenharmony_ci	THREAD_WAIT_CPU,
1158c2ecf20Sopenharmony_ci	THREAD_SCHED_IN,
1168c2ecf20Sopenharmony_ci	THREAD_IGNORE
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistruct work_atom {
1208c2ecf20Sopenharmony_ci	struct list_head	list;
1218c2ecf20Sopenharmony_ci	enum thread_state	state;
1228c2ecf20Sopenharmony_ci	u64			sched_out_time;
1238c2ecf20Sopenharmony_ci	u64			wake_up_time;
1248c2ecf20Sopenharmony_ci	u64			sched_in_time;
1258c2ecf20Sopenharmony_ci	u64			runtime;
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistruct work_atoms {
1298c2ecf20Sopenharmony_ci	struct list_head	work_list;
1308c2ecf20Sopenharmony_ci	struct thread		*thread;
1318c2ecf20Sopenharmony_ci	struct rb_node		node;
1328c2ecf20Sopenharmony_ci	u64			max_lat;
1338c2ecf20Sopenharmony_ci	u64			max_lat_start;
1348c2ecf20Sopenharmony_ci	u64			max_lat_end;
1358c2ecf20Sopenharmony_ci	u64			total_lat;
1368c2ecf20Sopenharmony_ci	u64			nb_atoms;
1378c2ecf20Sopenharmony_ci	u64			total_runtime;
1388c2ecf20Sopenharmony_ci	int			num_merged;
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_citypedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistruct perf_sched;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistruct trace_sched_handler {
1468c2ecf20Sopenharmony_ci	int (*switch_event)(struct perf_sched *sched, struct evsel *evsel,
1478c2ecf20Sopenharmony_ci			    struct perf_sample *sample, struct machine *machine);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	int (*runtime_event)(struct perf_sched *sched, struct evsel *evsel,
1508c2ecf20Sopenharmony_ci			     struct perf_sample *sample, struct machine *machine);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	int (*wakeup_event)(struct perf_sched *sched, struct evsel *evsel,
1538c2ecf20Sopenharmony_ci			    struct perf_sample *sample, struct machine *machine);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
1568c2ecf20Sopenharmony_ci	int (*fork_event)(struct perf_sched *sched, union perf_event *event,
1578c2ecf20Sopenharmony_ci			  struct machine *machine);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	int (*migrate_task_event)(struct perf_sched *sched,
1608c2ecf20Sopenharmony_ci				  struct evsel *evsel,
1618c2ecf20Sopenharmony_ci				  struct perf_sample *sample,
1628c2ecf20Sopenharmony_ci				  struct machine *machine);
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci#define COLOR_PIDS PERF_COLOR_BLUE
1668c2ecf20Sopenharmony_ci#define COLOR_CPUS PERF_COLOR_BG_RED
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistruct perf_sched_map {
1698c2ecf20Sopenharmony_ci	DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS);
1708c2ecf20Sopenharmony_ci	int			*comp_cpus;
1718c2ecf20Sopenharmony_ci	bool			 comp;
1728c2ecf20Sopenharmony_ci	struct perf_thread_map *color_pids;
1738c2ecf20Sopenharmony_ci	const char		*color_pids_str;
1748c2ecf20Sopenharmony_ci	struct perf_cpu_map	*color_cpus;
1758c2ecf20Sopenharmony_ci	const char		*color_cpus_str;
1768c2ecf20Sopenharmony_ci	struct perf_cpu_map	*cpus;
1778c2ecf20Sopenharmony_ci	const char		*cpus_str;
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistruct perf_sched {
1818c2ecf20Sopenharmony_ci	struct perf_tool tool;
1828c2ecf20Sopenharmony_ci	const char	 *sort_order;
1838c2ecf20Sopenharmony_ci	unsigned long	 nr_tasks;
1848c2ecf20Sopenharmony_ci	struct task_desc **pid_to_task;
1858c2ecf20Sopenharmony_ci	struct task_desc **tasks;
1868c2ecf20Sopenharmony_ci	const struct trace_sched_handler *tp_handler;
1878c2ecf20Sopenharmony_ci	pthread_mutex_t	 start_work_mutex;
1888c2ecf20Sopenharmony_ci	pthread_mutex_t	 work_done_wait_mutex;
1898c2ecf20Sopenharmony_ci	int		 profile_cpu;
1908c2ecf20Sopenharmony_ci/*
1918c2ecf20Sopenharmony_ci * Track the current task - that way we can know whether there's any
1928c2ecf20Sopenharmony_ci * weird events, such as a task being switched away that is not current.
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_ci	int		 max_cpu;
1958c2ecf20Sopenharmony_ci	u32		 curr_pid[MAX_CPUS];
1968c2ecf20Sopenharmony_ci	struct thread	 *curr_thread[MAX_CPUS];
1978c2ecf20Sopenharmony_ci	char		 next_shortname1;
1988c2ecf20Sopenharmony_ci	char		 next_shortname2;
1998c2ecf20Sopenharmony_ci	unsigned int	 replay_repeat;
2008c2ecf20Sopenharmony_ci	unsigned long	 nr_run_events;
2018c2ecf20Sopenharmony_ci	unsigned long	 nr_sleep_events;
2028c2ecf20Sopenharmony_ci	unsigned long	 nr_wakeup_events;
2038c2ecf20Sopenharmony_ci	unsigned long	 nr_sleep_corrections;
2048c2ecf20Sopenharmony_ci	unsigned long	 nr_run_events_optimized;
2058c2ecf20Sopenharmony_ci	unsigned long	 targetless_wakeups;
2068c2ecf20Sopenharmony_ci	unsigned long	 multitarget_wakeups;
2078c2ecf20Sopenharmony_ci	unsigned long	 nr_runs;
2088c2ecf20Sopenharmony_ci	unsigned long	 nr_timestamps;
2098c2ecf20Sopenharmony_ci	unsigned long	 nr_unordered_timestamps;
2108c2ecf20Sopenharmony_ci	unsigned long	 nr_context_switch_bugs;
2118c2ecf20Sopenharmony_ci	unsigned long	 nr_events;
2128c2ecf20Sopenharmony_ci	unsigned long	 nr_lost_chunks;
2138c2ecf20Sopenharmony_ci	unsigned long	 nr_lost_events;
2148c2ecf20Sopenharmony_ci	u64		 run_measurement_overhead;
2158c2ecf20Sopenharmony_ci	u64		 sleep_measurement_overhead;
2168c2ecf20Sopenharmony_ci	u64		 start_time;
2178c2ecf20Sopenharmony_ci	u64		 cpu_usage;
2188c2ecf20Sopenharmony_ci	u64		 runavg_cpu_usage;
2198c2ecf20Sopenharmony_ci	u64		 parent_cpu_usage;
2208c2ecf20Sopenharmony_ci	u64		 runavg_parent_cpu_usage;
2218c2ecf20Sopenharmony_ci	u64		 sum_runtime;
2228c2ecf20Sopenharmony_ci	u64		 sum_fluct;
2238c2ecf20Sopenharmony_ci	u64		 run_avg;
2248c2ecf20Sopenharmony_ci	u64		 all_runtime;
2258c2ecf20Sopenharmony_ci	u64		 all_count;
2268c2ecf20Sopenharmony_ci	u64		 cpu_last_switched[MAX_CPUS];
2278c2ecf20Sopenharmony_ci	struct rb_root_cached atom_root, sorted_atom_root, merged_atom_root;
2288c2ecf20Sopenharmony_ci	struct list_head sort_list, cmp_pid;
2298c2ecf20Sopenharmony_ci	bool force;
2308c2ecf20Sopenharmony_ci	bool skip_merge;
2318c2ecf20Sopenharmony_ci	struct perf_sched_map map;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* options for timehist command */
2348c2ecf20Sopenharmony_ci	bool		summary;
2358c2ecf20Sopenharmony_ci	bool		summary_only;
2368c2ecf20Sopenharmony_ci	bool		idle_hist;
2378c2ecf20Sopenharmony_ci	bool		show_callchain;
2388c2ecf20Sopenharmony_ci	unsigned int	max_stack;
2398c2ecf20Sopenharmony_ci	bool		show_cpu_visual;
2408c2ecf20Sopenharmony_ci	bool		show_wakeups;
2418c2ecf20Sopenharmony_ci	bool		show_next;
2428c2ecf20Sopenharmony_ci	bool		show_migrations;
2438c2ecf20Sopenharmony_ci	bool		show_state;
2448c2ecf20Sopenharmony_ci	u64		skipped_samples;
2458c2ecf20Sopenharmony_ci	const char	*time_str;
2468c2ecf20Sopenharmony_ci	struct perf_time_interval ptime;
2478c2ecf20Sopenharmony_ci	struct perf_time_interval hist_time;
2488c2ecf20Sopenharmony_ci};
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/* per thread run time data */
2518c2ecf20Sopenharmony_cistruct thread_runtime {
2528c2ecf20Sopenharmony_ci	u64 last_time;      /* time of previous sched in/out event */
2538c2ecf20Sopenharmony_ci	u64 dt_run;         /* run time */
2548c2ecf20Sopenharmony_ci	u64 dt_sleep;       /* time between CPU access by sleep (off cpu) */
2558c2ecf20Sopenharmony_ci	u64 dt_iowait;      /* time between CPU access by iowait (off cpu) */
2568c2ecf20Sopenharmony_ci	u64 dt_preempt;     /* time between CPU access by preempt (off cpu) */
2578c2ecf20Sopenharmony_ci	u64 dt_delay;       /* time between wakeup and sched-in */
2588c2ecf20Sopenharmony_ci	u64 ready_to_run;   /* time of wakeup */
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	struct stats run_stats;
2618c2ecf20Sopenharmony_ci	u64 total_run_time;
2628c2ecf20Sopenharmony_ci	u64 total_sleep_time;
2638c2ecf20Sopenharmony_ci	u64 total_iowait_time;
2648c2ecf20Sopenharmony_ci	u64 total_preempt_time;
2658c2ecf20Sopenharmony_ci	u64 total_delay_time;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	int last_state;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	char shortname[3];
2708c2ecf20Sopenharmony_ci	bool comm_changed;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	u64 migrations;
2738c2ecf20Sopenharmony_ci};
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/* per event run time data */
2768c2ecf20Sopenharmony_cistruct evsel_runtime {
2778c2ecf20Sopenharmony_ci	u64 *last_time; /* time this event was last seen per cpu */
2788c2ecf20Sopenharmony_ci	u32 ncpu;       /* highest cpu slot allocated */
2798c2ecf20Sopenharmony_ci};
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/* per cpu idle time data */
2828c2ecf20Sopenharmony_cistruct idle_thread_runtime {
2838c2ecf20Sopenharmony_ci	struct thread_runtime	tr;
2848c2ecf20Sopenharmony_ci	struct thread		*last_thread;
2858c2ecf20Sopenharmony_ci	struct rb_root_cached	sorted_root;
2868c2ecf20Sopenharmony_ci	struct callchain_root	callchain;
2878c2ecf20Sopenharmony_ci	struct callchain_cursor	cursor;
2888c2ecf20Sopenharmony_ci};
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* track idle times per cpu */
2918c2ecf20Sopenharmony_cistatic struct thread **idle_threads;
2928c2ecf20Sopenharmony_cistatic int idle_max_cpu;
2938c2ecf20Sopenharmony_cistatic char idle_comm[] = "<idle>";
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic u64 get_nsecs(void)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct timespec ts;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &ts);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void burn_nsecs(struct perf_sched *sched, u64 nsecs)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	u64 T0 = get_nsecs(), T1;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	do {
3098c2ecf20Sopenharmony_ci		T1 = get_nsecs();
3108c2ecf20Sopenharmony_ci	} while (T1 + sched->run_measurement_overhead < T0 + nsecs);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic void sleep_nsecs(u64 nsecs)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct timespec ts;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	ts.tv_nsec = nsecs % 999999999;
3188c2ecf20Sopenharmony_ci	ts.tv_sec = nsecs / 999999999;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	nanosleep(&ts, NULL);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic void calibrate_run_measurement_overhead(struct perf_sched *sched)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	u64 T0, T1, delta, min_delta = NSEC_PER_SEC;
3268c2ecf20Sopenharmony_ci	int i;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
3298c2ecf20Sopenharmony_ci		T0 = get_nsecs();
3308c2ecf20Sopenharmony_ci		burn_nsecs(sched, 0);
3318c2ecf20Sopenharmony_ci		T1 = get_nsecs();
3328c2ecf20Sopenharmony_ci		delta = T1-T0;
3338c2ecf20Sopenharmony_ci		min_delta = min(min_delta, delta);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci	sched->run_measurement_overhead = min_delta;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic void calibrate_sleep_measurement_overhead(struct perf_sched *sched)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	u64 T0, T1, delta, min_delta = NSEC_PER_SEC;
3438c2ecf20Sopenharmony_ci	int i;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
3468c2ecf20Sopenharmony_ci		T0 = get_nsecs();
3478c2ecf20Sopenharmony_ci		sleep_nsecs(10000);
3488c2ecf20Sopenharmony_ci		T1 = get_nsecs();
3498c2ecf20Sopenharmony_ci		delta = T1-T0;
3508c2ecf20Sopenharmony_ci		min_delta = min(min_delta, delta);
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci	min_delta -= 10000;
3538c2ecf20Sopenharmony_ci	sched->sleep_measurement_overhead = min_delta;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic struct sched_atom *
3598c2ecf20Sopenharmony_ciget_new_event(struct task_desc *task, u64 timestamp)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct sched_atom *event = zalloc(sizeof(*event));
3628c2ecf20Sopenharmony_ci	unsigned long idx = task->nr_events;
3638c2ecf20Sopenharmony_ci	size_t size;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	event->timestamp = timestamp;
3668c2ecf20Sopenharmony_ci	event->nr = idx;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	task->nr_events++;
3698c2ecf20Sopenharmony_ci	size = sizeof(struct sched_atom *) * task->nr_events;
3708c2ecf20Sopenharmony_ci	task->atoms = realloc(task->atoms, size);
3718c2ecf20Sopenharmony_ci	BUG_ON(!task->atoms);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	task->atoms[idx] = event;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return event;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic struct sched_atom *last_event(struct task_desc *task)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	if (!task->nr_events)
3818c2ecf20Sopenharmony_ci		return NULL;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return task->atoms[task->nr_events - 1];
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic void add_sched_event_run(struct perf_sched *sched, struct task_desc *task,
3878c2ecf20Sopenharmony_ci				u64 timestamp, u64 duration)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct sched_atom *event, *curr_event = last_event(task);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/*
3928c2ecf20Sopenharmony_ci	 * optimize an existing RUN event by merging this one
3938c2ecf20Sopenharmony_ci	 * to it:
3948c2ecf20Sopenharmony_ci	 */
3958c2ecf20Sopenharmony_ci	if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
3968c2ecf20Sopenharmony_ci		sched->nr_run_events_optimized++;
3978c2ecf20Sopenharmony_ci		curr_event->duration += duration;
3988c2ecf20Sopenharmony_ci		return;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	event = get_new_event(task, timestamp);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	event->type = SCHED_EVENT_RUN;
4048c2ecf20Sopenharmony_ci	event->duration = duration;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	sched->nr_run_events++;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *task,
4108c2ecf20Sopenharmony_ci				   u64 timestamp, struct task_desc *wakee)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct sched_atom *event, *wakee_event;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	event = get_new_event(task, timestamp);
4158c2ecf20Sopenharmony_ci	event->type = SCHED_EVENT_WAKEUP;
4168c2ecf20Sopenharmony_ci	event->wakee = wakee;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	wakee_event = last_event(wakee);
4198c2ecf20Sopenharmony_ci	if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
4208c2ecf20Sopenharmony_ci		sched->targetless_wakeups++;
4218c2ecf20Sopenharmony_ci		return;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	if (wakee_event->wait_sem) {
4248c2ecf20Sopenharmony_ci		sched->multitarget_wakeups++;
4258c2ecf20Sopenharmony_ci		return;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
4298c2ecf20Sopenharmony_ci	sem_init(wakee_event->wait_sem, 0, 0);
4308c2ecf20Sopenharmony_ci	wakee_event->specific_wait = 1;
4318c2ecf20Sopenharmony_ci	event->wait_sem = wakee_event->wait_sem;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	sched->nr_wakeup_events++;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task,
4378c2ecf20Sopenharmony_ci				  u64 timestamp, u64 task_state __maybe_unused)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct sched_atom *event = get_new_event(task, timestamp);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	event->type = SCHED_EVENT_SLEEP;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	sched->nr_sleep_events++;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic struct task_desc *register_pid(struct perf_sched *sched,
4478c2ecf20Sopenharmony_ci				      unsigned long pid, const char *comm)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct task_desc *task;
4508c2ecf20Sopenharmony_ci	static int pid_max;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (sched->pid_to_task == NULL) {
4538c2ecf20Sopenharmony_ci		if (sysctl__read_int("kernel/pid_max", &pid_max) < 0)
4548c2ecf20Sopenharmony_ci			pid_max = MAX_PID;
4558c2ecf20Sopenharmony_ci		BUG_ON((sched->pid_to_task = calloc(pid_max, sizeof(struct task_desc *))) == NULL);
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci	if (pid >= (unsigned long)pid_max) {
4588c2ecf20Sopenharmony_ci		BUG_ON((sched->pid_to_task = realloc(sched->pid_to_task, (pid + 1) *
4598c2ecf20Sopenharmony_ci			sizeof(struct task_desc *))) == NULL);
4608c2ecf20Sopenharmony_ci		while (pid >= (unsigned long)pid_max)
4618c2ecf20Sopenharmony_ci			sched->pid_to_task[pid_max++] = NULL;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	task = sched->pid_to_task[pid];
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (task)
4678c2ecf20Sopenharmony_ci		return task;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	task = zalloc(sizeof(*task));
4708c2ecf20Sopenharmony_ci	task->pid = pid;
4718c2ecf20Sopenharmony_ci	task->nr = sched->nr_tasks;
4728c2ecf20Sopenharmony_ci	strcpy(task->comm, comm);
4738c2ecf20Sopenharmony_ci	/*
4748c2ecf20Sopenharmony_ci	 * every task starts in sleeping state - this gets ignored
4758c2ecf20Sopenharmony_ci	 * if there's no wakeup pointing to this sleep state:
4768c2ecf20Sopenharmony_ci	 */
4778c2ecf20Sopenharmony_ci	add_sched_event_sleep(sched, task, 0, 0);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	sched->pid_to_task[pid] = task;
4808c2ecf20Sopenharmony_ci	sched->nr_tasks++;
4818c2ecf20Sopenharmony_ci	sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_desc *));
4828c2ecf20Sopenharmony_ci	BUG_ON(!sched->tasks);
4838c2ecf20Sopenharmony_ci	sched->tasks[task->nr] = task;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (verbose > 0)
4868c2ecf20Sopenharmony_ci		printf("registered task #%ld, PID %ld (%s)\n", sched->nr_tasks, pid, comm);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return task;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic void print_task_traces(struct perf_sched *sched)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct task_desc *task;
4958c2ecf20Sopenharmony_ci	unsigned long i;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	for (i = 0; i < sched->nr_tasks; i++) {
4988c2ecf20Sopenharmony_ci		task = sched->tasks[i];
4998c2ecf20Sopenharmony_ci		printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
5008c2ecf20Sopenharmony_ci			task->nr, task->comm, task->pid, task->nr_events);
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic void add_cross_task_wakeups(struct perf_sched *sched)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	struct task_desc *task1, *task2;
5078c2ecf20Sopenharmony_ci	unsigned long i, j;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i = 0; i < sched->nr_tasks; i++) {
5108c2ecf20Sopenharmony_ci		task1 = sched->tasks[i];
5118c2ecf20Sopenharmony_ci		j = i + 1;
5128c2ecf20Sopenharmony_ci		if (j == sched->nr_tasks)
5138c2ecf20Sopenharmony_ci			j = 0;
5148c2ecf20Sopenharmony_ci		task2 = sched->tasks[j];
5158c2ecf20Sopenharmony_ci		add_sched_event_wakeup(sched, task1, 0, task2);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic void perf_sched__process_event(struct perf_sched *sched,
5208c2ecf20Sopenharmony_ci				      struct sched_atom *atom)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	int ret = 0;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	switch (atom->type) {
5258c2ecf20Sopenharmony_ci		case SCHED_EVENT_RUN:
5268c2ecf20Sopenharmony_ci			burn_nsecs(sched, atom->duration);
5278c2ecf20Sopenharmony_ci			break;
5288c2ecf20Sopenharmony_ci		case SCHED_EVENT_SLEEP:
5298c2ecf20Sopenharmony_ci			if (atom->wait_sem)
5308c2ecf20Sopenharmony_ci				ret = sem_wait(atom->wait_sem);
5318c2ecf20Sopenharmony_ci			BUG_ON(ret);
5328c2ecf20Sopenharmony_ci			break;
5338c2ecf20Sopenharmony_ci		case SCHED_EVENT_WAKEUP:
5348c2ecf20Sopenharmony_ci			if (atom->wait_sem)
5358c2ecf20Sopenharmony_ci				ret = sem_post(atom->wait_sem);
5368c2ecf20Sopenharmony_ci			BUG_ON(ret);
5378c2ecf20Sopenharmony_ci			break;
5388c2ecf20Sopenharmony_ci		case SCHED_EVENT_MIGRATION:
5398c2ecf20Sopenharmony_ci			break;
5408c2ecf20Sopenharmony_ci		default:
5418c2ecf20Sopenharmony_ci			BUG_ON(1);
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic u64 get_cpu_usage_nsec_parent(void)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct rusage ru;
5488c2ecf20Sopenharmony_ci	u64 sum;
5498c2ecf20Sopenharmony_ci	int err;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	err = getrusage(RUSAGE_SELF, &ru);
5528c2ecf20Sopenharmony_ci	BUG_ON(err);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	sum =  ru.ru_utime.tv_sec * NSEC_PER_SEC + ru.ru_utime.tv_usec * NSEC_PER_USEC;
5558c2ecf20Sopenharmony_ci	sum += ru.ru_stime.tv_sec * NSEC_PER_SEC + ru.ru_stime.tv_usec * NSEC_PER_USEC;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return sum;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int self_open_counters(struct perf_sched *sched, unsigned long cur_task)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct perf_event_attr attr;
5638c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE], info[STRERR_BUFSIZE];
5648c2ecf20Sopenharmony_ci	int fd;
5658c2ecf20Sopenharmony_ci	struct rlimit limit;
5668c2ecf20Sopenharmony_ci	bool need_privilege = false;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	memset(&attr, 0, sizeof(attr));
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	attr.type = PERF_TYPE_SOFTWARE;
5718c2ecf20Sopenharmony_ci	attr.config = PERF_COUNT_SW_TASK_CLOCK;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ciforce_again:
5748c2ecf20Sopenharmony_ci	fd = sys_perf_event_open(&attr, 0, -1, -1,
5758c2ecf20Sopenharmony_ci				 perf_event_open_cloexec_flag());
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (fd < 0) {
5788c2ecf20Sopenharmony_ci		if (errno == EMFILE) {
5798c2ecf20Sopenharmony_ci			if (sched->force) {
5808c2ecf20Sopenharmony_ci				BUG_ON(getrlimit(RLIMIT_NOFILE, &limit) == -1);
5818c2ecf20Sopenharmony_ci				limit.rlim_cur += sched->nr_tasks - cur_task;
5828c2ecf20Sopenharmony_ci				if (limit.rlim_cur > limit.rlim_max) {
5838c2ecf20Sopenharmony_ci					limit.rlim_max = limit.rlim_cur;
5848c2ecf20Sopenharmony_ci					need_privilege = true;
5858c2ecf20Sopenharmony_ci				}
5868c2ecf20Sopenharmony_ci				if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
5878c2ecf20Sopenharmony_ci					if (need_privilege && errno == EPERM)
5888c2ecf20Sopenharmony_ci						strcpy(info, "Need privilege\n");
5898c2ecf20Sopenharmony_ci				} else
5908c2ecf20Sopenharmony_ci					goto force_again;
5918c2ecf20Sopenharmony_ci			} else
5928c2ecf20Sopenharmony_ci				strcpy(info, "Have a try with -f option\n");
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci		pr_err("Error: sys_perf_event_open() syscall returned "
5958c2ecf20Sopenharmony_ci		       "with %d (%s)\n%s", fd,
5968c2ecf20Sopenharmony_ci		       str_error_r(errno, sbuf, sizeof(sbuf)), info);
5978c2ecf20Sopenharmony_ci		exit(EXIT_FAILURE);
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci	return fd;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic u64 get_cpu_usage_nsec_self(int fd)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	u64 runtime;
6058c2ecf20Sopenharmony_ci	int ret;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	ret = read(fd, &runtime, sizeof(runtime));
6088c2ecf20Sopenharmony_ci	BUG_ON(ret != sizeof(runtime));
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return runtime;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistruct sched_thread_parms {
6148c2ecf20Sopenharmony_ci	struct task_desc  *task;
6158c2ecf20Sopenharmony_ci	struct perf_sched *sched;
6168c2ecf20Sopenharmony_ci	int fd;
6178c2ecf20Sopenharmony_ci};
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic void *thread_func(void *ctx)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct sched_thread_parms *parms = ctx;
6228c2ecf20Sopenharmony_ci	struct task_desc *this_task = parms->task;
6238c2ecf20Sopenharmony_ci	struct perf_sched *sched = parms->sched;
6248c2ecf20Sopenharmony_ci	u64 cpu_usage_0, cpu_usage_1;
6258c2ecf20Sopenharmony_ci	unsigned long i, ret;
6268c2ecf20Sopenharmony_ci	char comm2[22];
6278c2ecf20Sopenharmony_ci	int fd = parms->fd;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	zfree(&parms);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	sprintf(comm2, ":%s", this_task->comm);
6328c2ecf20Sopenharmony_ci	prctl(PR_SET_NAME, comm2);
6338c2ecf20Sopenharmony_ci	if (fd < 0)
6348c2ecf20Sopenharmony_ci		return NULL;
6358c2ecf20Sopenharmony_ciagain:
6368c2ecf20Sopenharmony_ci	ret = sem_post(&this_task->ready_for_work);
6378c2ecf20Sopenharmony_ci	BUG_ON(ret);
6388c2ecf20Sopenharmony_ci	ret = pthread_mutex_lock(&sched->start_work_mutex);
6398c2ecf20Sopenharmony_ci	BUG_ON(ret);
6408c2ecf20Sopenharmony_ci	ret = pthread_mutex_unlock(&sched->start_work_mutex);
6418c2ecf20Sopenharmony_ci	BUG_ON(ret);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	cpu_usage_0 = get_cpu_usage_nsec_self(fd);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	for (i = 0; i < this_task->nr_events; i++) {
6468c2ecf20Sopenharmony_ci		this_task->curr_event = i;
6478c2ecf20Sopenharmony_ci		perf_sched__process_event(sched, this_task->atoms[i]);
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	cpu_usage_1 = get_cpu_usage_nsec_self(fd);
6518c2ecf20Sopenharmony_ci	this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
6528c2ecf20Sopenharmony_ci	ret = sem_post(&this_task->work_done_sem);
6538c2ecf20Sopenharmony_ci	BUG_ON(ret);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
6568c2ecf20Sopenharmony_ci	BUG_ON(ret);
6578c2ecf20Sopenharmony_ci	ret = pthread_mutex_unlock(&sched->work_done_wait_mutex);
6588c2ecf20Sopenharmony_ci	BUG_ON(ret);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	goto again;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic void create_tasks(struct perf_sched *sched)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	struct task_desc *task;
6668c2ecf20Sopenharmony_ci	pthread_attr_t attr;
6678c2ecf20Sopenharmony_ci	unsigned long i;
6688c2ecf20Sopenharmony_ci	int err;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	err = pthread_attr_init(&attr);
6718c2ecf20Sopenharmony_ci	BUG_ON(err);
6728c2ecf20Sopenharmony_ci	err = pthread_attr_setstacksize(&attr,
6738c2ecf20Sopenharmony_ci			(size_t) max(16 * 1024, (int)PTHREAD_STACK_MIN));
6748c2ecf20Sopenharmony_ci	BUG_ON(err);
6758c2ecf20Sopenharmony_ci	err = pthread_mutex_lock(&sched->start_work_mutex);
6768c2ecf20Sopenharmony_ci	BUG_ON(err);
6778c2ecf20Sopenharmony_ci	err = pthread_mutex_lock(&sched->work_done_wait_mutex);
6788c2ecf20Sopenharmony_ci	BUG_ON(err);
6798c2ecf20Sopenharmony_ci	for (i = 0; i < sched->nr_tasks; i++) {
6808c2ecf20Sopenharmony_ci		struct sched_thread_parms *parms = malloc(sizeof(*parms));
6818c2ecf20Sopenharmony_ci		BUG_ON(parms == NULL);
6828c2ecf20Sopenharmony_ci		parms->task = task = sched->tasks[i];
6838c2ecf20Sopenharmony_ci		parms->sched = sched;
6848c2ecf20Sopenharmony_ci		parms->fd = self_open_counters(sched, i);
6858c2ecf20Sopenharmony_ci		sem_init(&task->sleep_sem, 0, 0);
6868c2ecf20Sopenharmony_ci		sem_init(&task->ready_for_work, 0, 0);
6878c2ecf20Sopenharmony_ci		sem_init(&task->work_done_sem, 0, 0);
6888c2ecf20Sopenharmony_ci		task->curr_event = 0;
6898c2ecf20Sopenharmony_ci		err = pthread_create(&task->thread, &attr, thread_func, parms);
6908c2ecf20Sopenharmony_ci		BUG_ON(err);
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_cistatic void wait_for_tasks(struct perf_sched *sched)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	u64 cpu_usage_0, cpu_usage_1;
6978c2ecf20Sopenharmony_ci	struct task_desc *task;
6988c2ecf20Sopenharmony_ci	unsigned long i, ret;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	sched->start_time = get_nsecs();
7018c2ecf20Sopenharmony_ci	sched->cpu_usage = 0;
7028c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&sched->work_done_wait_mutex);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	for (i = 0; i < sched->nr_tasks; i++) {
7058c2ecf20Sopenharmony_ci		task = sched->tasks[i];
7068c2ecf20Sopenharmony_ci		ret = sem_wait(&task->ready_for_work);
7078c2ecf20Sopenharmony_ci		BUG_ON(ret);
7088c2ecf20Sopenharmony_ci		sem_init(&task->ready_for_work, 0, 0);
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci	ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
7118c2ecf20Sopenharmony_ci	BUG_ON(ret);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	cpu_usage_0 = get_cpu_usage_nsec_parent();
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&sched->start_work_mutex);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	for (i = 0; i < sched->nr_tasks; i++) {
7188c2ecf20Sopenharmony_ci		task = sched->tasks[i];
7198c2ecf20Sopenharmony_ci		ret = sem_wait(&task->work_done_sem);
7208c2ecf20Sopenharmony_ci		BUG_ON(ret);
7218c2ecf20Sopenharmony_ci		sem_init(&task->work_done_sem, 0, 0);
7228c2ecf20Sopenharmony_ci		sched->cpu_usage += task->cpu_usage;
7238c2ecf20Sopenharmony_ci		task->cpu_usage = 0;
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	cpu_usage_1 = get_cpu_usage_nsec_parent();
7278c2ecf20Sopenharmony_ci	if (!sched->runavg_cpu_usage)
7288c2ecf20Sopenharmony_ci		sched->runavg_cpu_usage = sched->cpu_usage;
7298c2ecf20Sopenharmony_ci	sched->runavg_cpu_usage = (sched->runavg_cpu_usage * (sched->replay_repeat - 1) + sched->cpu_usage) / sched->replay_repeat;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
7328c2ecf20Sopenharmony_ci	if (!sched->runavg_parent_cpu_usage)
7338c2ecf20Sopenharmony_ci		sched->runavg_parent_cpu_usage = sched->parent_cpu_usage;
7348c2ecf20Sopenharmony_ci	sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * (sched->replay_repeat - 1) +
7358c2ecf20Sopenharmony_ci					 sched->parent_cpu_usage)/sched->replay_repeat;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	ret = pthread_mutex_lock(&sched->start_work_mutex);
7388c2ecf20Sopenharmony_ci	BUG_ON(ret);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	for (i = 0; i < sched->nr_tasks; i++) {
7418c2ecf20Sopenharmony_ci		task = sched->tasks[i];
7428c2ecf20Sopenharmony_ci		sem_init(&task->sleep_sem, 0, 0);
7438c2ecf20Sopenharmony_ci		task->curr_event = 0;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cistatic void run_one_test(struct perf_sched *sched)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	u64 T0, T1, delta, avg_delta, fluct;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	T0 = get_nsecs();
7528c2ecf20Sopenharmony_ci	wait_for_tasks(sched);
7538c2ecf20Sopenharmony_ci	T1 = get_nsecs();
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	delta = T1 - T0;
7568c2ecf20Sopenharmony_ci	sched->sum_runtime += delta;
7578c2ecf20Sopenharmony_ci	sched->nr_runs++;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	avg_delta = sched->sum_runtime / sched->nr_runs;
7608c2ecf20Sopenharmony_ci	if (delta < avg_delta)
7618c2ecf20Sopenharmony_ci		fluct = avg_delta - delta;
7628c2ecf20Sopenharmony_ci	else
7638c2ecf20Sopenharmony_ci		fluct = delta - avg_delta;
7648c2ecf20Sopenharmony_ci	sched->sum_fluct += fluct;
7658c2ecf20Sopenharmony_ci	if (!sched->run_avg)
7668c2ecf20Sopenharmony_ci		sched->run_avg = delta;
7678c2ecf20Sopenharmony_ci	sched->run_avg = (sched->run_avg * (sched->replay_repeat - 1) + delta) / sched->replay_repeat;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / NSEC_PER_MSEC);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	printf("ravg: %0.2f, ", (double)sched->run_avg / NSEC_PER_MSEC);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	printf("cpu: %0.2f / %0.2f",
7748c2ecf20Sopenharmony_ci		(double)sched->cpu_usage / NSEC_PER_MSEC, (double)sched->runavg_cpu_usage / NSEC_PER_MSEC);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci#if 0
7778c2ecf20Sopenharmony_ci	/*
7788c2ecf20Sopenharmony_ci	 * rusage statistics done by the parent, these are less
7798c2ecf20Sopenharmony_ci	 * accurate than the sched->sum_exec_runtime based statistics:
7808c2ecf20Sopenharmony_ci	 */
7818c2ecf20Sopenharmony_ci	printf(" [%0.2f / %0.2f]",
7828c2ecf20Sopenharmony_ci		(double)sched->parent_cpu_usage / NSEC_PER_MSEC,
7838c2ecf20Sopenharmony_ci		(double)sched->runavg_parent_cpu_usage / NSEC_PER_MSEC);
7848c2ecf20Sopenharmony_ci#endif
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	printf("\n");
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (sched->nr_sleep_corrections)
7898c2ecf20Sopenharmony_ci		printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections);
7908c2ecf20Sopenharmony_ci	sched->nr_sleep_corrections = 0;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistatic void test_calibrations(struct perf_sched *sched)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	u64 T0, T1;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	T0 = get_nsecs();
7988c2ecf20Sopenharmony_ci	burn_nsecs(sched, NSEC_PER_MSEC);
7998c2ecf20Sopenharmony_ci	T1 = get_nsecs();
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	T0 = get_nsecs();
8048c2ecf20Sopenharmony_ci	sleep_nsecs(NSEC_PER_MSEC);
8058c2ecf20Sopenharmony_ci	T1 = get_nsecs();
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic int
8118c2ecf20Sopenharmony_cireplay_wakeup_event(struct perf_sched *sched,
8128c2ecf20Sopenharmony_ci		    struct evsel *evsel, struct perf_sample *sample,
8138c2ecf20Sopenharmony_ci		    struct machine *machine __maybe_unused)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	const char *comm = evsel__strval(evsel, sample, "comm");
8168c2ecf20Sopenharmony_ci	const u32 pid	 = evsel__intval(evsel, sample, "pid");
8178c2ecf20Sopenharmony_ci	struct task_desc *waker, *wakee;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	if (verbose > 0) {
8208c2ecf20Sopenharmony_ci		printf("sched_wakeup event %p\n", evsel);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci		printf(" ... pid %d woke up %s/%d\n", sample->tid, comm, pid);
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	waker = register_pid(sched, sample->tid, "<unknown>");
8268c2ecf20Sopenharmony_ci	wakee = register_pid(sched, pid, comm);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	add_sched_event_wakeup(sched, waker, sample->time, wakee);
8298c2ecf20Sopenharmony_ci	return 0;
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_cistatic int replay_switch_event(struct perf_sched *sched,
8338c2ecf20Sopenharmony_ci			       struct evsel *evsel,
8348c2ecf20Sopenharmony_ci			       struct perf_sample *sample,
8358c2ecf20Sopenharmony_ci			       struct machine *machine __maybe_unused)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	const char *prev_comm  = evsel__strval(evsel, sample, "prev_comm"),
8388c2ecf20Sopenharmony_ci		   *next_comm  = evsel__strval(evsel, sample, "next_comm");
8398c2ecf20Sopenharmony_ci	const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"),
8408c2ecf20Sopenharmony_ci		  next_pid = evsel__intval(evsel, sample, "next_pid");
8418c2ecf20Sopenharmony_ci	const u64 prev_state = evsel__intval(evsel, sample, "prev_state");
8428c2ecf20Sopenharmony_ci	struct task_desc *prev, __maybe_unused *next;
8438c2ecf20Sopenharmony_ci	u64 timestamp0, timestamp = sample->time;
8448c2ecf20Sopenharmony_ci	int cpu = sample->cpu;
8458c2ecf20Sopenharmony_ci	s64 delta;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (verbose > 0)
8488c2ecf20Sopenharmony_ci		printf("sched_switch event %p\n", evsel);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	if (cpu >= MAX_CPUS || cpu < 0)
8518c2ecf20Sopenharmony_ci		return 0;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	timestamp0 = sched->cpu_last_switched[cpu];
8548c2ecf20Sopenharmony_ci	if (timestamp0)
8558c2ecf20Sopenharmony_ci		delta = timestamp - timestamp0;
8568c2ecf20Sopenharmony_ci	else
8578c2ecf20Sopenharmony_ci		delta = 0;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (delta < 0) {
8608c2ecf20Sopenharmony_ci		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
8618c2ecf20Sopenharmony_ci		return -1;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	pr_debug(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
8658c2ecf20Sopenharmony_ci		 prev_comm, prev_pid, next_comm, next_pid, delta);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	prev = register_pid(sched, prev_pid, prev_comm);
8688c2ecf20Sopenharmony_ci	next = register_pid(sched, next_pid, next_comm);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	sched->cpu_last_switched[cpu] = timestamp;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	add_sched_event_run(sched, prev, timestamp, delta);
8738c2ecf20Sopenharmony_ci	add_sched_event_sleep(sched, prev, timestamp, prev_state);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	return 0;
8768c2ecf20Sopenharmony_ci}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic int replay_fork_event(struct perf_sched *sched,
8798c2ecf20Sopenharmony_ci			     union perf_event *event,
8808c2ecf20Sopenharmony_ci			     struct machine *machine)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	struct thread *child, *parent;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	child = machine__findnew_thread(machine, event->fork.pid,
8858c2ecf20Sopenharmony_ci					event->fork.tid);
8868c2ecf20Sopenharmony_ci	parent = machine__findnew_thread(machine, event->fork.ppid,
8878c2ecf20Sopenharmony_ci					 event->fork.ptid);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (child == NULL || parent == NULL) {
8908c2ecf20Sopenharmony_ci		pr_debug("thread does not exist on fork event: child %p, parent %p\n",
8918c2ecf20Sopenharmony_ci				 child, parent);
8928c2ecf20Sopenharmony_ci		goto out_put;
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (verbose > 0) {
8968c2ecf20Sopenharmony_ci		printf("fork event\n");
8978c2ecf20Sopenharmony_ci		printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
8988c2ecf20Sopenharmony_ci		printf("...  child: %s/%d\n", thread__comm_str(child), child->tid);
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	register_pid(sched, parent->tid, thread__comm_str(parent));
9028c2ecf20Sopenharmony_ci	register_pid(sched, child->tid, thread__comm_str(child));
9038c2ecf20Sopenharmony_ciout_put:
9048c2ecf20Sopenharmony_ci	thread__put(child);
9058c2ecf20Sopenharmony_ci	thread__put(parent);
9068c2ecf20Sopenharmony_ci	return 0;
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistruct sort_dimension {
9108c2ecf20Sopenharmony_ci	const char		*name;
9118c2ecf20Sopenharmony_ci	sort_fn_t		cmp;
9128c2ecf20Sopenharmony_ci	struct list_head	list;
9138c2ecf20Sopenharmony_ci};
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci/*
9168c2ecf20Sopenharmony_ci * handle runtime stats saved per thread
9178c2ecf20Sopenharmony_ci */
9188c2ecf20Sopenharmony_cistatic struct thread_runtime *thread__init_runtime(struct thread *thread)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	struct thread_runtime *r;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	r = zalloc(sizeof(struct thread_runtime));
9238c2ecf20Sopenharmony_ci	if (!r)
9248c2ecf20Sopenharmony_ci		return NULL;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	init_stats(&r->run_stats);
9278c2ecf20Sopenharmony_ci	thread__set_priv(thread, r);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	return r;
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic struct thread_runtime *thread__get_runtime(struct thread *thread)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct thread_runtime *tr;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	tr = thread__priv(thread);
9378c2ecf20Sopenharmony_ci	if (tr == NULL) {
9388c2ecf20Sopenharmony_ci		tr = thread__init_runtime(thread);
9398c2ecf20Sopenharmony_ci		if (tr == NULL)
9408c2ecf20Sopenharmony_ci			pr_debug("Failed to malloc memory for runtime data.\n");
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return tr;
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic int
9478c2ecf20Sopenharmony_cithread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	struct sort_dimension *sort;
9508c2ecf20Sopenharmony_ci	int ret = 0;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	BUG_ON(list_empty(list));
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	list_for_each_entry(sort, list, list) {
9558c2ecf20Sopenharmony_ci		ret = sort->cmp(l, r);
9568c2ecf20Sopenharmony_ci		if (ret)
9578c2ecf20Sopenharmony_ci			return ret;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	return ret;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic struct work_atoms *
9648c2ecf20Sopenharmony_cithread_atoms_search(struct rb_root_cached *root, struct thread *thread,
9658c2ecf20Sopenharmony_ci			 struct list_head *sort_list)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	struct rb_node *node = root->rb_root.rb_node;
9688c2ecf20Sopenharmony_ci	struct work_atoms key = { .thread = thread };
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	while (node) {
9718c2ecf20Sopenharmony_ci		struct work_atoms *atoms;
9728c2ecf20Sopenharmony_ci		int cmp;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		atoms = container_of(node, struct work_atoms, node);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		cmp = thread_lat_cmp(sort_list, &key, atoms);
9778c2ecf20Sopenharmony_ci		if (cmp > 0)
9788c2ecf20Sopenharmony_ci			node = node->rb_left;
9798c2ecf20Sopenharmony_ci		else if (cmp < 0)
9808c2ecf20Sopenharmony_ci			node = node->rb_right;
9818c2ecf20Sopenharmony_ci		else {
9828c2ecf20Sopenharmony_ci			BUG_ON(thread != atoms->thread);
9838c2ecf20Sopenharmony_ci			return atoms;
9848c2ecf20Sopenharmony_ci		}
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ci	return NULL;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_cistatic void
9908c2ecf20Sopenharmony_ci__thread_latency_insert(struct rb_root_cached *root, struct work_atoms *data,
9918c2ecf20Sopenharmony_ci			 struct list_head *sort_list)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
9948c2ecf20Sopenharmony_ci	bool leftmost = true;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	while (*new) {
9978c2ecf20Sopenharmony_ci		struct work_atoms *this;
9988c2ecf20Sopenharmony_ci		int cmp;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci		this = container_of(*new, struct work_atoms, node);
10018c2ecf20Sopenharmony_ci		parent = *new;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci		cmp = thread_lat_cmp(sort_list, data, this);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		if (cmp > 0)
10068c2ecf20Sopenharmony_ci			new = &((*new)->rb_left);
10078c2ecf20Sopenharmony_ci		else {
10088c2ecf20Sopenharmony_ci			new = &((*new)->rb_right);
10098c2ecf20Sopenharmony_ci			leftmost = false;
10108c2ecf20Sopenharmony_ci		}
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	rb_link_node(&data->node, parent, new);
10148c2ecf20Sopenharmony_ci	rb_insert_color_cached(&data->node, root, leftmost);
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct work_atoms *atoms = zalloc(sizeof(*atoms));
10208c2ecf20Sopenharmony_ci	if (!atoms) {
10218c2ecf20Sopenharmony_ci		pr_err("No memory at %s\n", __func__);
10228c2ecf20Sopenharmony_ci		return -1;
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	atoms->thread = thread__get(thread);
10268c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&atoms->work_list);
10278c2ecf20Sopenharmony_ci	__thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
10288c2ecf20Sopenharmony_ci	return 0;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic char sched_out_state(u64 prev_state)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	const char *str = TASK_STATE_TO_CHAR_STR;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return str[prev_state];
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic int
10398c2ecf20Sopenharmony_ciadd_sched_out_event(struct work_atoms *atoms,
10408c2ecf20Sopenharmony_ci		    char run_state,
10418c2ecf20Sopenharmony_ci		    u64 timestamp)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	struct work_atom *atom = zalloc(sizeof(*atom));
10448c2ecf20Sopenharmony_ci	if (!atom) {
10458c2ecf20Sopenharmony_ci		pr_err("Non memory at %s", __func__);
10468c2ecf20Sopenharmony_ci		return -1;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	atom->sched_out_time = timestamp;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	if (run_state == 'R') {
10528c2ecf20Sopenharmony_ci		atom->state = THREAD_WAIT_CPU;
10538c2ecf20Sopenharmony_ci		atom->wake_up_time = atom->sched_out_time;
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	list_add_tail(&atom->list, &atoms->work_list);
10578c2ecf20Sopenharmony_ci	return 0;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic void
10618c2ecf20Sopenharmony_ciadd_runtime_event(struct work_atoms *atoms, u64 delta,
10628c2ecf20Sopenharmony_ci		  u64 timestamp __maybe_unused)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	struct work_atom *atom;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	BUG_ON(list_empty(&atoms->work_list));
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	atom->runtime += delta;
10718c2ecf20Sopenharmony_ci	atoms->total_runtime += delta;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic void
10758c2ecf20Sopenharmony_ciadd_sched_in_event(struct work_atoms *atoms, u64 timestamp)
10768c2ecf20Sopenharmony_ci{
10778c2ecf20Sopenharmony_ci	struct work_atom *atom;
10788c2ecf20Sopenharmony_ci	u64 delta;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (list_empty(&atoms->work_list))
10818c2ecf20Sopenharmony_ci		return;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (atom->state != THREAD_WAIT_CPU)
10868c2ecf20Sopenharmony_ci		return;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (timestamp < atom->wake_up_time) {
10898c2ecf20Sopenharmony_ci		atom->state = THREAD_IGNORE;
10908c2ecf20Sopenharmony_ci		return;
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	atom->state = THREAD_SCHED_IN;
10948c2ecf20Sopenharmony_ci	atom->sched_in_time = timestamp;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	delta = atom->sched_in_time - atom->wake_up_time;
10978c2ecf20Sopenharmony_ci	atoms->total_lat += delta;
10988c2ecf20Sopenharmony_ci	if (delta > atoms->max_lat) {
10998c2ecf20Sopenharmony_ci		atoms->max_lat = delta;
11008c2ecf20Sopenharmony_ci		atoms->max_lat_start = atom->wake_up_time;
11018c2ecf20Sopenharmony_ci		atoms->max_lat_end = timestamp;
11028c2ecf20Sopenharmony_ci	}
11038c2ecf20Sopenharmony_ci	atoms->nb_atoms++;
11048c2ecf20Sopenharmony_ci}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic int latency_switch_event(struct perf_sched *sched,
11078c2ecf20Sopenharmony_ci				struct evsel *evsel,
11088c2ecf20Sopenharmony_ci				struct perf_sample *sample,
11098c2ecf20Sopenharmony_ci				struct machine *machine)
11108c2ecf20Sopenharmony_ci{
11118c2ecf20Sopenharmony_ci	const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"),
11128c2ecf20Sopenharmony_ci		  next_pid = evsel__intval(evsel, sample, "next_pid");
11138c2ecf20Sopenharmony_ci	const u64 prev_state = evsel__intval(evsel, sample, "prev_state");
11148c2ecf20Sopenharmony_ci	struct work_atoms *out_events, *in_events;
11158c2ecf20Sopenharmony_ci	struct thread *sched_out, *sched_in;
11168c2ecf20Sopenharmony_ci	u64 timestamp0, timestamp = sample->time;
11178c2ecf20Sopenharmony_ci	int cpu = sample->cpu, err = -1;
11188c2ecf20Sopenharmony_ci	s64 delta;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	timestamp0 = sched->cpu_last_switched[cpu];
11238c2ecf20Sopenharmony_ci	sched->cpu_last_switched[cpu] = timestamp;
11248c2ecf20Sopenharmony_ci	if (timestamp0)
11258c2ecf20Sopenharmony_ci		delta = timestamp - timestamp0;
11268c2ecf20Sopenharmony_ci	else
11278c2ecf20Sopenharmony_ci		delta = 0;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	if (delta < 0) {
11308c2ecf20Sopenharmony_ci		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
11318c2ecf20Sopenharmony_ci		return -1;
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	sched_out = machine__findnew_thread(machine, -1, prev_pid);
11358c2ecf20Sopenharmony_ci	sched_in = machine__findnew_thread(machine, -1, next_pid);
11368c2ecf20Sopenharmony_ci	if (sched_out == NULL || sched_in == NULL)
11378c2ecf20Sopenharmony_ci		goto out_put;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
11408c2ecf20Sopenharmony_ci	if (!out_events) {
11418c2ecf20Sopenharmony_ci		if (thread_atoms_insert(sched, sched_out))
11428c2ecf20Sopenharmony_ci			goto out_put;
11438c2ecf20Sopenharmony_ci		out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
11448c2ecf20Sopenharmony_ci		if (!out_events) {
11458c2ecf20Sopenharmony_ci			pr_err("out-event: Internal tree error");
11468c2ecf20Sopenharmony_ci			goto out_put;
11478c2ecf20Sopenharmony_ci		}
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci	if (add_sched_out_event(out_events, sched_out_state(prev_state), timestamp))
11508c2ecf20Sopenharmony_ci		return -1;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
11538c2ecf20Sopenharmony_ci	if (!in_events) {
11548c2ecf20Sopenharmony_ci		if (thread_atoms_insert(sched, sched_in))
11558c2ecf20Sopenharmony_ci			goto out_put;
11568c2ecf20Sopenharmony_ci		in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
11578c2ecf20Sopenharmony_ci		if (!in_events) {
11588c2ecf20Sopenharmony_ci			pr_err("in-event: Internal tree error");
11598c2ecf20Sopenharmony_ci			goto out_put;
11608c2ecf20Sopenharmony_ci		}
11618c2ecf20Sopenharmony_ci		/*
11628c2ecf20Sopenharmony_ci		 * Take came in we have not heard about yet,
11638c2ecf20Sopenharmony_ci		 * add in an initial atom in runnable state:
11648c2ecf20Sopenharmony_ci		 */
11658c2ecf20Sopenharmony_ci		if (add_sched_out_event(in_events, 'R', timestamp))
11668c2ecf20Sopenharmony_ci			goto out_put;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci	add_sched_in_event(in_events, timestamp);
11698c2ecf20Sopenharmony_ci	err = 0;
11708c2ecf20Sopenharmony_ciout_put:
11718c2ecf20Sopenharmony_ci	thread__put(sched_out);
11728c2ecf20Sopenharmony_ci	thread__put(sched_in);
11738c2ecf20Sopenharmony_ci	return err;
11748c2ecf20Sopenharmony_ci}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_cistatic int latency_runtime_event(struct perf_sched *sched,
11778c2ecf20Sopenharmony_ci				 struct evsel *evsel,
11788c2ecf20Sopenharmony_ci				 struct perf_sample *sample,
11798c2ecf20Sopenharmony_ci				 struct machine *machine)
11808c2ecf20Sopenharmony_ci{
11818c2ecf20Sopenharmony_ci	const u32 pid	   = evsel__intval(evsel, sample, "pid");
11828c2ecf20Sopenharmony_ci	const u64 runtime  = evsel__intval(evsel, sample, "runtime");
11838c2ecf20Sopenharmony_ci	struct thread *thread = machine__findnew_thread(machine, -1, pid);
11848c2ecf20Sopenharmony_ci	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
11858c2ecf20Sopenharmony_ci	u64 timestamp = sample->time;
11868c2ecf20Sopenharmony_ci	int cpu = sample->cpu, err = -1;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (thread == NULL)
11898c2ecf20Sopenharmony_ci		return -1;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
11928c2ecf20Sopenharmony_ci	if (!atoms) {
11938c2ecf20Sopenharmony_ci		if (thread_atoms_insert(sched, thread))
11948c2ecf20Sopenharmony_ci			goto out_put;
11958c2ecf20Sopenharmony_ci		atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
11968c2ecf20Sopenharmony_ci		if (!atoms) {
11978c2ecf20Sopenharmony_ci			pr_err("in-event: Internal tree error");
11988c2ecf20Sopenharmony_ci			goto out_put;
11998c2ecf20Sopenharmony_ci		}
12008c2ecf20Sopenharmony_ci		if (add_sched_out_event(atoms, 'R', timestamp))
12018c2ecf20Sopenharmony_ci			goto out_put;
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	add_runtime_event(atoms, runtime, timestamp);
12058c2ecf20Sopenharmony_ci	err = 0;
12068c2ecf20Sopenharmony_ciout_put:
12078c2ecf20Sopenharmony_ci	thread__put(thread);
12088c2ecf20Sopenharmony_ci	return err;
12098c2ecf20Sopenharmony_ci}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_cistatic int latency_wakeup_event(struct perf_sched *sched,
12128c2ecf20Sopenharmony_ci				struct evsel *evsel,
12138c2ecf20Sopenharmony_ci				struct perf_sample *sample,
12148c2ecf20Sopenharmony_ci				struct machine *machine)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	const u32 pid	  = evsel__intval(evsel, sample, "pid");
12178c2ecf20Sopenharmony_ci	struct work_atoms *atoms;
12188c2ecf20Sopenharmony_ci	struct work_atom *atom;
12198c2ecf20Sopenharmony_ci	struct thread *wakee;
12208c2ecf20Sopenharmony_ci	u64 timestamp = sample->time;
12218c2ecf20Sopenharmony_ci	int err = -1;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	wakee = machine__findnew_thread(machine, -1, pid);
12248c2ecf20Sopenharmony_ci	if (wakee == NULL)
12258c2ecf20Sopenharmony_ci		return -1;
12268c2ecf20Sopenharmony_ci	atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
12278c2ecf20Sopenharmony_ci	if (!atoms) {
12288c2ecf20Sopenharmony_ci		if (thread_atoms_insert(sched, wakee))
12298c2ecf20Sopenharmony_ci			goto out_put;
12308c2ecf20Sopenharmony_ci		atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
12318c2ecf20Sopenharmony_ci		if (!atoms) {
12328c2ecf20Sopenharmony_ci			pr_err("wakeup-event: Internal tree error");
12338c2ecf20Sopenharmony_ci			goto out_put;
12348c2ecf20Sopenharmony_ci		}
12358c2ecf20Sopenharmony_ci		if (add_sched_out_event(atoms, 'S', timestamp))
12368c2ecf20Sopenharmony_ci			goto out_put;
12378c2ecf20Sopenharmony_ci	}
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	BUG_ON(list_empty(&atoms->work_list));
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	/*
12448c2ecf20Sopenharmony_ci	 * As we do not guarantee the wakeup event happens when
12458c2ecf20Sopenharmony_ci	 * task is out of run queue, also may happen when task is
12468c2ecf20Sopenharmony_ci	 * on run queue and wakeup only change ->state to TASK_RUNNING,
12478c2ecf20Sopenharmony_ci	 * then we should not set the ->wake_up_time when wake up a
12488c2ecf20Sopenharmony_ci	 * task which is on run queue.
12498c2ecf20Sopenharmony_ci	 *
12508c2ecf20Sopenharmony_ci	 * You WILL be missing events if you've recorded only
12518c2ecf20Sopenharmony_ci	 * one CPU, or are only looking at only one, so don't
12528c2ecf20Sopenharmony_ci	 * skip in this case.
12538c2ecf20Sopenharmony_ci	 */
12548c2ecf20Sopenharmony_ci	if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING)
12558c2ecf20Sopenharmony_ci		goto out_ok;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	sched->nr_timestamps++;
12588c2ecf20Sopenharmony_ci	if (atom->sched_out_time > timestamp) {
12598c2ecf20Sopenharmony_ci		sched->nr_unordered_timestamps++;
12608c2ecf20Sopenharmony_ci		goto out_ok;
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	atom->state = THREAD_WAIT_CPU;
12648c2ecf20Sopenharmony_ci	atom->wake_up_time = timestamp;
12658c2ecf20Sopenharmony_ciout_ok:
12668c2ecf20Sopenharmony_ci	err = 0;
12678c2ecf20Sopenharmony_ciout_put:
12688c2ecf20Sopenharmony_ci	thread__put(wakee);
12698c2ecf20Sopenharmony_ci	return err;
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic int latency_migrate_task_event(struct perf_sched *sched,
12738c2ecf20Sopenharmony_ci				      struct evsel *evsel,
12748c2ecf20Sopenharmony_ci				      struct perf_sample *sample,
12758c2ecf20Sopenharmony_ci				      struct machine *machine)
12768c2ecf20Sopenharmony_ci{
12778c2ecf20Sopenharmony_ci	const u32 pid = evsel__intval(evsel, sample, "pid");
12788c2ecf20Sopenharmony_ci	u64 timestamp = sample->time;
12798c2ecf20Sopenharmony_ci	struct work_atoms *atoms;
12808c2ecf20Sopenharmony_ci	struct work_atom *atom;
12818c2ecf20Sopenharmony_ci	struct thread *migrant;
12828c2ecf20Sopenharmony_ci	int err = -1;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	/*
12858c2ecf20Sopenharmony_ci	 * Only need to worry about migration when profiling one CPU.
12868c2ecf20Sopenharmony_ci	 */
12878c2ecf20Sopenharmony_ci	if (sched->profile_cpu == -1)
12888c2ecf20Sopenharmony_ci		return 0;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	migrant = machine__findnew_thread(machine, -1, pid);
12918c2ecf20Sopenharmony_ci	if (migrant == NULL)
12928c2ecf20Sopenharmony_ci		return -1;
12938c2ecf20Sopenharmony_ci	atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
12948c2ecf20Sopenharmony_ci	if (!atoms) {
12958c2ecf20Sopenharmony_ci		if (thread_atoms_insert(sched, migrant))
12968c2ecf20Sopenharmony_ci			goto out_put;
12978c2ecf20Sopenharmony_ci		register_pid(sched, migrant->tid, thread__comm_str(migrant));
12988c2ecf20Sopenharmony_ci		atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
12998c2ecf20Sopenharmony_ci		if (!atoms) {
13008c2ecf20Sopenharmony_ci			pr_err("migration-event: Internal tree error");
13018c2ecf20Sopenharmony_ci			goto out_put;
13028c2ecf20Sopenharmony_ci		}
13038c2ecf20Sopenharmony_ci		if (add_sched_out_event(atoms, 'R', timestamp))
13048c2ecf20Sopenharmony_ci			goto out_put;
13058c2ecf20Sopenharmony_ci	}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	BUG_ON(list_empty(&atoms->work_list));
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	atom = list_entry(atoms->work_list.prev, struct work_atom, list);
13108c2ecf20Sopenharmony_ci	atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	sched->nr_timestamps++;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if (atom->sched_out_time > timestamp)
13158c2ecf20Sopenharmony_ci		sched->nr_unordered_timestamps++;
13168c2ecf20Sopenharmony_ci	err = 0;
13178c2ecf20Sopenharmony_ciout_put:
13188c2ecf20Sopenharmony_ci	thread__put(migrant);
13198c2ecf20Sopenharmony_ci	return err;
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cistatic void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_list)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	int i;
13258c2ecf20Sopenharmony_ci	int ret;
13268c2ecf20Sopenharmony_ci	u64 avg;
13278c2ecf20Sopenharmony_ci	char max_lat_start[32], max_lat_end[32];
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (!work_list->nb_atoms)
13308c2ecf20Sopenharmony_ci		return;
13318c2ecf20Sopenharmony_ci	/*
13328c2ecf20Sopenharmony_ci	 * Ignore idle threads:
13338c2ecf20Sopenharmony_ci	 */
13348c2ecf20Sopenharmony_ci	if (!strcmp(thread__comm_str(work_list->thread), "swapper"))
13358c2ecf20Sopenharmony_ci		return;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	sched->all_runtime += work_list->total_runtime;
13388c2ecf20Sopenharmony_ci	sched->all_count   += work_list->nb_atoms;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	if (work_list->num_merged > 1)
13418c2ecf20Sopenharmony_ci		ret = printf("  %s:(%d) ", thread__comm_str(work_list->thread), work_list->num_merged);
13428c2ecf20Sopenharmony_ci	else
13438c2ecf20Sopenharmony_ci		ret = printf("  %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid);
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	for (i = 0; i < 24 - ret; i++)
13468c2ecf20Sopenharmony_ci		printf(" ");
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	avg = work_list->total_lat / work_list->nb_atoms;
13498c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(work_list->max_lat_start, max_lat_start, sizeof(max_lat_start));
13508c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(work_list->max_lat_end, max_lat_end, sizeof(max_lat_end));
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	printf("|%11.3f ms |%9" PRIu64 " | avg:%8.3f ms | max:%8.3f ms | max start: %12s s | max end: %12s s\n",
13538c2ecf20Sopenharmony_ci	      (double)work_list->total_runtime / NSEC_PER_MSEC,
13548c2ecf20Sopenharmony_ci		 work_list->nb_atoms, (double)avg / NSEC_PER_MSEC,
13558c2ecf20Sopenharmony_ci		 (double)work_list->max_lat / NSEC_PER_MSEC,
13568c2ecf20Sopenharmony_ci		 max_lat_start, max_lat_end);
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_cistatic int pid_cmp(struct work_atoms *l, struct work_atoms *r)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	if (l->thread == r->thread)
13628c2ecf20Sopenharmony_ci		return 0;
13638c2ecf20Sopenharmony_ci	if (l->thread->tid < r->thread->tid)
13648c2ecf20Sopenharmony_ci		return -1;
13658c2ecf20Sopenharmony_ci	if (l->thread->tid > r->thread->tid)
13668c2ecf20Sopenharmony_ci		return 1;
13678c2ecf20Sopenharmony_ci	return (int)(l->thread - r->thread);
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_cistatic int avg_cmp(struct work_atoms *l, struct work_atoms *r)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	u64 avgl, avgr;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	if (!l->nb_atoms)
13758c2ecf20Sopenharmony_ci		return -1;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	if (!r->nb_atoms)
13788c2ecf20Sopenharmony_ci		return 1;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	avgl = l->total_lat / l->nb_atoms;
13818c2ecf20Sopenharmony_ci	avgr = r->total_lat / r->nb_atoms;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	if (avgl < avgr)
13848c2ecf20Sopenharmony_ci		return -1;
13858c2ecf20Sopenharmony_ci	if (avgl > avgr)
13868c2ecf20Sopenharmony_ci		return 1;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	return 0;
13898c2ecf20Sopenharmony_ci}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_cistatic int max_cmp(struct work_atoms *l, struct work_atoms *r)
13928c2ecf20Sopenharmony_ci{
13938c2ecf20Sopenharmony_ci	if (l->max_lat < r->max_lat)
13948c2ecf20Sopenharmony_ci		return -1;
13958c2ecf20Sopenharmony_ci	if (l->max_lat > r->max_lat)
13968c2ecf20Sopenharmony_ci		return 1;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	return 0;
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic int switch_cmp(struct work_atoms *l, struct work_atoms *r)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	if (l->nb_atoms < r->nb_atoms)
14048c2ecf20Sopenharmony_ci		return -1;
14058c2ecf20Sopenharmony_ci	if (l->nb_atoms > r->nb_atoms)
14068c2ecf20Sopenharmony_ci		return 1;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	return 0;
14098c2ecf20Sopenharmony_ci}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_cistatic int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
14128c2ecf20Sopenharmony_ci{
14138c2ecf20Sopenharmony_ci	if (l->total_runtime < r->total_runtime)
14148c2ecf20Sopenharmony_ci		return -1;
14158c2ecf20Sopenharmony_ci	if (l->total_runtime > r->total_runtime)
14168c2ecf20Sopenharmony_ci		return 1;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	return 0;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_cistatic int sort_dimension__add(const char *tok, struct list_head *list)
14228c2ecf20Sopenharmony_ci{
14238c2ecf20Sopenharmony_ci	size_t i;
14248c2ecf20Sopenharmony_ci	static struct sort_dimension avg_sort_dimension = {
14258c2ecf20Sopenharmony_ci		.name = "avg",
14268c2ecf20Sopenharmony_ci		.cmp  = avg_cmp,
14278c2ecf20Sopenharmony_ci	};
14288c2ecf20Sopenharmony_ci	static struct sort_dimension max_sort_dimension = {
14298c2ecf20Sopenharmony_ci		.name = "max",
14308c2ecf20Sopenharmony_ci		.cmp  = max_cmp,
14318c2ecf20Sopenharmony_ci	};
14328c2ecf20Sopenharmony_ci	static struct sort_dimension pid_sort_dimension = {
14338c2ecf20Sopenharmony_ci		.name = "pid",
14348c2ecf20Sopenharmony_ci		.cmp  = pid_cmp,
14358c2ecf20Sopenharmony_ci	};
14368c2ecf20Sopenharmony_ci	static struct sort_dimension runtime_sort_dimension = {
14378c2ecf20Sopenharmony_ci		.name = "runtime",
14388c2ecf20Sopenharmony_ci		.cmp  = runtime_cmp,
14398c2ecf20Sopenharmony_ci	};
14408c2ecf20Sopenharmony_ci	static struct sort_dimension switch_sort_dimension = {
14418c2ecf20Sopenharmony_ci		.name = "switch",
14428c2ecf20Sopenharmony_ci		.cmp  = switch_cmp,
14438c2ecf20Sopenharmony_ci	};
14448c2ecf20Sopenharmony_ci	struct sort_dimension *available_sorts[] = {
14458c2ecf20Sopenharmony_ci		&pid_sort_dimension,
14468c2ecf20Sopenharmony_ci		&avg_sort_dimension,
14478c2ecf20Sopenharmony_ci		&max_sort_dimension,
14488c2ecf20Sopenharmony_ci		&switch_sort_dimension,
14498c2ecf20Sopenharmony_ci		&runtime_sort_dimension,
14508c2ecf20Sopenharmony_ci	};
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(available_sorts); i++) {
14538c2ecf20Sopenharmony_ci		if (!strcmp(available_sorts[i]->name, tok)) {
14548c2ecf20Sopenharmony_ci			list_add_tail(&available_sorts[i]->list, list);
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci			return 0;
14578c2ecf20Sopenharmony_ci		}
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	return -1;
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic void perf_sched__sort_lat(struct perf_sched *sched)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct rb_node *node;
14668c2ecf20Sopenharmony_ci	struct rb_root_cached *root = &sched->atom_root;
14678c2ecf20Sopenharmony_ciagain:
14688c2ecf20Sopenharmony_ci	for (;;) {
14698c2ecf20Sopenharmony_ci		struct work_atoms *data;
14708c2ecf20Sopenharmony_ci		node = rb_first_cached(root);
14718c2ecf20Sopenharmony_ci		if (!node)
14728c2ecf20Sopenharmony_ci			break;
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci		rb_erase_cached(node, root);
14758c2ecf20Sopenharmony_ci		data = rb_entry(node, struct work_atoms, node);
14768c2ecf20Sopenharmony_ci		__thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list);
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci	if (root == &sched->atom_root) {
14798c2ecf20Sopenharmony_ci		root = &sched->merged_atom_root;
14808c2ecf20Sopenharmony_ci		goto again;
14818c2ecf20Sopenharmony_ci	}
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cistatic int process_sched_wakeup_event(struct perf_tool *tool,
14858c2ecf20Sopenharmony_ci				      struct evsel *evsel,
14868c2ecf20Sopenharmony_ci				      struct perf_sample *sample,
14878c2ecf20Sopenharmony_ci				      struct machine *machine)
14888c2ecf20Sopenharmony_ci{
14898c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	if (sched->tp_handler->wakeup_event)
14928c2ecf20Sopenharmony_ci		return sched->tp_handler->wakeup_event(sched, evsel, sample, machine);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	return 0;
14958c2ecf20Sopenharmony_ci}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ciunion map_priv {
14988c2ecf20Sopenharmony_ci	void	*ptr;
14998c2ecf20Sopenharmony_ci	bool	 color;
15008c2ecf20Sopenharmony_ci};
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_cistatic bool thread__has_color(struct thread *thread)
15038c2ecf20Sopenharmony_ci{
15048c2ecf20Sopenharmony_ci	union map_priv priv = {
15058c2ecf20Sopenharmony_ci		.ptr = thread__priv(thread),
15068c2ecf20Sopenharmony_ci	};
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	return priv.color;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_cistatic struct thread*
15128c2ecf20Sopenharmony_cimap__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid)
15138c2ecf20Sopenharmony_ci{
15148c2ecf20Sopenharmony_ci	struct thread *thread = machine__findnew_thread(machine, pid, tid);
15158c2ecf20Sopenharmony_ci	union map_priv priv = {
15168c2ecf20Sopenharmony_ci		.color = false,
15178c2ecf20Sopenharmony_ci	};
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	if (!sched->map.color_pids || !thread || thread__priv(thread))
15208c2ecf20Sopenharmony_ci		return thread;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	if (thread_map__has(sched->map.color_pids, tid))
15238c2ecf20Sopenharmony_ci		priv.color = true;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	thread__set_priv(thread, priv.ptr);
15268c2ecf20Sopenharmony_ci	return thread;
15278c2ecf20Sopenharmony_ci}
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_cistatic int map_switch_event(struct perf_sched *sched, struct evsel *evsel,
15308c2ecf20Sopenharmony_ci			    struct perf_sample *sample, struct machine *machine)
15318c2ecf20Sopenharmony_ci{
15328c2ecf20Sopenharmony_ci	const u32 next_pid = evsel__intval(evsel, sample, "next_pid");
15338c2ecf20Sopenharmony_ci	struct thread *sched_in;
15348c2ecf20Sopenharmony_ci	struct thread_runtime *tr;
15358c2ecf20Sopenharmony_ci	int new_shortname;
15368c2ecf20Sopenharmony_ci	u64 timestamp0, timestamp = sample->time;
15378c2ecf20Sopenharmony_ci	s64 delta;
15388c2ecf20Sopenharmony_ci	int i, this_cpu = sample->cpu;
15398c2ecf20Sopenharmony_ci	int cpus_nr;
15408c2ecf20Sopenharmony_ci	bool new_cpu = false;
15418c2ecf20Sopenharmony_ci	const char *color = PERF_COLOR_NORMAL;
15428c2ecf20Sopenharmony_ci	char stimestamp[32];
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	if (this_cpu > sched->max_cpu)
15478c2ecf20Sopenharmony_ci		sched->max_cpu = this_cpu;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	if (sched->map.comp) {
15508c2ecf20Sopenharmony_ci		cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS);
15518c2ecf20Sopenharmony_ci		if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) {
15528c2ecf20Sopenharmony_ci			sched->map.comp_cpus[cpus_nr++] = this_cpu;
15538c2ecf20Sopenharmony_ci			new_cpu = true;
15548c2ecf20Sopenharmony_ci		}
15558c2ecf20Sopenharmony_ci	} else
15568c2ecf20Sopenharmony_ci		cpus_nr = sched->max_cpu;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	timestamp0 = sched->cpu_last_switched[this_cpu];
15598c2ecf20Sopenharmony_ci	sched->cpu_last_switched[this_cpu] = timestamp;
15608c2ecf20Sopenharmony_ci	if (timestamp0)
15618c2ecf20Sopenharmony_ci		delta = timestamp - timestamp0;
15628c2ecf20Sopenharmony_ci	else
15638c2ecf20Sopenharmony_ci		delta = 0;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	if (delta < 0) {
15668c2ecf20Sopenharmony_ci		pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
15678c2ecf20Sopenharmony_ci		return -1;
15688c2ecf20Sopenharmony_ci	}
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	sched_in = map__findnew_thread(sched, machine, -1, next_pid);
15718c2ecf20Sopenharmony_ci	if (sched_in == NULL)
15728c2ecf20Sopenharmony_ci		return -1;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	tr = thread__get_runtime(sched_in);
15758c2ecf20Sopenharmony_ci	if (tr == NULL) {
15768c2ecf20Sopenharmony_ci		thread__put(sched_in);
15778c2ecf20Sopenharmony_ci		return -1;
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	sched->curr_thread[this_cpu] = thread__get(sched_in);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	printf("  ");
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	new_shortname = 0;
15858c2ecf20Sopenharmony_ci	if (!tr->shortname[0]) {
15868c2ecf20Sopenharmony_ci		if (!strcmp(thread__comm_str(sched_in), "swapper")) {
15878c2ecf20Sopenharmony_ci			/*
15888c2ecf20Sopenharmony_ci			 * Don't allocate a letter-number for swapper:0
15898c2ecf20Sopenharmony_ci			 * as a shortname. Instead, we use '.' for it.
15908c2ecf20Sopenharmony_ci			 */
15918c2ecf20Sopenharmony_ci			tr->shortname[0] = '.';
15928c2ecf20Sopenharmony_ci			tr->shortname[1] = ' ';
15938c2ecf20Sopenharmony_ci		} else {
15948c2ecf20Sopenharmony_ci			tr->shortname[0] = sched->next_shortname1;
15958c2ecf20Sopenharmony_ci			tr->shortname[1] = sched->next_shortname2;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci			if (sched->next_shortname1 < 'Z') {
15988c2ecf20Sopenharmony_ci				sched->next_shortname1++;
15998c2ecf20Sopenharmony_ci			} else {
16008c2ecf20Sopenharmony_ci				sched->next_shortname1 = 'A';
16018c2ecf20Sopenharmony_ci				if (sched->next_shortname2 < '9')
16028c2ecf20Sopenharmony_ci					sched->next_shortname2++;
16038c2ecf20Sopenharmony_ci				else
16048c2ecf20Sopenharmony_ci					sched->next_shortname2 = '0';
16058c2ecf20Sopenharmony_ci			}
16068c2ecf20Sopenharmony_ci		}
16078c2ecf20Sopenharmony_ci		new_shortname = 1;
16088c2ecf20Sopenharmony_ci	}
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	for (i = 0; i < cpus_nr; i++) {
16118c2ecf20Sopenharmony_ci		int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i;
16128c2ecf20Sopenharmony_ci		struct thread *curr_thread = sched->curr_thread[cpu];
16138c2ecf20Sopenharmony_ci		struct thread_runtime *curr_tr;
16148c2ecf20Sopenharmony_ci		const char *pid_color = color;
16158c2ecf20Sopenharmony_ci		const char *cpu_color = color;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci		if (curr_thread && thread__has_color(curr_thread))
16188c2ecf20Sopenharmony_ci			pid_color = COLOR_PIDS;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci		if (sched->map.cpus && !cpu_map__has(sched->map.cpus, cpu))
16218c2ecf20Sopenharmony_ci			continue;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci		if (sched->map.color_cpus && cpu_map__has(sched->map.color_cpus, cpu))
16248c2ecf20Sopenharmony_ci			cpu_color = COLOR_CPUS;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci		if (cpu != this_cpu)
16278c2ecf20Sopenharmony_ci			color_fprintf(stdout, color, " ");
16288c2ecf20Sopenharmony_ci		else
16298c2ecf20Sopenharmony_ci			color_fprintf(stdout, cpu_color, "*");
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci		if (sched->curr_thread[cpu]) {
16328c2ecf20Sopenharmony_ci			curr_tr = thread__get_runtime(sched->curr_thread[cpu]);
16338c2ecf20Sopenharmony_ci			if (curr_tr == NULL) {
16348c2ecf20Sopenharmony_ci				thread__put(sched_in);
16358c2ecf20Sopenharmony_ci				return -1;
16368c2ecf20Sopenharmony_ci			}
16378c2ecf20Sopenharmony_ci			color_fprintf(stdout, pid_color, "%2s ", curr_tr->shortname);
16388c2ecf20Sopenharmony_ci		} else
16398c2ecf20Sopenharmony_ci			color_fprintf(stdout, color, "   ");
16408c2ecf20Sopenharmony_ci	}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu))
16438c2ecf20Sopenharmony_ci		goto out;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(timestamp, stimestamp, sizeof(stimestamp));
16468c2ecf20Sopenharmony_ci	color_fprintf(stdout, color, "  %12s secs ", stimestamp);
16478c2ecf20Sopenharmony_ci	if (new_shortname || tr->comm_changed || (verbose > 0 && sched_in->tid)) {
16488c2ecf20Sopenharmony_ci		const char *pid_color = color;
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci		if (thread__has_color(sched_in))
16518c2ecf20Sopenharmony_ci			pid_color = COLOR_PIDS;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci		color_fprintf(stdout, pid_color, "%s => %s:%d",
16548c2ecf20Sopenharmony_ci		       tr->shortname, thread__comm_str(sched_in), sched_in->tid);
16558c2ecf20Sopenharmony_ci		tr->comm_changed = false;
16568c2ecf20Sopenharmony_ci	}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	if (sched->map.comp && new_cpu)
16598c2ecf20Sopenharmony_ci		color_fprintf(stdout, color, " (CPU %d)", this_cpu);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ciout:
16628c2ecf20Sopenharmony_ci	color_fprintf(stdout, color, "\n");
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	thread__put(sched_in);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	return 0;
16678c2ecf20Sopenharmony_ci}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_cistatic int process_sched_switch_event(struct perf_tool *tool,
16708c2ecf20Sopenharmony_ci				      struct evsel *evsel,
16718c2ecf20Sopenharmony_ci				      struct perf_sample *sample,
16728c2ecf20Sopenharmony_ci				      struct machine *machine)
16738c2ecf20Sopenharmony_ci{
16748c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
16758c2ecf20Sopenharmony_ci	int this_cpu = sample->cpu, err = 0;
16768c2ecf20Sopenharmony_ci	u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"),
16778c2ecf20Sopenharmony_ci	    next_pid = evsel__intval(evsel, sample, "next_pid");
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	if (sched->curr_pid[this_cpu] != (u32)-1) {
16808c2ecf20Sopenharmony_ci		/*
16818c2ecf20Sopenharmony_ci		 * Are we trying to switch away a PID that is
16828c2ecf20Sopenharmony_ci		 * not current?
16838c2ecf20Sopenharmony_ci		 */
16848c2ecf20Sopenharmony_ci		if (sched->curr_pid[this_cpu] != prev_pid)
16858c2ecf20Sopenharmony_ci			sched->nr_context_switch_bugs++;
16868c2ecf20Sopenharmony_ci	}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	if (sched->tp_handler->switch_event)
16898c2ecf20Sopenharmony_ci		err = sched->tp_handler->switch_event(sched, evsel, sample, machine);
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	sched->curr_pid[this_cpu] = next_pid;
16928c2ecf20Sopenharmony_ci	return err;
16938c2ecf20Sopenharmony_ci}
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_cistatic int process_sched_runtime_event(struct perf_tool *tool,
16968c2ecf20Sopenharmony_ci				       struct evsel *evsel,
16978c2ecf20Sopenharmony_ci				       struct perf_sample *sample,
16988c2ecf20Sopenharmony_ci				       struct machine *machine)
16998c2ecf20Sopenharmony_ci{
17008c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	if (sched->tp_handler->runtime_event)
17038c2ecf20Sopenharmony_ci		return sched->tp_handler->runtime_event(sched, evsel, sample, machine);
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	return 0;
17068c2ecf20Sopenharmony_ci}
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_cistatic int perf_sched__process_fork_event(struct perf_tool *tool,
17098c2ecf20Sopenharmony_ci					  union perf_event *event,
17108c2ecf20Sopenharmony_ci					  struct perf_sample *sample,
17118c2ecf20Sopenharmony_ci					  struct machine *machine)
17128c2ecf20Sopenharmony_ci{
17138c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	/* run the fork event through the perf machineruy */
17168c2ecf20Sopenharmony_ci	perf_event__process_fork(tool, event, sample, machine);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	/* and then run additional processing needed for this command */
17198c2ecf20Sopenharmony_ci	if (sched->tp_handler->fork_event)
17208c2ecf20Sopenharmony_ci		return sched->tp_handler->fork_event(sched, event, machine);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	return 0;
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic int process_sched_migrate_task_event(struct perf_tool *tool,
17268c2ecf20Sopenharmony_ci					    struct evsel *evsel,
17278c2ecf20Sopenharmony_ci					    struct perf_sample *sample,
17288c2ecf20Sopenharmony_ci					    struct machine *machine)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	if (sched->tp_handler->migrate_task_event)
17338c2ecf20Sopenharmony_ci		return sched->tp_handler->migrate_task_event(sched, evsel, sample, machine);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	return 0;
17368c2ecf20Sopenharmony_ci}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_citypedef int (*tracepoint_handler)(struct perf_tool *tool,
17398c2ecf20Sopenharmony_ci				  struct evsel *evsel,
17408c2ecf20Sopenharmony_ci				  struct perf_sample *sample,
17418c2ecf20Sopenharmony_ci				  struct machine *machine);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_cistatic int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused,
17448c2ecf20Sopenharmony_ci						 union perf_event *event __maybe_unused,
17458c2ecf20Sopenharmony_ci						 struct perf_sample *sample,
17468c2ecf20Sopenharmony_ci						 struct evsel *evsel,
17478c2ecf20Sopenharmony_ci						 struct machine *machine)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	int err = 0;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (evsel->handler != NULL) {
17528c2ecf20Sopenharmony_ci		tracepoint_handler f = evsel->handler;
17538c2ecf20Sopenharmony_ci		err = f(tool, evsel, sample, machine);
17548c2ecf20Sopenharmony_ci	}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	return err;
17578c2ecf20Sopenharmony_ci}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_cistatic int perf_sched__process_comm(struct perf_tool *tool __maybe_unused,
17608c2ecf20Sopenharmony_ci				    union perf_event *event,
17618c2ecf20Sopenharmony_ci				    struct perf_sample *sample,
17628c2ecf20Sopenharmony_ci				    struct machine *machine)
17638c2ecf20Sopenharmony_ci{
17648c2ecf20Sopenharmony_ci	struct thread *thread;
17658c2ecf20Sopenharmony_ci	struct thread_runtime *tr;
17668c2ecf20Sopenharmony_ci	int err;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	err = perf_event__process_comm(tool, event, sample, machine);
17698c2ecf20Sopenharmony_ci	if (err)
17708c2ecf20Sopenharmony_ci		return err;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	thread = machine__find_thread(machine, sample->pid, sample->tid);
17738c2ecf20Sopenharmony_ci	if (!thread) {
17748c2ecf20Sopenharmony_ci		pr_err("Internal error: can't find thread\n");
17758c2ecf20Sopenharmony_ci		return -1;
17768c2ecf20Sopenharmony_ci	}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	tr = thread__get_runtime(thread);
17798c2ecf20Sopenharmony_ci	if (tr == NULL) {
17808c2ecf20Sopenharmony_ci		thread__put(thread);
17818c2ecf20Sopenharmony_ci		return -1;
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	tr->comm_changed = true;
17858c2ecf20Sopenharmony_ci	thread__put(thread);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	return 0;
17888c2ecf20Sopenharmony_ci}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_cistatic int perf_sched__read_events(struct perf_sched *sched)
17918c2ecf20Sopenharmony_ci{
17928c2ecf20Sopenharmony_ci	const struct evsel_str_handler handlers[] = {
17938c2ecf20Sopenharmony_ci		{ "sched:sched_switch",	      process_sched_switch_event, },
17948c2ecf20Sopenharmony_ci		{ "sched:sched_stat_runtime", process_sched_runtime_event, },
17958c2ecf20Sopenharmony_ci		{ "sched:sched_wakeup",	      process_sched_wakeup_event, },
17968c2ecf20Sopenharmony_ci		{ "sched:sched_wakeup_new",   process_sched_wakeup_event, },
17978c2ecf20Sopenharmony_ci		{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
17988c2ecf20Sopenharmony_ci	};
17998c2ecf20Sopenharmony_ci	struct perf_session *session;
18008c2ecf20Sopenharmony_ci	struct perf_data data = {
18018c2ecf20Sopenharmony_ci		.path  = input_name,
18028c2ecf20Sopenharmony_ci		.mode  = PERF_DATA_MODE_READ,
18038c2ecf20Sopenharmony_ci		.force = sched->force,
18048c2ecf20Sopenharmony_ci	};
18058c2ecf20Sopenharmony_ci	int rc = -1;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	session = perf_session__new(&data, false, &sched->tool);
18088c2ecf20Sopenharmony_ci	if (IS_ERR(session)) {
18098c2ecf20Sopenharmony_ci		pr_debug("Error creating perf session");
18108c2ecf20Sopenharmony_ci		return PTR_ERR(session);
18118c2ecf20Sopenharmony_ci	}
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	symbol__init(&session->header.env);
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	if (perf_session__set_tracepoints_handlers(session, handlers))
18168c2ecf20Sopenharmony_ci		goto out_delete;
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	if (perf_session__has_traces(session, "record -R")) {
18198c2ecf20Sopenharmony_ci		int err = perf_session__process_events(session);
18208c2ecf20Sopenharmony_ci		if (err) {
18218c2ecf20Sopenharmony_ci			pr_err("Failed to process events, error %d", err);
18228c2ecf20Sopenharmony_ci			goto out_delete;
18238c2ecf20Sopenharmony_ci		}
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci		sched->nr_events      = session->evlist->stats.nr_events[0];
18268c2ecf20Sopenharmony_ci		sched->nr_lost_events = session->evlist->stats.total_lost;
18278c2ecf20Sopenharmony_ci		sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST];
18288c2ecf20Sopenharmony_ci	}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	rc = 0;
18318c2ecf20Sopenharmony_ciout_delete:
18328c2ecf20Sopenharmony_ci	perf_session__delete(session);
18338c2ecf20Sopenharmony_ci	return rc;
18348c2ecf20Sopenharmony_ci}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci/*
18378c2ecf20Sopenharmony_ci * scheduling times are printed as msec.usec
18388c2ecf20Sopenharmony_ci */
18398c2ecf20Sopenharmony_cistatic inline void print_sched_time(unsigned long long nsecs, int width)
18408c2ecf20Sopenharmony_ci{
18418c2ecf20Sopenharmony_ci	unsigned long msecs;
18428c2ecf20Sopenharmony_ci	unsigned long usecs;
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	msecs  = nsecs / NSEC_PER_MSEC;
18458c2ecf20Sopenharmony_ci	nsecs -= msecs * NSEC_PER_MSEC;
18468c2ecf20Sopenharmony_ci	usecs  = nsecs / NSEC_PER_USEC;
18478c2ecf20Sopenharmony_ci	printf("%*lu.%03lu ", width, msecs, usecs);
18488c2ecf20Sopenharmony_ci}
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci/*
18518c2ecf20Sopenharmony_ci * returns runtime data for event, allocating memory for it the
18528c2ecf20Sopenharmony_ci * first time it is used.
18538c2ecf20Sopenharmony_ci */
18548c2ecf20Sopenharmony_cistatic struct evsel_runtime *evsel__get_runtime(struct evsel *evsel)
18558c2ecf20Sopenharmony_ci{
18568c2ecf20Sopenharmony_ci	struct evsel_runtime *r = evsel->priv;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	if (r == NULL) {
18598c2ecf20Sopenharmony_ci		r = zalloc(sizeof(struct evsel_runtime));
18608c2ecf20Sopenharmony_ci		evsel->priv = r;
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	return r;
18648c2ecf20Sopenharmony_ci}
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci/*
18678c2ecf20Sopenharmony_ci * save last time event was seen per cpu
18688c2ecf20Sopenharmony_ci */
18698c2ecf20Sopenharmony_cistatic void evsel__save_time(struct evsel *evsel, u64 timestamp, u32 cpu)
18708c2ecf20Sopenharmony_ci{
18718c2ecf20Sopenharmony_ci	struct evsel_runtime *r = evsel__get_runtime(evsel);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	if (r == NULL)
18748c2ecf20Sopenharmony_ci		return;
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	if ((cpu >= r->ncpu) || (r->last_time == NULL)) {
18778c2ecf20Sopenharmony_ci		int i, n = __roundup_pow_of_two(cpu+1);
18788c2ecf20Sopenharmony_ci		void *p = r->last_time;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci		p = realloc(r->last_time, n * sizeof(u64));
18818c2ecf20Sopenharmony_ci		if (!p)
18828c2ecf20Sopenharmony_ci			return;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci		r->last_time = p;
18858c2ecf20Sopenharmony_ci		for (i = r->ncpu; i < n; ++i)
18868c2ecf20Sopenharmony_ci			r->last_time[i] = (u64) 0;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci		r->ncpu = n;
18898c2ecf20Sopenharmony_ci	}
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	r->last_time[cpu] = timestamp;
18928c2ecf20Sopenharmony_ci}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci/* returns last time this event was seen on the given cpu */
18958c2ecf20Sopenharmony_cistatic u64 evsel__get_time(struct evsel *evsel, u32 cpu)
18968c2ecf20Sopenharmony_ci{
18978c2ecf20Sopenharmony_ci	struct evsel_runtime *r = evsel__get_runtime(evsel);
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	if ((r == NULL) || (r->last_time == NULL) || (cpu >= r->ncpu))
19008c2ecf20Sopenharmony_ci		return 0;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	return r->last_time[cpu];
19038c2ecf20Sopenharmony_ci}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_cistatic int comm_width = 30;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_cistatic char *timehist_get_commstr(struct thread *thread)
19088c2ecf20Sopenharmony_ci{
19098c2ecf20Sopenharmony_ci	static char str[32];
19108c2ecf20Sopenharmony_ci	const char *comm = thread__comm_str(thread);
19118c2ecf20Sopenharmony_ci	pid_t tid = thread->tid;
19128c2ecf20Sopenharmony_ci	pid_t pid = thread->pid_;
19138c2ecf20Sopenharmony_ci	int n;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	if (pid == 0)
19168c2ecf20Sopenharmony_ci		n = scnprintf(str, sizeof(str), "%s", comm);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	else if (tid != pid)
19198c2ecf20Sopenharmony_ci		n = scnprintf(str, sizeof(str), "%s[%d/%d]", comm, tid, pid);
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	else
19228c2ecf20Sopenharmony_ci		n = scnprintf(str, sizeof(str), "%s[%d]", comm, tid);
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	if (n > comm_width)
19258c2ecf20Sopenharmony_ci		comm_width = n;
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	return str;
19288c2ecf20Sopenharmony_ci}
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_cistatic void timehist_header(struct perf_sched *sched)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	u32 ncpus = sched->max_cpu + 1;
19338c2ecf20Sopenharmony_ci	u32 i, j;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	printf("%15s %6s ", "time", "cpu");
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	if (sched->show_cpu_visual) {
19388c2ecf20Sopenharmony_ci		printf(" ");
19398c2ecf20Sopenharmony_ci		for (i = 0, j = 0; i < ncpus; ++i) {
19408c2ecf20Sopenharmony_ci			printf("%x", j++);
19418c2ecf20Sopenharmony_ci			if (j > 15)
19428c2ecf20Sopenharmony_ci				j = 0;
19438c2ecf20Sopenharmony_ci		}
19448c2ecf20Sopenharmony_ci		printf(" ");
19458c2ecf20Sopenharmony_ci	}
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	printf(" %-*s  %9s  %9s  %9s", comm_width,
19488c2ecf20Sopenharmony_ci		"task name", "wait time", "sch delay", "run time");
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	if (sched->show_state)
19518c2ecf20Sopenharmony_ci		printf("  %s", "state");
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	printf("\n");
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	/*
19568c2ecf20Sopenharmony_ci	 * units row
19578c2ecf20Sopenharmony_ci	 */
19588c2ecf20Sopenharmony_ci	printf("%15s %-6s ", "", "");
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci	if (sched->show_cpu_visual)
19618c2ecf20Sopenharmony_ci		printf(" %*s ", ncpus, "");
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	printf(" %-*s  %9s  %9s  %9s", comm_width,
19648c2ecf20Sopenharmony_ci	       "[tid/pid]", "(msec)", "(msec)", "(msec)");
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	if (sched->show_state)
19678c2ecf20Sopenharmony_ci		printf("  %5s", "");
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	printf("\n");
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	/*
19728c2ecf20Sopenharmony_ci	 * separator
19738c2ecf20Sopenharmony_ci	 */
19748c2ecf20Sopenharmony_ci	printf("%.15s %.6s ", graph_dotted_line, graph_dotted_line);
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	if (sched->show_cpu_visual)
19778c2ecf20Sopenharmony_ci		printf(" %.*s ", ncpus, graph_dotted_line);
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	printf(" %.*s  %.9s  %.9s  %.9s", comm_width,
19808c2ecf20Sopenharmony_ci		graph_dotted_line, graph_dotted_line, graph_dotted_line,
19818c2ecf20Sopenharmony_ci		graph_dotted_line);
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	if (sched->show_state)
19848c2ecf20Sopenharmony_ci		printf("  %.5s", graph_dotted_line);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	printf("\n");
19878c2ecf20Sopenharmony_ci}
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_cistatic char task_state_char(struct thread *thread, int state)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
19928c2ecf20Sopenharmony_ci	unsigned bit = state ? ffs(state) : 0;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	/* 'I' for idle */
19958c2ecf20Sopenharmony_ci	if (thread->tid == 0)
19968c2ecf20Sopenharmony_ci		return 'I';
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
19998c2ecf20Sopenharmony_ci}
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_cistatic void timehist_print_sample(struct perf_sched *sched,
20028c2ecf20Sopenharmony_ci				  struct evsel *evsel,
20038c2ecf20Sopenharmony_ci				  struct perf_sample *sample,
20048c2ecf20Sopenharmony_ci				  struct addr_location *al,
20058c2ecf20Sopenharmony_ci				  struct thread *thread,
20068c2ecf20Sopenharmony_ci				  u64 t, int state)
20078c2ecf20Sopenharmony_ci{
20088c2ecf20Sopenharmony_ci	struct thread_runtime *tr = thread__priv(thread);
20098c2ecf20Sopenharmony_ci	const char *next_comm = evsel__strval(evsel, sample, "next_comm");
20108c2ecf20Sopenharmony_ci	const u32 next_pid = evsel__intval(evsel, sample, "next_pid");
20118c2ecf20Sopenharmony_ci	u32 max_cpus = sched->max_cpu + 1;
20128c2ecf20Sopenharmony_ci	char tstr[64];
20138c2ecf20Sopenharmony_ci	char nstr[30];
20148c2ecf20Sopenharmony_ci	u64 wait_time;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
20178c2ecf20Sopenharmony_ci		return;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
20208c2ecf20Sopenharmony_ci	printf("%15s [%04d] ", tstr, sample->cpu);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	if (sched->show_cpu_visual) {
20238c2ecf20Sopenharmony_ci		u32 i;
20248c2ecf20Sopenharmony_ci		char c;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci		printf(" ");
20278c2ecf20Sopenharmony_ci		for (i = 0; i < max_cpus; ++i) {
20288c2ecf20Sopenharmony_ci			/* flag idle times with 'i'; others are sched events */
20298c2ecf20Sopenharmony_ci			if (i == sample->cpu)
20308c2ecf20Sopenharmony_ci				c = (thread->tid == 0) ? 'i' : 's';
20318c2ecf20Sopenharmony_ci			else
20328c2ecf20Sopenharmony_ci				c = ' ';
20338c2ecf20Sopenharmony_ci			printf("%c", c);
20348c2ecf20Sopenharmony_ci		}
20358c2ecf20Sopenharmony_ci		printf(" ");
20368c2ecf20Sopenharmony_ci	}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	printf(" %-*s ", comm_width, timehist_get_commstr(thread));
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	wait_time = tr->dt_sleep + tr->dt_iowait + tr->dt_preempt;
20418c2ecf20Sopenharmony_ci	print_sched_time(wait_time, 6);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	print_sched_time(tr->dt_delay, 6);
20448c2ecf20Sopenharmony_ci	print_sched_time(tr->dt_run, 6);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	if (sched->show_state)
20478c2ecf20Sopenharmony_ci		printf(" %5c ", task_state_char(thread, state));
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	if (sched->show_next) {
20508c2ecf20Sopenharmony_ci		snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid);
20518c2ecf20Sopenharmony_ci		printf(" %-*s", comm_width, nstr);
20528c2ecf20Sopenharmony_ci	}
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	if (sched->show_wakeups && !sched->show_next)
20558c2ecf20Sopenharmony_ci		printf("  %-*s", comm_width, "");
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	if (thread->tid == 0)
20588c2ecf20Sopenharmony_ci		goto out;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	if (sched->show_callchain)
20618c2ecf20Sopenharmony_ci		printf("  ");
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	sample__fprintf_sym(sample, al, 0,
20648c2ecf20Sopenharmony_ci			    EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
20658c2ecf20Sopenharmony_ci			    EVSEL__PRINT_CALLCHAIN_ARROW |
20668c2ecf20Sopenharmony_ci			    EVSEL__PRINT_SKIP_IGNORED,
20678c2ecf20Sopenharmony_ci			    &callchain_cursor, symbol_conf.bt_stop_list,  stdout);
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ciout:
20708c2ecf20Sopenharmony_ci	printf("\n");
20718c2ecf20Sopenharmony_ci}
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci/*
20748c2ecf20Sopenharmony_ci * Explanation of delta-time stats:
20758c2ecf20Sopenharmony_ci *
20768c2ecf20Sopenharmony_ci *            t = time of current schedule out event
20778c2ecf20Sopenharmony_ci *        tprev = time of previous sched out event
20788c2ecf20Sopenharmony_ci *                also time of schedule-in event for current task
20798c2ecf20Sopenharmony_ci *    last_time = time of last sched change event for current task
20808c2ecf20Sopenharmony_ci *                (i.e, time process was last scheduled out)
20818c2ecf20Sopenharmony_ci * ready_to_run = time of wakeup for current task
20828c2ecf20Sopenharmony_ci *
20838c2ecf20Sopenharmony_ci * -----|------------|------------|------------|------
20848c2ecf20Sopenharmony_ci *    last         ready        tprev          t
20858c2ecf20Sopenharmony_ci *    time         to run
20868c2ecf20Sopenharmony_ci *
20878c2ecf20Sopenharmony_ci *      |-------- dt_wait --------|
20888c2ecf20Sopenharmony_ci *                   |- dt_delay -|-- dt_run --|
20898c2ecf20Sopenharmony_ci *
20908c2ecf20Sopenharmony_ci *   dt_run = run time of current task
20918c2ecf20Sopenharmony_ci *  dt_wait = time between last schedule out event for task and tprev
20928c2ecf20Sopenharmony_ci *            represents time spent off the cpu
20938c2ecf20Sopenharmony_ci * dt_delay = time between wakeup and schedule-in of task
20948c2ecf20Sopenharmony_ci */
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_cistatic void timehist_update_runtime_stats(struct thread_runtime *r,
20978c2ecf20Sopenharmony_ci					 u64 t, u64 tprev)
20988c2ecf20Sopenharmony_ci{
20998c2ecf20Sopenharmony_ci	r->dt_delay   = 0;
21008c2ecf20Sopenharmony_ci	r->dt_sleep   = 0;
21018c2ecf20Sopenharmony_ci	r->dt_iowait  = 0;
21028c2ecf20Sopenharmony_ci	r->dt_preempt = 0;
21038c2ecf20Sopenharmony_ci	r->dt_run     = 0;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	if (tprev) {
21068c2ecf20Sopenharmony_ci		r->dt_run = t - tprev;
21078c2ecf20Sopenharmony_ci		if (r->ready_to_run) {
21088c2ecf20Sopenharmony_ci			if (r->ready_to_run > tprev)
21098c2ecf20Sopenharmony_ci				pr_debug("time travel: wakeup time for task > previous sched_switch event\n");
21108c2ecf20Sopenharmony_ci			else
21118c2ecf20Sopenharmony_ci				r->dt_delay = tprev - r->ready_to_run;
21128c2ecf20Sopenharmony_ci		}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci		if (r->last_time > tprev)
21158c2ecf20Sopenharmony_ci			pr_debug("time travel: last sched out time for task > previous sched_switch event\n");
21168c2ecf20Sopenharmony_ci		else if (r->last_time) {
21178c2ecf20Sopenharmony_ci			u64 dt_wait = tprev - r->last_time;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci			if (r->last_state == TASK_RUNNING)
21208c2ecf20Sopenharmony_ci				r->dt_preempt = dt_wait;
21218c2ecf20Sopenharmony_ci			else if (r->last_state == TASK_UNINTERRUPTIBLE)
21228c2ecf20Sopenharmony_ci				r->dt_iowait = dt_wait;
21238c2ecf20Sopenharmony_ci			else
21248c2ecf20Sopenharmony_ci				r->dt_sleep = dt_wait;
21258c2ecf20Sopenharmony_ci		}
21268c2ecf20Sopenharmony_ci	}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	update_stats(&r->run_stats, r->dt_run);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	r->total_run_time     += r->dt_run;
21318c2ecf20Sopenharmony_ci	r->total_delay_time   += r->dt_delay;
21328c2ecf20Sopenharmony_ci	r->total_sleep_time   += r->dt_sleep;
21338c2ecf20Sopenharmony_ci	r->total_iowait_time  += r->dt_iowait;
21348c2ecf20Sopenharmony_ci	r->total_preempt_time += r->dt_preempt;
21358c2ecf20Sopenharmony_ci}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_cistatic bool is_idle_sample(struct perf_sample *sample,
21388c2ecf20Sopenharmony_ci			   struct evsel *evsel)
21398c2ecf20Sopenharmony_ci{
21408c2ecf20Sopenharmony_ci	/* pid 0 == swapper == idle task */
21418c2ecf20Sopenharmony_ci	if (strcmp(evsel__name(evsel), "sched:sched_switch") == 0)
21428c2ecf20Sopenharmony_ci		return evsel__intval(evsel, sample, "prev_pid") == 0;
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	return sample->pid == 0;
21458c2ecf20Sopenharmony_ci}
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_cistatic void save_task_callchain(struct perf_sched *sched,
21488c2ecf20Sopenharmony_ci				struct perf_sample *sample,
21498c2ecf20Sopenharmony_ci				struct evsel *evsel,
21508c2ecf20Sopenharmony_ci				struct machine *machine)
21518c2ecf20Sopenharmony_ci{
21528c2ecf20Sopenharmony_ci	struct callchain_cursor *cursor = &callchain_cursor;
21538c2ecf20Sopenharmony_ci	struct thread *thread;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	/* want main thread for process - has maps */
21568c2ecf20Sopenharmony_ci	thread = machine__findnew_thread(machine, sample->pid, sample->pid);
21578c2ecf20Sopenharmony_ci	if (thread == NULL) {
21588c2ecf20Sopenharmony_ci		pr_debug("Failed to get thread for pid %d.\n", sample->pid);
21598c2ecf20Sopenharmony_ci		return;
21608c2ecf20Sopenharmony_ci	}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	if (!sched->show_callchain || sample->callchain == NULL)
21638c2ecf20Sopenharmony_ci		return;
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci	if (thread__resolve_callchain(thread, cursor, evsel, sample,
21668c2ecf20Sopenharmony_ci				      NULL, NULL, sched->max_stack + 2) != 0) {
21678c2ecf20Sopenharmony_ci		if (verbose > 0)
21688c2ecf20Sopenharmony_ci			pr_err("Failed to resolve callchain. Skipping\n");
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci		return;
21718c2ecf20Sopenharmony_ci	}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	callchain_cursor_commit(cursor);
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	while (true) {
21768c2ecf20Sopenharmony_ci		struct callchain_cursor_node *node;
21778c2ecf20Sopenharmony_ci		struct symbol *sym;
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci		node = callchain_cursor_current(cursor);
21808c2ecf20Sopenharmony_ci		if (node == NULL)
21818c2ecf20Sopenharmony_ci			break;
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci		sym = node->ms.sym;
21848c2ecf20Sopenharmony_ci		if (sym) {
21858c2ecf20Sopenharmony_ci			if (!strcmp(sym->name, "schedule") ||
21868c2ecf20Sopenharmony_ci			    !strcmp(sym->name, "__schedule") ||
21878c2ecf20Sopenharmony_ci			    !strcmp(sym->name, "preempt_schedule"))
21888c2ecf20Sopenharmony_ci				sym->ignore = 1;
21898c2ecf20Sopenharmony_ci		}
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci		callchain_cursor_advance(cursor);
21928c2ecf20Sopenharmony_ci	}
21938c2ecf20Sopenharmony_ci}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_cistatic int init_idle_thread(struct thread *thread)
21968c2ecf20Sopenharmony_ci{
21978c2ecf20Sopenharmony_ci	struct idle_thread_runtime *itr;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	thread__set_comm(thread, idle_comm, 0);
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	itr = zalloc(sizeof(*itr));
22028c2ecf20Sopenharmony_ci	if (itr == NULL)
22038c2ecf20Sopenharmony_ci		return -ENOMEM;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	init_stats(&itr->tr.run_stats);
22068c2ecf20Sopenharmony_ci	callchain_init(&itr->callchain);
22078c2ecf20Sopenharmony_ci	callchain_cursor_reset(&itr->cursor);
22088c2ecf20Sopenharmony_ci	thread__set_priv(thread, itr);
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	return 0;
22118c2ecf20Sopenharmony_ci}
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci/*
22148c2ecf20Sopenharmony_ci * Track idle stats per cpu by maintaining a local thread
22158c2ecf20Sopenharmony_ci * struct for the idle task on each cpu.
22168c2ecf20Sopenharmony_ci */
22178c2ecf20Sopenharmony_cistatic int init_idle_threads(int ncpu)
22188c2ecf20Sopenharmony_ci{
22198c2ecf20Sopenharmony_ci	int i, ret;
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	idle_threads = zalloc(ncpu * sizeof(struct thread *));
22228c2ecf20Sopenharmony_ci	if (!idle_threads)
22238c2ecf20Sopenharmony_ci		return -ENOMEM;
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	idle_max_cpu = ncpu;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	/* allocate the actual thread struct if needed */
22288c2ecf20Sopenharmony_ci	for (i = 0; i < ncpu; ++i) {
22298c2ecf20Sopenharmony_ci		idle_threads[i] = thread__new(0, 0);
22308c2ecf20Sopenharmony_ci		if (idle_threads[i] == NULL)
22318c2ecf20Sopenharmony_ci			return -ENOMEM;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci		ret = init_idle_thread(idle_threads[i]);
22348c2ecf20Sopenharmony_ci		if (ret < 0)
22358c2ecf20Sopenharmony_ci			return ret;
22368c2ecf20Sopenharmony_ci	}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	return 0;
22398c2ecf20Sopenharmony_ci}
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_cistatic void free_idle_threads(void)
22428c2ecf20Sopenharmony_ci{
22438c2ecf20Sopenharmony_ci	int i;
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	if (idle_threads == NULL)
22468c2ecf20Sopenharmony_ci		return;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	for (i = 0; i < idle_max_cpu; ++i) {
22498c2ecf20Sopenharmony_ci		if ((idle_threads[i]))
22508c2ecf20Sopenharmony_ci			thread__delete(idle_threads[i]);
22518c2ecf20Sopenharmony_ci	}
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	free(idle_threads);
22548c2ecf20Sopenharmony_ci}
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_cistatic struct thread *get_idle_thread(int cpu)
22578c2ecf20Sopenharmony_ci{
22588c2ecf20Sopenharmony_ci	/*
22598c2ecf20Sopenharmony_ci	 * expand/allocate array of pointers to local thread
22608c2ecf20Sopenharmony_ci	 * structs if needed
22618c2ecf20Sopenharmony_ci	 */
22628c2ecf20Sopenharmony_ci	if ((cpu >= idle_max_cpu) || (idle_threads == NULL)) {
22638c2ecf20Sopenharmony_ci		int i, j = __roundup_pow_of_two(cpu+1);
22648c2ecf20Sopenharmony_ci		void *p;
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci		p = realloc(idle_threads, j * sizeof(struct thread *));
22678c2ecf20Sopenharmony_ci		if (!p)
22688c2ecf20Sopenharmony_ci			return NULL;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci		idle_threads = (struct thread **) p;
22718c2ecf20Sopenharmony_ci		for (i = idle_max_cpu; i < j; ++i)
22728c2ecf20Sopenharmony_ci			idle_threads[i] = NULL;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		idle_max_cpu = j;
22758c2ecf20Sopenharmony_ci	}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	/* allocate a new thread struct if needed */
22788c2ecf20Sopenharmony_ci	if (idle_threads[cpu] == NULL) {
22798c2ecf20Sopenharmony_ci		idle_threads[cpu] = thread__new(0, 0);
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci		if (idle_threads[cpu]) {
22828c2ecf20Sopenharmony_ci			if (init_idle_thread(idle_threads[cpu]) < 0)
22838c2ecf20Sopenharmony_ci				return NULL;
22848c2ecf20Sopenharmony_ci		}
22858c2ecf20Sopenharmony_ci	}
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	return idle_threads[cpu];
22888c2ecf20Sopenharmony_ci}
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_cistatic void save_idle_callchain(struct perf_sched *sched,
22918c2ecf20Sopenharmony_ci				struct idle_thread_runtime *itr,
22928c2ecf20Sopenharmony_ci				struct perf_sample *sample)
22938c2ecf20Sopenharmony_ci{
22948c2ecf20Sopenharmony_ci	if (!sched->show_callchain || sample->callchain == NULL)
22958c2ecf20Sopenharmony_ci		return;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	callchain_cursor__copy(&itr->cursor, &callchain_cursor);
22988c2ecf20Sopenharmony_ci}
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_cistatic struct thread *timehist_get_thread(struct perf_sched *sched,
23018c2ecf20Sopenharmony_ci					  struct perf_sample *sample,
23028c2ecf20Sopenharmony_ci					  struct machine *machine,
23038c2ecf20Sopenharmony_ci					  struct evsel *evsel)
23048c2ecf20Sopenharmony_ci{
23058c2ecf20Sopenharmony_ci	struct thread *thread;
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	if (is_idle_sample(sample, evsel)) {
23088c2ecf20Sopenharmony_ci		thread = get_idle_thread(sample->cpu);
23098c2ecf20Sopenharmony_ci		if (thread == NULL)
23108c2ecf20Sopenharmony_ci			pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	} else {
23138c2ecf20Sopenharmony_ci		/* there were samples with tid 0 but non-zero pid */
23148c2ecf20Sopenharmony_ci		thread = machine__findnew_thread(machine, sample->pid,
23158c2ecf20Sopenharmony_ci						 sample->tid ?: sample->pid);
23168c2ecf20Sopenharmony_ci		if (thread == NULL) {
23178c2ecf20Sopenharmony_ci			pr_debug("Failed to get thread for tid %d. skipping sample.\n",
23188c2ecf20Sopenharmony_ci				 sample->tid);
23198c2ecf20Sopenharmony_ci		}
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci		save_task_callchain(sched, sample, evsel, machine);
23228c2ecf20Sopenharmony_ci		if (sched->idle_hist) {
23238c2ecf20Sopenharmony_ci			struct thread *idle;
23248c2ecf20Sopenharmony_ci			struct idle_thread_runtime *itr;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci			idle = get_idle_thread(sample->cpu);
23278c2ecf20Sopenharmony_ci			if (idle == NULL) {
23288c2ecf20Sopenharmony_ci				pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
23298c2ecf20Sopenharmony_ci				return NULL;
23308c2ecf20Sopenharmony_ci			}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci			itr = thread__priv(idle);
23338c2ecf20Sopenharmony_ci			if (itr == NULL)
23348c2ecf20Sopenharmony_ci				return NULL;
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci			itr->last_thread = thread;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci			/* copy task callchain when entering to idle */
23398c2ecf20Sopenharmony_ci			if (evsel__intval(evsel, sample, "next_pid") == 0)
23408c2ecf20Sopenharmony_ci				save_idle_callchain(sched, itr, sample);
23418c2ecf20Sopenharmony_ci		}
23428c2ecf20Sopenharmony_ci	}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	return thread;
23458c2ecf20Sopenharmony_ci}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_cistatic bool timehist_skip_sample(struct perf_sched *sched,
23488c2ecf20Sopenharmony_ci				 struct thread *thread,
23498c2ecf20Sopenharmony_ci				 struct evsel *evsel,
23508c2ecf20Sopenharmony_ci				 struct perf_sample *sample)
23518c2ecf20Sopenharmony_ci{
23528c2ecf20Sopenharmony_ci	bool rc = false;
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	if (thread__is_filtered(thread)) {
23558c2ecf20Sopenharmony_ci		rc = true;
23568c2ecf20Sopenharmony_ci		sched->skipped_samples++;
23578c2ecf20Sopenharmony_ci	}
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	if (sched->idle_hist) {
23608c2ecf20Sopenharmony_ci		if (strcmp(evsel__name(evsel), "sched:sched_switch"))
23618c2ecf20Sopenharmony_ci			rc = true;
23628c2ecf20Sopenharmony_ci		else if (evsel__intval(evsel, sample, "prev_pid") != 0 &&
23638c2ecf20Sopenharmony_ci			 evsel__intval(evsel, sample, "next_pid") != 0)
23648c2ecf20Sopenharmony_ci			rc = true;
23658c2ecf20Sopenharmony_ci	}
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	return rc;
23688c2ecf20Sopenharmony_ci}
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_cistatic void timehist_print_wakeup_event(struct perf_sched *sched,
23718c2ecf20Sopenharmony_ci					struct evsel *evsel,
23728c2ecf20Sopenharmony_ci					struct perf_sample *sample,
23738c2ecf20Sopenharmony_ci					struct machine *machine,
23748c2ecf20Sopenharmony_ci					struct thread *awakened)
23758c2ecf20Sopenharmony_ci{
23768c2ecf20Sopenharmony_ci	struct thread *thread;
23778c2ecf20Sopenharmony_ci	char tstr[64];
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
23808c2ecf20Sopenharmony_ci	if (thread == NULL)
23818c2ecf20Sopenharmony_ci		return;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	/* show wakeup unless both awakee and awaker are filtered */
23848c2ecf20Sopenharmony_ci	if (timehist_skip_sample(sched, thread, evsel, sample) &&
23858c2ecf20Sopenharmony_ci	    timehist_skip_sample(sched, awakened, evsel, sample)) {
23868c2ecf20Sopenharmony_ci		return;
23878c2ecf20Sopenharmony_ci	}
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
23908c2ecf20Sopenharmony_ci	printf("%15s [%04d] ", tstr, sample->cpu);
23918c2ecf20Sopenharmony_ci	if (sched->show_cpu_visual)
23928c2ecf20Sopenharmony_ci		printf(" %*s ", sched->max_cpu + 1, "");
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	printf(" %-*s ", comm_width, timehist_get_commstr(thread));
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	/* dt spacer */
23978c2ecf20Sopenharmony_ci	printf("  %9s  %9s  %9s ", "", "", "");
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	printf("awakened: %s", timehist_get_commstr(awakened));
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	printf("\n");
24028c2ecf20Sopenharmony_ci}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_cistatic int timehist_sched_wakeup_ignore(struct perf_tool *tool __maybe_unused,
24058c2ecf20Sopenharmony_ci					union perf_event *event __maybe_unused,
24068c2ecf20Sopenharmony_ci					struct evsel *evsel __maybe_unused,
24078c2ecf20Sopenharmony_ci					struct perf_sample *sample __maybe_unused,
24088c2ecf20Sopenharmony_ci					struct machine *machine __maybe_unused)
24098c2ecf20Sopenharmony_ci{
24108c2ecf20Sopenharmony_ci	return 0;
24118c2ecf20Sopenharmony_ci}
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_cistatic int timehist_sched_wakeup_event(struct perf_tool *tool,
24148c2ecf20Sopenharmony_ci				       union perf_event *event __maybe_unused,
24158c2ecf20Sopenharmony_ci				       struct evsel *evsel,
24168c2ecf20Sopenharmony_ci				       struct perf_sample *sample,
24178c2ecf20Sopenharmony_ci				       struct machine *machine)
24188c2ecf20Sopenharmony_ci{
24198c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
24208c2ecf20Sopenharmony_ci	struct thread *thread;
24218c2ecf20Sopenharmony_ci	struct thread_runtime *tr = NULL;
24228c2ecf20Sopenharmony_ci	/* want pid of awakened task not pid in sample */
24238c2ecf20Sopenharmony_ci	const u32 pid = evsel__intval(evsel, sample, "pid");
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	thread = machine__findnew_thread(machine, 0, pid);
24268c2ecf20Sopenharmony_ci	if (thread == NULL)
24278c2ecf20Sopenharmony_ci		return -1;
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	tr = thread__get_runtime(thread);
24308c2ecf20Sopenharmony_ci	if (tr == NULL)
24318c2ecf20Sopenharmony_ci		return -1;
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	if (tr->ready_to_run == 0)
24348c2ecf20Sopenharmony_ci		tr->ready_to_run = sample->time;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	/* show wakeups if requested */
24378c2ecf20Sopenharmony_ci	if (sched->show_wakeups &&
24388c2ecf20Sopenharmony_ci	    !perf_time__skip_sample(&sched->ptime, sample->time))
24398c2ecf20Sopenharmony_ci		timehist_print_wakeup_event(sched, evsel, sample, machine, thread);
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	return 0;
24428c2ecf20Sopenharmony_ci}
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_cistatic void timehist_print_migration_event(struct perf_sched *sched,
24458c2ecf20Sopenharmony_ci					struct evsel *evsel,
24468c2ecf20Sopenharmony_ci					struct perf_sample *sample,
24478c2ecf20Sopenharmony_ci					struct machine *machine,
24488c2ecf20Sopenharmony_ci					struct thread *migrated)
24498c2ecf20Sopenharmony_ci{
24508c2ecf20Sopenharmony_ci	struct thread *thread;
24518c2ecf20Sopenharmony_ci	char tstr[64];
24528c2ecf20Sopenharmony_ci	u32 max_cpus = sched->max_cpu + 1;
24538c2ecf20Sopenharmony_ci	u32 ocpu, dcpu;
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	if (sched->summary_only)
24568c2ecf20Sopenharmony_ci		return;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	max_cpus = sched->max_cpu + 1;
24598c2ecf20Sopenharmony_ci	ocpu = evsel__intval(evsel, sample, "orig_cpu");
24608c2ecf20Sopenharmony_ci	dcpu = evsel__intval(evsel, sample, "dest_cpu");
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
24638c2ecf20Sopenharmony_ci	if (thread == NULL)
24648c2ecf20Sopenharmony_ci		return;
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	if (timehist_skip_sample(sched, thread, evsel, sample) &&
24678c2ecf20Sopenharmony_ci	    timehist_skip_sample(sched, migrated, evsel, sample)) {
24688c2ecf20Sopenharmony_ci		return;
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
24728c2ecf20Sopenharmony_ci	printf("%15s [%04d] ", tstr, sample->cpu);
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	if (sched->show_cpu_visual) {
24758c2ecf20Sopenharmony_ci		u32 i;
24768c2ecf20Sopenharmony_ci		char c;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci		printf("  ");
24798c2ecf20Sopenharmony_ci		for (i = 0; i < max_cpus; ++i) {
24808c2ecf20Sopenharmony_ci			c = (i == sample->cpu) ? 'm' : ' ';
24818c2ecf20Sopenharmony_ci			printf("%c", c);
24828c2ecf20Sopenharmony_ci		}
24838c2ecf20Sopenharmony_ci		printf("  ");
24848c2ecf20Sopenharmony_ci	}
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	printf(" %-*s ", comm_width, timehist_get_commstr(thread));
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	/* dt spacer */
24898c2ecf20Sopenharmony_ci	printf("  %9s  %9s  %9s ", "", "", "");
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	printf("migrated: %s", timehist_get_commstr(migrated));
24928c2ecf20Sopenharmony_ci	printf(" cpu %d => %d", ocpu, dcpu);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	printf("\n");
24958c2ecf20Sopenharmony_ci}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_cistatic int timehist_migrate_task_event(struct perf_tool *tool,
24988c2ecf20Sopenharmony_ci				       union perf_event *event __maybe_unused,
24998c2ecf20Sopenharmony_ci				       struct evsel *evsel,
25008c2ecf20Sopenharmony_ci				       struct perf_sample *sample,
25018c2ecf20Sopenharmony_ci				       struct machine *machine)
25028c2ecf20Sopenharmony_ci{
25038c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
25048c2ecf20Sopenharmony_ci	struct thread *thread;
25058c2ecf20Sopenharmony_ci	struct thread_runtime *tr = NULL;
25068c2ecf20Sopenharmony_ci	/* want pid of migrated task not pid in sample */
25078c2ecf20Sopenharmony_ci	const u32 pid = evsel__intval(evsel, sample, "pid");
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	thread = machine__findnew_thread(machine, 0, pid);
25108c2ecf20Sopenharmony_ci	if (thread == NULL)
25118c2ecf20Sopenharmony_ci		return -1;
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci	tr = thread__get_runtime(thread);
25148c2ecf20Sopenharmony_ci	if (tr == NULL)
25158c2ecf20Sopenharmony_ci		return -1;
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	tr->migrations++;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	/* show migrations if requested */
25208c2ecf20Sopenharmony_ci	timehist_print_migration_event(sched, evsel, sample, machine, thread);
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	return 0;
25238c2ecf20Sopenharmony_ci}
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_cistatic int timehist_sched_change_event(struct perf_tool *tool,
25268c2ecf20Sopenharmony_ci				       union perf_event *event,
25278c2ecf20Sopenharmony_ci				       struct evsel *evsel,
25288c2ecf20Sopenharmony_ci				       struct perf_sample *sample,
25298c2ecf20Sopenharmony_ci				       struct machine *machine)
25308c2ecf20Sopenharmony_ci{
25318c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
25328c2ecf20Sopenharmony_ci	struct perf_time_interval *ptime = &sched->ptime;
25338c2ecf20Sopenharmony_ci	struct addr_location al;
25348c2ecf20Sopenharmony_ci	struct thread *thread;
25358c2ecf20Sopenharmony_ci	struct thread_runtime *tr = NULL;
25368c2ecf20Sopenharmony_ci	u64 tprev, t = sample->time;
25378c2ecf20Sopenharmony_ci	int rc = 0;
25388c2ecf20Sopenharmony_ci	int state = evsel__intval(evsel, sample, "prev_state");
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	if (machine__resolve(machine, &al, sample) < 0) {
25418c2ecf20Sopenharmony_ci		pr_err("problem processing %d event. skipping it\n",
25428c2ecf20Sopenharmony_ci		       event->header.type);
25438c2ecf20Sopenharmony_ci		rc = -1;
25448c2ecf20Sopenharmony_ci		goto out;
25458c2ecf20Sopenharmony_ci	}
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci	thread = timehist_get_thread(sched, sample, machine, evsel);
25488c2ecf20Sopenharmony_ci	if (thread == NULL) {
25498c2ecf20Sopenharmony_ci		rc = -1;
25508c2ecf20Sopenharmony_ci		goto out;
25518c2ecf20Sopenharmony_ci	}
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	if (timehist_skip_sample(sched, thread, evsel, sample))
25548c2ecf20Sopenharmony_ci		goto out;
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	tr = thread__get_runtime(thread);
25578c2ecf20Sopenharmony_ci	if (tr == NULL) {
25588c2ecf20Sopenharmony_ci		rc = -1;
25598c2ecf20Sopenharmony_ci		goto out;
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	tprev = evsel__get_time(evsel, sample->cpu);
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	/*
25658c2ecf20Sopenharmony_ci	 * If start time given:
25668c2ecf20Sopenharmony_ci	 * - sample time is under window user cares about - skip sample
25678c2ecf20Sopenharmony_ci	 * - tprev is under window user cares about  - reset to start of window
25688c2ecf20Sopenharmony_ci	 */
25698c2ecf20Sopenharmony_ci	if (ptime->start && ptime->start > t)
25708c2ecf20Sopenharmony_ci		goto out;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci	if (tprev && ptime->start > tprev)
25738c2ecf20Sopenharmony_ci		tprev = ptime->start;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	/*
25768c2ecf20Sopenharmony_ci	 * If end time given:
25778c2ecf20Sopenharmony_ci	 * - previous sched event is out of window - we are done
25788c2ecf20Sopenharmony_ci	 * - sample time is beyond window user cares about - reset it
25798c2ecf20Sopenharmony_ci	 *   to close out stats for time window interest
25808c2ecf20Sopenharmony_ci	 */
25818c2ecf20Sopenharmony_ci	if (ptime->end) {
25828c2ecf20Sopenharmony_ci		if (tprev > ptime->end)
25838c2ecf20Sopenharmony_ci			goto out;
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci		if (t > ptime->end)
25868c2ecf20Sopenharmony_ci			t = ptime->end;
25878c2ecf20Sopenharmony_ci	}
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	if (!sched->idle_hist || thread->tid == 0) {
25908c2ecf20Sopenharmony_ci		if (!cpu_list || test_bit(sample->cpu, cpu_bitmap))
25918c2ecf20Sopenharmony_ci			timehist_update_runtime_stats(tr, t, tprev);
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci		if (sched->idle_hist) {
25948c2ecf20Sopenharmony_ci			struct idle_thread_runtime *itr = (void *)tr;
25958c2ecf20Sopenharmony_ci			struct thread_runtime *last_tr;
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci			BUG_ON(thread->tid != 0);
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci			if (itr->last_thread == NULL)
26008c2ecf20Sopenharmony_ci				goto out;
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci			/* add current idle time as last thread's runtime */
26038c2ecf20Sopenharmony_ci			last_tr = thread__get_runtime(itr->last_thread);
26048c2ecf20Sopenharmony_ci			if (last_tr == NULL)
26058c2ecf20Sopenharmony_ci				goto out;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci			timehist_update_runtime_stats(last_tr, t, tprev);
26088c2ecf20Sopenharmony_ci			/*
26098c2ecf20Sopenharmony_ci			 * remove delta time of last thread as it's not updated
26108c2ecf20Sopenharmony_ci			 * and otherwise it will show an invalid value next
26118c2ecf20Sopenharmony_ci			 * time.  we only care total run time and run stat.
26128c2ecf20Sopenharmony_ci			 */
26138c2ecf20Sopenharmony_ci			last_tr->dt_run = 0;
26148c2ecf20Sopenharmony_ci			last_tr->dt_delay = 0;
26158c2ecf20Sopenharmony_ci			last_tr->dt_sleep = 0;
26168c2ecf20Sopenharmony_ci			last_tr->dt_iowait = 0;
26178c2ecf20Sopenharmony_ci			last_tr->dt_preempt = 0;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci			if (itr->cursor.nr)
26208c2ecf20Sopenharmony_ci				callchain_append(&itr->callchain, &itr->cursor, t - tprev);
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci			itr->last_thread = NULL;
26238c2ecf20Sopenharmony_ci		}
26248c2ecf20Sopenharmony_ci	}
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	if (!sched->summary_only)
26278c2ecf20Sopenharmony_ci		timehist_print_sample(sched, evsel, sample, &al, thread, t, state);
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ciout:
26308c2ecf20Sopenharmony_ci	if (sched->hist_time.start == 0 && t >= ptime->start)
26318c2ecf20Sopenharmony_ci		sched->hist_time.start = t;
26328c2ecf20Sopenharmony_ci	if (ptime->end == 0 || t <= ptime->end)
26338c2ecf20Sopenharmony_ci		sched->hist_time.end = t;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	if (tr) {
26368c2ecf20Sopenharmony_ci		/* time of this sched_switch event becomes last time task seen */
26378c2ecf20Sopenharmony_ci		tr->last_time = sample->time;
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci		/* last state is used to determine where to account wait time */
26408c2ecf20Sopenharmony_ci		tr->last_state = state;
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci		/* sched out event for task so reset ready to run time */
26438c2ecf20Sopenharmony_ci		tr->ready_to_run = 0;
26448c2ecf20Sopenharmony_ci	}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	evsel__save_time(evsel, sample->time, sample->cpu);
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	return rc;
26498c2ecf20Sopenharmony_ci}
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_cistatic int timehist_sched_switch_event(struct perf_tool *tool,
26528c2ecf20Sopenharmony_ci			     union perf_event *event,
26538c2ecf20Sopenharmony_ci			     struct evsel *evsel,
26548c2ecf20Sopenharmony_ci			     struct perf_sample *sample,
26558c2ecf20Sopenharmony_ci			     struct machine *machine __maybe_unused)
26568c2ecf20Sopenharmony_ci{
26578c2ecf20Sopenharmony_ci	return timehist_sched_change_event(tool, event, evsel, sample, machine);
26588c2ecf20Sopenharmony_ci}
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_cistatic int process_lost(struct perf_tool *tool __maybe_unused,
26618c2ecf20Sopenharmony_ci			union perf_event *event,
26628c2ecf20Sopenharmony_ci			struct perf_sample *sample,
26638c2ecf20Sopenharmony_ci			struct machine *machine __maybe_unused)
26648c2ecf20Sopenharmony_ci{
26658c2ecf20Sopenharmony_ci	char tstr[64];
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
26688c2ecf20Sopenharmony_ci	printf("%15s ", tstr);
26698c2ecf20Sopenharmony_ci	printf("lost %" PRI_lu64 " events on cpu %d\n", event->lost.lost, sample->cpu);
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	return 0;
26728c2ecf20Sopenharmony_ci}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_cistatic void print_thread_runtime(struct thread *t,
26768c2ecf20Sopenharmony_ci				 struct thread_runtime *r)
26778c2ecf20Sopenharmony_ci{
26788c2ecf20Sopenharmony_ci	double mean = avg_stats(&r->run_stats);
26798c2ecf20Sopenharmony_ci	float stddev;
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_ci	printf("%*s   %5d  %9" PRIu64 " ",
26828c2ecf20Sopenharmony_ci	       comm_width, timehist_get_commstr(t), t->ppid,
26838c2ecf20Sopenharmony_ci	       (u64) r->run_stats.n);
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	print_sched_time(r->total_run_time, 8);
26868c2ecf20Sopenharmony_ci	stddev = rel_stddev_stats(stddev_stats(&r->run_stats), mean);
26878c2ecf20Sopenharmony_ci	print_sched_time(r->run_stats.min, 6);
26888c2ecf20Sopenharmony_ci	printf(" ");
26898c2ecf20Sopenharmony_ci	print_sched_time((u64) mean, 6);
26908c2ecf20Sopenharmony_ci	printf(" ");
26918c2ecf20Sopenharmony_ci	print_sched_time(r->run_stats.max, 6);
26928c2ecf20Sopenharmony_ci	printf("  ");
26938c2ecf20Sopenharmony_ci	printf("%5.2f", stddev);
26948c2ecf20Sopenharmony_ci	printf("   %5" PRIu64, r->migrations);
26958c2ecf20Sopenharmony_ci	printf("\n");
26968c2ecf20Sopenharmony_ci}
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_cistatic void print_thread_waittime(struct thread *t,
26998c2ecf20Sopenharmony_ci				  struct thread_runtime *r)
27008c2ecf20Sopenharmony_ci{
27018c2ecf20Sopenharmony_ci	printf("%*s   %5d  %9" PRIu64 " ",
27028c2ecf20Sopenharmony_ci	       comm_width, timehist_get_commstr(t), t->ppid,
27038c2ecf20Sopenharmony_ci	       (u64) r->run_stats.n);
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci	print_sched_time(r->total_run_time, 8);
27068c2ecf20Sopenharmony_ci	print_sched_time(r->total_sleep_time, 6);
27078c2ecf20Sopenharmony_ci	printf(" ");
27088c2ecf20Sopenharmony_ci	print_sched_time(r->total_iowait_time, 6);
27098c2ecf20Sopenharmony_ci	printf(" ");
27108c2ecf20Sopenharmony_ci	print_sched_time(r->total_preempt_time, 6);
27118c2ecf20Sopenharmony_ci	printf(" ");
27128c2ecf20Sopenharmony_ci	print_sched_time(r->total_delay_time, 6);
27138c2ecf20Sopenharmony_ci	printf("\n");
27148c2ecf20Sopenharmony_ci}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_cistruct total_run_stats {
27178c2ecf20Sopenharmony_ci	struct perf_sched *sched;
27188c2ecf20Sopenharmony_ci	u64  sched_count;
27198c2ecf20Sopenharmony_ci	u64  task_count;
27208c2ecf20Sopenharmony_ci	u64  total_run_time;
27218c2ecf20Sopenharmony_ci};
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_cistatic int __show_thread_runtime(struct thread *t, void *priv)
27248c2ecf20Sopenharmony_ci{
27258c2ecf20Sopenharmony_ci	struct total_run_stats *stats = priv;
27268c2ecf20Sopenharmony_ci	struct thread_runtime *r;
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci	if (thread__is_filtered(t))
27298c2ecf20Sopenharmony_ci		return 0;
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	r = thread__priv(t);
27328c2ecf20Sopenharmony_ci	if (r && r->run_stats.n) {
27338c2ecf20Sopenharmony_ci		stats->task_count++;
27348c2ecf20Sopenharmony_ci		stats->sched_count += r->run_stats.n;
27358c2ecf20Sopenharmony_ci		stats->total_run_time += r->total_run_time;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci		if (stats->sched->show_state)
27388c2ecf20Sopenharmony_ci			print_thread_waittime(t, r);
27398c2ecf20Sopenharmony_ci		else
27408c2ecf20Sopenharmony_ci			print_thread_runtime(t, r);
27418c2ecf20Sopenharmony_ci	}
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	return 0;
27448c2ecf20Sopenharmony_ci}
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_cistatic int show_thread_runtime(struct thread *t, void *priv)
27478c2ecf20Sopenharmony_ci{
27488c2ecf20Sopenharmony_ci	if (t->dead)
27498c2ecf20Sopenharmony_ci		return 0;
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci	return __show_thread_runtime(t, priv);
27528c2ecf20Sopenharmony_ci}
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_cistatic int show_deadthread_runtime(struct thread *t, void *priv)
27558c2ecf20Sopenharmony_ci{
27568c2ecf20Sopenharmony_ci	if (!t->dead)
27578c2ecf20Sopenharmony_ci		return 0;
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	return __show_thread_runtime(t, priv);
27608c2ecf20Sopenharmony_ci}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_cistatic size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
27638c2ecf20Sopenharmony_ci{
27648c2ecf20Sopenharmony_ci	const char *sep = " <- ";
27658c2ecf20Sopenharmony_ci	struct callchain_list *chain;
27668c2ecf20Sopenharmony_ci	size_t ret = 0;
27678c2ecf20Sopenharmony_ci	char bf[1024];
27688c2ecf20Sopenharmony_ci	bool first;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	if (node == NULL)
27718c2ecf20Sopenharmony_ci		return 0;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	ret = callchain__fprintf_folded(fp, node->parent);
27748c2ecf20Sopenharmony_ci	first = (ret == 0);
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	list_for_each_entry(chain, &node->val, list) {
27778c2ecf20Sopenharmony_ci		if (chain->ip >= PERF_CONTEXT_MAX)
27788c2ecf20Sopenharmony_ci			continue;
27798c2ecf20Sopenharmony_ci		if (chain->ms.sym && chain->ms.sym->ignore)
27808c2ecf20Sopenharmony_ci			continue;
27818c2ecf20Sopenharmony_ci		ret += fprintf(fp, "%s%s", first ? "" : sep,
27828c2ecf20Sopenharmony_ci			       callchain_list__sym_name(chain, bf, sizeof(bf),
27838c2ecf20Sopenharmony_ci							false));
27848c2ecf20Sopenharmony_ci		first = false;
27858c2ecf20Sopenharmony_ci	}
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_ci	return ret;
27888c2ecf20Sopenharmony_ci}
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_cistatic size_t timehist_print_idlehist_callchain(struct rb_root_cached *root)
27918c2ecf20Sopenharmony_ci{
27928c2ecf20Sopenharmony_ci	size_t ret = 0;
27938c2ecf20Sopenharmony_ci	FILE *fp = stdout;
27948c2ecf20Sopenharmony_ci	struct callchain_node *chain;
27958c2ecf20Sopenharmony_ci	struct rb_node *rb_node = rb_first_cached(root);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	printf("  %16s  %8s  %s\n", "Idle time (msec)", "Count", "Callchains");
27988c2ecf20Sopenharmony_ci	printf("  %.16s  %.8s  %.50s\n", graph_dotted_line, graph_dotted_line,
27998c2ecf20Sopenharmony_ci	       graph_dotted_line);
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_ci	while (rb_node) {
28028c2ecf20Sopenharmony_ci		chain = rb_entry(rb_node, struct callchain_node, rb_node);
28038c2ecf20Sopenharmony_ci		rb_node = rb_next(rb_node);
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci		ret += fprintf(fp, "  ");
28068c2ecf20Sopenharmony_ci		print_sched_time(chain->hit, 12);
28078c2ecf20Sopenharmony_ci		ret += 16;  /* print_sched_time returns 2nd arg + 4 */
28088c2ecf20Sopenharmony_ci		ret += fprintf(fp, " %8d  ", chain->count);
28098c2ecf20Sopenharmony_ci		ret += callchain__fprintf_folded(fp, chain);
28108c2ecf20Sopenharmony_ci		ret += fprintf(fp, "\n");
28118c2ecf20Sopenharmony_ci	}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	return ret;
28148c2ecf20Sopenharmony_ci}
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_cistatic void timehist_print_summary(struct perf_sched *sched,
28178c2ecf20Sopenharmony_ci				   struct perf_session *session)
28188c2ecf20Sopenharmony_ci{
28198c2ecf20Sopenharmony_ci	struct machine *m = &session->machines.host;
28208c2ecf20Sopenharmony_ci	struct total_run_stats totals;
28218c2ecf20Sopenharmony_ci	u64 task_count;
28228c2ecf20Sopenharmony_ci	struct thread *t;
28238c2ecf20Sopenharmony_ci	struct thread_runtime *r;
28248c2ecf20Sopenharmony_ci	int i;
28258c2ecf20Sopenharmony_ci	u64 hist_time = sched->hist_time.end - sched->hist_time.start;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	memset(&totals, 0, sizeof(totals));
28288c2ecf20Sopenharmony_ci	totals.sched = sched;
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	if (sched->idle_hist) {
28318c2ecf20Sopenharmony_ci		printf("\nIdle-time summary\n");
28328c2ecf20Sopenharmony_ci		printf("%*s  parent  sched-out  ", comm_width, "comm");
28338c2ecf20Sopenharmony_ci		printf("  idle-time   min-idle    avg-idle    max-idle  stddev  migrations\n");
28348c2ecf20Sopenharmony_ci	} else if (sched->show_state) {
28358c2ecf20Sopenharmony_ci		printf("\nWait-time summary\n");
28368c2ecf20Sopenharmony_ci		printf("%*s  parent   sched-in  ", comm_width, "comm");
28378c2ecf20Sopenharmony_ci		printf("   run-time      sleep      iowait     preempt       delay\n");
28388c2ecf20Sopenharmony_ci	} else {
28398c2ecf20Sopenharmony_ci		printf("\nRuntime summary\n");
28408c2ecf20Sopenharmony_ci		printf("%*s  parent   sched-in  ", comm_width, "comm");
28418c2ecf20Sopenharmony_ci		printf("   run-time    min-run     avg-run     max-run  stddev  migrations\n");
28428c2ecf20Sopenharmony_ci	}
28438c2ecf20Sopenharmony_ci	printf("%*s            (count)  ", comm_width, "");
28448c2ecf20Sopenharmony_ci	printf("     (msec)     (msec)      (msec)      (msec)       %s\n",
28458c2ecf20Sopenharmony_ci	       sched->show_state ? "(msec)" : "%");
28468c2ecf20Sopenharmony_ci	printf("%.117s\n", graph_dotted_line);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	machine__for_each_thread(m, show_thread_runtime, &totals);
28498c2ecf20Sopenharmony_ci	task_count = totals.task_count;
28508c2ecf20Sopenharmony_ci	if (!task_count)
28518c2ecf20Sopenharmony_ci		printf("<no still running tasks>\n");
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci	printf("\nTerminated tasks:\n");
28548c2ecf20Sopenharmony_ci	machine__for_each_thread(m, show_deadthread_runtime, &totals);
28558c2ecf20Sopenharmony_ci	if (task_count == totals.task_count)
28568c2ecf20Sopenharmony_ci		printf("<no terminated tasks>\n");
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	/* CPU idle stats not tracked when samples were skipped */
28598c2ecf20Sopenharmony_ci	if (sched->skipped_samples && !sched->idle_hist)
28608c2ecf20Sopenharmony_ci		return;
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	printf("\nIdle stats:\n");
28638c2ecf20Sopenharmony_ci	for (i = 0; i < idle_max_cpu; ++i) {
28648c2ecf20Sopenharmony_ci		if (cpu_list && !test_bit(i, cpu_bitmap))
28658c2ecf20Sopenharmony_ci			continue;
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci		t = idle_threads[i];
28688c2ecf20Sopenharmony_ci		if (!t)
28698c2ecf20Sopenharmony_ci			continue;
28708c2ecf20Sopenharmony_ci
28718c2ecf20Sopenharmony_ci		r = thread__priv(t);
28728c2ecf20Sopenharmony_ci		if (r && r->run_stats.n) {
28738c2ecf20Sopenharmony_ci			totals.sched_count += r->run_stats.n;
28748c2ecf20Sopenharmony_ci			printf("    CPU %2d idle for ", i);
28758c2ecf20Sopenharmony_ci			print_sched_time(r->total_run_time, 6);
28768c2ecf20Sopenharmony_ci			printf(" msec  (%6.2f%%)\n", 100.0 * r->total_run_time / hist_time);
28778c2ecf20Sopenharmony_ci		} else
28788c2ecf20Sopenharmony_ci			printf("    CPU %2d idle entire time window\n", i);
28798c2ecf20Sopenharmony_ci	}
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	if (sched->idle_hist && sched->show_callchain) {
28828c2ecf20Sopenharmony_ci		callchain_param.mode  = CHAIN_FOLDED;
28838c2ecf20Sopenharmony_ci		callchain_param.value = CCVAL_PERIOD;
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci		callchain_register_param(&callchain_param);
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci		printf("\nIdle stats by callchain:\n");
28888c2ecf20Sopenharmony_ci		for (i = 0; i < idle_max_cpu; ++i) {
28898c2ecf20Sopenharmony_ci			struct idle_thread_runtime *itr;
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci			t = idle_threads[i];
28928c2ecf20Sopenharmony_ci			if (!t)
28938c2ecf20Sopenharmony_ci				continue;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci			itr = thread__priv(t);
28968c2ecf20Sopenharmony_ci			if (itr == NULL)
28978c2ecf20Sopenharmony_ci				continue;
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci			callchain_param.sort(&itr->sorted_root.rb_root, &itr->callchain,
29008c2ecf20Sopenharmony_ci					     0, &callchain_param);
29018c2ecf20Sopenharmony_ci
29028c2ecf20Sopenharmony_ci			printf("  CPU %2d:", i);
29038c2ecf20Sopenharmony_ci			print_sched_time(itr->tr.total_run_time, 6);
29048c2ecf20Sopenharmony_ci			printf(" msec\n");
29058c2ecf20Sopenharmony_ci			timehist_print_idlehist_callchain(&itr->sorted_root);
29068c2ecf20Sopenharmony_ci			printf("\n");
29078c2ecf20Sopenharmony_ci		}
29088c2ecf20Sopenharmony_ci	}
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci	printf("\n"
29118c2ecf20Sopenharmony_ci	       "    Total number of unique tasks: %" PRIu64 "\n"
29128c2ecf20Sopenharmony_ci	       "Total number of context switches: %" PRIu64 "\n",
29138c2ecf20Sopenharmony_ci	       totals.task_count, totals.sched_count);
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci	printf("           Total run time (msec): ");
29168c2ecf20Sopenharmony_ci	print_sched_time(totals.total_run_time, 2);
29178c2ecf20Sopenharmony_ci	printf("\n");
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	printf("    Total scheduling time (msec): ");
29208c2ecf20Sopenharmony_ci	print_sched_time(hist_time, 2);
29218c2ecf20Sopenharmony_ci	printf(" (x %d)\n", sched->max_cpu);
29228c2ecf20Sopenharmony_ci}
29238c2ecf20Sopenharmony_ci
29248c2ecf20Sopenharmony_citypedef int (*sched_handler)(struct perf_tool *tool,
29258c2ecf20Sopenharmony_ci			  union perf_event *event,
29268c2ecf20Sopenharmony_ci			  struct evsel *evsel,
29278c2ecf20Sopenharmony_ci			  struct perf_sample *sample,
29288c2ecf20Sopenharmony_ci			  struct machine *machine);
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_cistatic int perf_timehist__process_sample(struct perf_tool *tool,
29318c2ecf20Sopenharmony_ci					 union perf_event *event,
29328c2ecf20Sopenharmony_ci					 struct perf_sample *sample,
29338c2ecf20Sopenharmony_ci					 struct evsel *evsel,
29348c2ecf20Sopenharmony_ci					 struct machine *machine)
29358c2ecf20Sopenharmony_ci{
29368c2ecf20Sopenharmony_ci	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
29378c2ecf20Sopenharmony_ci	int err = 0;
29388c2ecf20Sopenharmony_ci	int this_cpu = sample->cpu;
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	if (this_cpu > sched->max_cpu)
29418c2ecf20Sopenharmony_ci		sched->max_cpu = this_cpu;
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci	if (evsel->handler != NULL) {
29448c2ecf20Sopenharmony_ci		sched_handler f = evsel->handler;
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci		err = f(tool, event, evsel, sample, machine);
29478c2ecf20Sopenharmony_ci	}
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci	return err;
29508c2ecf20Sopenharmony_ci}
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_cistatic int timehist_check_attr(struct perf_sched *sched,
29538c2ecf20Sopenharmony_ci			       struct evlist *evlist)
29548c2ecf20Sopenharmony_ci{
29558c2ecf20Sopenharmony_ci	struct evsel *evsel;
29568c2ecf20Sopenharmony_ci	struct evsel_runtime *er;
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	list_for_each_entry(evsel, &evlist->core.entries, core.node) {
29598c2ecf20Sopenharmony_ci		er = evsel__get_runtime(evsel);
29608c2ecf20Sopenharmony_ci		if (er == NULL) {
29618c2ecf20Sopenharmony_ci			pr_err("Failed to allocate memory for evsel runtime data\n");
29628c2ecf20Sopenharmony_ci			return -1;
29638c2ecf20Sopenharmony_ci		}
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci		if (sched->show_callchain && !evsel__has_callchain(evsel)) {
29668c2ecf20Sopenharmony_ci			pr_info("Samples do not have callchains.\n");
29678c2ecf20Sopenharmony_ci			sched->show_callchain = 0;
29688c2ecf20Sopenharmony_ci			symbol_conf.use_callchain = 0;
29698c2ecf20Sopenharmony_ci		}
29708c2ecf20Sopenharmony_ci	}
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_ci	return 0;
29738c2ecf20Sopenharmony_ci}
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_cistatic int perf_sched__timehist(struct perf_sched *sched)
29768c2ecf20Sopenharmony_ci{
29778c2ecf20Sopenharmony_ci	struct evsel_str_handler handlers[] = {
29788c2ecf20Sopenharmony_ci		{ "sched:sched_switch",       timehist_sched_switch_event, },
29798c2ecf20Sopenharmony_ci		{ "sched:sched_wakeup",	      timehist_sched_wakeup_event, },
29808c2ecf20Sopenharmony_ci		{ "sched:sched_waking",       timehist_sched_wakeup_event, },
29818c2ecf20Sopenharmony_ci		{ "sched:sched_wakeup_new",   timehist_sched_wakeup_event, },
29828c2ecf20Sopenharmony_ci	};
29838c2ecf20Sopenharmony_ci	const struct evsel_str_handler migrate_handlers[] = {
29848c2ecf20Sopenharmony_ci		{ "sched:sched_migrate_task", timehist_migrate_task_event, },
29858c2ecf20Sopenharmony_ci	};
29868c2ecf20Sopenharmony_ci	struct perf_data data = {
29878c2ecf20Sopenharmony_ci		.path  = input_name,
29888c2ecf20Sopenharmony_ci		.mode  = PERF_DATA_MODE_READ,
29898c2ecf20Sopenharmony_ci		.force = sched->force,
29908c2ecf20Sopenharmony_ci	};
29918c2ecf20Sopenharmony_ci
29928c2ecf20Sopenharmony_ci	struct perf_session *session;
29938c2ecf20Sopenharmony_ci	struct evlist *evlist;
29948c2ecf20Sopenharmony_ci	int err = -1;
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	/*
29978c2ecf20Sopenharmony_ci	 * event handlers for timehist option
29988c2ecf20Sopenharmony_ci	 */
29998c2ecf20Sopenharmony_ci	sched->tool.sample	 = perf_timehist__process_sample;
30008c2ecf20Sopenharmony_ci	sched->tool.mmap	 = perf_event__process_mmap;
30018c2ecf20Sopenharmony_ci	sched->tool.comm	 = perf_event__process_comm;
30028c2ecf20Sopenharmony_ci	sched->tool.exit	 = perf_event__process_exit;
30038c2ecf20Sopenharmony_ci	sched->tool.fork	 = perf_event__process_fork;
30048c2ecf20Sopenharmony_ci	sched->tool.lost	 = process_lost;
30058c2ecf20Sopenharmony_ci	sched->tool.attr	 = perf_event__process_attr;
30068c2ecf20Sopenharmony_ci	sched->tool.tracing_data = perf_event__process_tracing_data;
30078c2ecf20Sopenharmony_ci	sched->tool.build_id	 = perf_event__process_build_id;
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci	sched->tool.ordered_events = true;
30108c2ecf20Sopenharmony_ci	sched->tool.ordering_requires_timestamps = true;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	symbol_conf.use_callchain = sched->show_callchain;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	session = perf_session__new(&data, false, &sched->tool);
30158c2ecf20Sopenharmony_ci	if (IS_ERR(session))
30168c2ecf20Sopenharmony_ci		return PTR_ERR(session);
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	if (cpu_list) {
30198c2ecf20Sopenharmony_ci		err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
30208c2ecf20Sopenharmony_ci		if (err < 0)
30218c2ecf20Sopenharmony_ci			goto out;
30228c2ecf20Sopenharmony_ci	}
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci	evlist = session->evlist;
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_ci	symbol__init(&session->header.env);
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	if (perf_time__parse_str(&sched->ptime, sched->time_str) != 0) {
30298c2ecf20Sopenharmony_ci		pr_err("Invalid time string\n");
30308c2ecf20Sopenharmony_ci		return -EINVAL;
30318c2ecf20Sopenharmony_ci	}
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	if (timehist_check_attr(sched, evlist) != 0)
30348c2ecf20Sopenharmony_ci		goto out;
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci	setup_pager();
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	/* prefer sched_waking if it is captured */
30398c2ecf20Sopenharmony_ci	if (perf_evlist__find_tracepoint_by_name(session->evlist,
30408c2ecf20Sopenharmony_ci						  "sched:sched_waking"))
30418c2ecf20Sopenharmony_ci		handlers[1].handler = timehist_sched_wakeup_ignore;
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	/* setup per-evsel handlers */
30448c2ecf20Sopenharmony_ci	if (perf_session__set_tracepoints_handlers(session, handlers))
30458c2ecf20Sopenharmony_ci		goto out;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	/* sched_switch event at a minimum needs to exist */
30488c2ecf20Sopenharmony_ci	if (!perf_evlist__find_tracepoint_by_name(session->evlist,
30498c2ecf20Sopenharmony_ci						  "sched:sched_switch")) {
30508c2ecf20Sopenharmony_ci		pr_err("No sched_switch events found. Have you run 'perf sched record'?\n");
30518c2ecf20Sopenharmony_ci		goto out;
30528c2ecf20Sopenharmony_ci	}
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	if (sched->show_migrations &&
30558c2ecf20Sopenharmony_ci	    perf_session__set_tracepoints_handlers(session, migrate_handlers))
30568c2ecf20Sopenharmony_ci		goto out;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	/* pre-allocate struct for per-CPU idle stats */
30598c2ecf20Sopenharmony_ci	sched->max_cpu = session->header.env.nr_cpus_online;
30608c2ecf20Sopenharmony_ci	if (sched->max_cpu == 0)
30618c2ecf20Sopenharmony_ci		sched->max_cpu = 4;
30628c2ecf20Sopenharmony_ci	if (init_idle_threads(sched->max_cpu))
30638c2ecf20Sopenharmony_ci		goto out;
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci	/* summary_only implies summary option, but don't overwrite summary if set */
30668c2ecf20Sopenharmony_ci	if (sched->summary_only)
30678c2ecf20Sopenharmony_ci		sched->summary = sched->summary_only;
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci	if (!sched->summary_only)
30708c2ecf20Sopenharmony_ci		timehist_header(sched);
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	err = perf_session__process_events(session);
30738c2ecf20Sopenharmony_ci	if (err) {
30748c2ecf20Sopenharmony_ci		pr_err("Failed to process events, error %d", err);
30758c2ecf20Sopenharmony_ci		goto out;
30768c2ecf20Sopenharmony_ci	}
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci	sched->nr_events      = evlist->stats.nr_events[0];
30798c2ecf20Sopenharmony_ci	sched->nr_lost_events = evlist->stats.total_lost;
30808c2ecf20Sopenharmony_ci	sched->nr_lost_chunks = evlist->stats.nr_events[PERF_RECORD_LOST];
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci	if (sched->summary)
30838c2ecf20Sopenharmony_ci		timehist_print_summary(sched, session);
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ciout:
30868c2ecf20Sopenharmony_ci	free_idle_threads();
30878c2ecf20Sopenharmony_ci	perf_session__delete(session);
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	return err;
30908c2ecf20Sopenharmony_ci}
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_cistatic void print_bad_events(struct perf_sched *sched)
30948c2ecf20Sopenharmony_ci{
30958c2ecf20Sopenharmony_ci	if (sched->nr_unordered_timestamps && sched->nr_timestamps) {
30968c2ecf20Sopenharmony_ci		printf("  INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
30978c2ecf20Sopenharmony_ci			(double)sched->nr_unordered_timestamps/(double)sched->nr_timestamps*100.0,
30988c2ecf20Sopenharmony_ci			sched->nr_unordered_timestamps, sched->nr_timestamps);
30998c2ecf20Sopenharmony_ci	}
31008c2ecf20Sopenharmony_ci	if (sched->nr_lost_events && sched->nr_events) {
31018c2ecf20Sopenharmony_ci		printf("  INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
31028c2ecf20Sopenharmony_ci			(double)sched->nr_lost_events/(double)sched->nr_events * 100.0,
31038c2ecf20Sopenharmony_ci			sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks);
31048c2ecf20Sopenharmony_ci	}
31058c2ecf20Sopenharmony_ci	if (sched->nr_context_switch_bugs && sched->nr_timestamps) {
31068c2ecf20Sopenharmony_ci		printf("  INFO: %.3f%% context switch bugs (%ld out of %ld)",
31078c2ecf20Sopenharmony_ci			(double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0,
31088c2ecf20Sopenharmony_ci			sched->nr_context_switch_bugs, sched->nr_timestamps);
31098c2ecf20Sopenharmony_ci		if (sched->nr_lost_events)
31108c2ecf20Sopenharmony_ci			printf(" (due to lost events?)");
31118c2ecf20Sopenharmony_ci		printf("\n");
31128c2ecf20Sopenharmony_ci	}
31138c2ecf20Sopenharmony_ci}
31148c2ecf20Sopenharmony_ci
31158c2ecf20Sopenharmony_cistatic void __merge_work_atoms(struct rb_root_cached *root, struct work_atoms *data)
31168c2ecf20Sopenharmony_ci{
31178c2ecf20Sopenharmony_ci	struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
31188c2ecf20Sopenharmony_ci	struct work_atoms *this;
31198c2ecf20Sopenharmony_ci	const char *comm = thread__comm_str(data->thread), *this_comm;
31208c2ecf20Sopenharmony_ci	bool leftmost = true;
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	while (*new) {
31238c2ecf20Sopenharmony_ci		int cmp;
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci		this = container_of(*new, struct work_atoms, node);
31268c2ecf20Sopenharmony_ci		parent = *new;
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci		this_comm = thread__comm_str(this->thread);
31298c2ecf20Sopenharmony_ci		cmp = strcmp(comm, this_comm);
31308c2ecf20Sopenharmony_ci		if (cmp > 0) {
31318c2ecf20Sopenharmony_ci			new = &((*new)->rb_left);
31328c2ecf20Sopenharmony_ci		} else if (cmp < 0) {
31338c2ecf20Sopenharmony_ci			new = &((*new)->rb_right);
31348c2ecf20Sopenharmony_ci			leftmost = false;
31358c2ecf20Sopenharmony_ci		} else {
31368c2ecf20Sopenharmony_ci			this->num_merged++;
31378c2ecf20Sopenharmony_ci			this->total_runtime += data->total_runtime;
31388c2ecf20Sopenharmony_ci			this->nb_atoms += data->nb_atoms;
31398c2ecf20Sopenharmony_ci			this->total_lat += data->total_lat;
31408c2ecf20Sopenharmony_ci			list_splice(&data->work_list, &this->work_list);
31418c2ecf20Sopenharmony_ci			if (this->max_lat < data->max_lat) {
31428c2ecf20Sopenharmony_ci				this->max_lat = data->max_lat;
31438c2ecf20Sopenharmony_ci				this->max_lat_start = data->max_lat_start;
31448c2ecf20Sopenharmony_ci				this->max_lat_end = data->max_lat_end;
31458c2ecf20Sopenharmony_ci			}
31468c2ecf20Sopenharmony_ci			zfree(&data);
31478c2ecf20Sopenharmony_ci			return;
31488c2ecf20Sopenharmony_ci		}
31498c2ecf20Sopenharmony_ci	}
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	data->num_merged++;
31528c2ecf20Sopenharmony_ci	rb_link_node(&data->node, parent, new);
31538c2ecf20Sopenharmony_ci	rb_insert_color_cached(&data->node, root, leftmost);
31548c2ecf20Sopenharmony_ci}
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_cistatic void perf_sched__merge_lat(struct perf_sched *sched)
31578c2ecf20Sopenharmony_ci{
31588c2ecf20Sopenharmony_ci	struct work_atoms *data;
31598c2ecf20Sopenharmony_ci	struct rb_node *node;
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci	if (sched->skip_merge)
31628c2ecf20Sopenharmony_ci		return;
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	while ((node = rb_first_cached(&sched->atom_root))) {
31658c2ecf20Sopenharmony_ci		rb_erase_cached(node, &sched->atom_root);
31668c2ecf20Sopenharmony_ci		data = rb_entry(node, struct work_atoms, node);
31678c2ecf20Sopenharmony_ci		__merge_work_atoms(&sched->merged_atom_root, data);
31688c2ecf20Sopenharmony_ci	}
31698c2ecf20Sopenharmony_ci}
31708c2ecf20Sopenharmony_ci
31718c2ecf20Sopenharmony_cistatic int perf_sched__lat(struct perf_sched *sched)
31728c2ecf20Sopenharmony_ci{
31738c2ecf20Sopenharmony_ci	struct rb_node *next;
31748c2ecf20Sopenharmony_ci
31758c2ecf20Sopenharmony_ci	setup_pager();
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci	if (perf_sched__read_events(sched))
31788c2ecf20Sopenharmony_ci		return -1;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	perf_sched__merge_lat(sched);
31818c2ecf20Sopenharmony_ci	perf_sched__sort_lat(sched);
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci	printf("\n -------------------------------------------------------------------------------------------------------------------------------------------\n");
31848c2ecf20Sopenharmony_ci	printf("  Task                  |   Runtime ms  | Switches | Avg delay ms    | Max delay ms    | Max delay start           | Max delay end          |\n");
31858c2ecf20Sopenharmony_ci	printf(" -------------------------------------------------------------------------------------------------------------------------------------------\n");
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_ci	next = rb_first_cached(&sched->sorted_atom_root);
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci	while (next) {
31908c2ecf20Sopenharmony_ci		struct work_atoms *work_list;
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci		work_list = rb_entry(next, struct work_atoms, node);
31938c2ecf20Sopenharmony_ci		output_lat_thread(sched, work_list);
31948c2ecf20Sopenharmony_ci		next = rb_next(next);
31958c2ecf20Sopenharmony_ci		thread__zput(work_list->thread);
31968c2ecf20Sopenharmony_ci	}
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	printf(" -----------------------------------------------------------------------------------------------------------------\n");
31998c2ecf20Sopenharmony_ci	printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
32008c2ecf20Sopenharmony_ci		(double)sched->all_runtime / NSEC_PER_MSEC, sched->all_count);
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci	printf(" ---------------------------------------------------\n");
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	print_bad_events(sched);
32058c2ecf20Sopenharmony_ci	printf("\n");
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci	return 0;
32088c2ecf20Sopenharmony_ci}
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_cistatic int setup_map_cpus(struct perf_sched *sched)
32118c2ecf20Sopenharmony_ci{
32128c2ecf20Sopenharmony_ci	struct perf_cpu_map *map;
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci	sched->max_cpu  = sysconf(_SC_NPROCESSORS_CONF);
32158c2ecf20Sopenharmony_ci
32168c2ecf20Sopenharmony_ci	if (sched->map.comp) {
32178c2ecf20Sopenharmony_ci		sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int));
32188c2ecf20Sopenharmony_ci		if (!sched->map.comp_cpus)
32198c2ecf20Sopenharmony_ci			return -1;
32208c2ecf20Sopenharmony_ci	}
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_ci	if (!sched->map.cpus_str)
32238c2ecf20Sopenharmony_ci		return 0;
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ci	map = perf_cpu_map__new(sched->map.cpus_str);
32268c2ecf20Sopenharmony_ci	if (!map) {
32278c2ecf20Sopenharmony_ci		pr_err("failed to get cpus map from %s\n", sched->map.cpus_str);
32288c2ecf20Sopenharmony_ci		return -1;
32298c2ecf20Sopenharmony_ci	}
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci	sched->map.cpus = map;
32328c2ecf20Sopenharmony_ci	return 0;
32338c2ecf20Sopenharmony_ci}
32348c2ecf20Sopenharmony_ci
32358c2ecf20Sopenharmony_cistatic int setup_color_pids(struct perf_sched *sched)
32368c2ecf20Sopenharmony_ci{
32378c2ecf20Sopenharmony_ci	struct perf_thread_map *map;
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_ci	if (!sched->map.color_pids_str)
32408c2ecf20Sopenharmony_ci		return 0;
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci	map = thread_map__new_by_tid_str(sched->map.color_pids_str);
32438c2ecf20Sopenharmony_ci	if (!map) {
32448c2ecf20Sopenharmony_ci		pr_err("failed to get thread map from %s\n", sched->map.color_pids_str);
32458c2ecf20Sopenharmony_ci		return -1;
32468c2ecf20Sopenharmony_ci	}
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci	sched->map.color_pids = map;
32498c2ecf20Sopenharmony_ci	return 0;
32508c2ecf20Sopenharmony_ci}
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_cistatic int setup_color_cpus(struct perf_sched *sched)
32538c2ecf20Sopenharmony_ci{
32548c2ecf20Sopenharmony_ci	struct perf_cpu_map *map;
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	if (!sched->map.color_cpus_str)
32578c2ecf20Sopenharmony_ci		return 0;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	map = perf_cpu_map__new(sched->map.color_cpus_str);
32608c2ecf20Sopenharmony_ci	if (!map) {
32618c2ecf20Sopenharmony_ci		pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str);
32628c2ecf20Sopenharmony_ci		return -1;
32638c2ecf20Sopenharmony_ci	}
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	sched->map.color_cpus = map;
32668c2ecf20Sopenharmony_ci	return 0;
32678c2ecf20Sopenharmony_ci}
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_cistatic int perf_sched__map(struct perf_sched *sched)
32708c2ecf20Sopenharmony_ci{
32718c2ecf20Sopenharmony_ci	if (setup_map_cpus(sched))
32728c2ecf20Sopenharmony_ci		return -1;
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	if (setup_color_pids(sched))
32758c2ecf20Sopenharmony_ci		return -1;
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	if (setup_color_cpus(sched))
32788c2ecf20Sopenharmony_ci		return -1;
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci	setup_pager();
32818c2ecf20Sopenharmony_ci	if (perf_sched__read_events(sched))
32828c2ecf20Sopenharmony_ci		return -1;
32838c2ecf20Sopenharmony_ci	print_bad_events(sched);
32848c2ecf20Sopenharmony_ci	return 0;
32858c2ecf20Sopenharmony_ci}
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_cistatic int perf_sched__replay(struct perf_sched *sched)
32888c2ecf20Sopenharmony_ci{
32898c2ecf20Sopenharmony_ci	unsigned long i;
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ci	calibrate_run_measurement_overhead(sched);
32928c2ecf20Sopenharmony_ci	calibrate_sleep_measurement_overhead(sched);
32938c2ecf20Sopenharmony_ci
32948c2ecf20Sopenharmony_ci	test_calibrations(sched);
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_ci	if (perf_sched__read_events(sched))
32978c2ecf20Sopenharmony_ci		return -1;
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	printf("nr_run_events:        %ld\n", sched->nr_run_events);
33008c2ecf20Sopenharmony_ci	printf("nr_sleep_events:      %ld\n", sched->nr_sleep_events);
33018c2ecf20Sopenharmony_ci	printf("nr_wakeup_events:     %ld\n", sched->nr_wakeup_events);
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci	if (sched->targetless_wakeups)
33048c2ecf20Sopenharmony_ci		printf("target-less wakeups:  %ld\n", sched->targetless_wakeups);
33058c2ecf20Sopenharmony_ci	if (sched->multitarget_wakeups)
33068c2ecf20Sopenharmony_ci		printf("multi-target wakeups: %ld\n", sched->multitarget_wakeups);
33078c2ecf20Sopenharmony_ci	if (sched->nr_run_events_optimized)
33088c2ecf20Sopenharmony_ci		printf("run atoms optimized: %ld\n",
33098c2ecf20Sopenharmony_ci			sched->nr_run_events_optimized);
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	print_task_traces(sched);
33128c2ecf20Sopenharmony_ci	add_cross_task_wakeups(sched);
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_ci	create_tasks(sched);
33158c2ecf20Sopenharmony_ci	printf("------------------------------------------------------------\n");
33168c2ecf20Sopenharmony_ci	for (i = 0; i < sched->replay_repeat; i++)
33178c2ecf20Sopenharmony_ci		run_one_test(sched);
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	return 0;
33208c2ecf20Sopenharmony_ci}
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_cistatic void setup_sorting(struct perf_sched *sched, const struct option *options,
33238c2ecf20Sopenharmony_ci			  const char * const usage_msg[])
33248c2ecf20Sopenharmony_ci{
33258c2ecf20Sopenharmony_ci	char *tmp, *tok, *str = strdup(sched->sort_order);
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	for (tok = strtok_r(str, ", ", &tmp);
33288c2ecf20Sopenharmony_ci			tok; tok = strtok_r(NULL, ", ", &tmp)) {
33298c2ecf20Sopenharmony_ci		if (sort_dimension__add(tok, &sched->sort_list) < 0) {
33308c2ecf20Sopenharmony_ci			usage_with_options_msg(usage_msg, options,
33318c2ecf20Sopenharmony_ci					"Unknown --sort key: `%s'", tok);
33328c2ecf20Sopenharmony_ci		}
33338c2ecf20Sopenharmony_ci	}
33348c2ecf20Sopenharmony_ci
33358c2ecf20Sopenharmony_ci	free(str);
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_ci	sort_dimension__add("pid", &sched->cmp_pid);
33388c2ecf20Sopenharmony_ci}
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_cistatic bool schedstat_events_exposed(void)
33418c2ecf20Sopenharmony_ci{
33428c2ecf20Sopenharmony_ci	/*
33438c2ecf20Sopenharmony_ci	 * Select "sched:sched_stat_wait" event to check
33448c2ecf20Sopenharmony_ci	 * whether schedstat tracepoints are exposed.
33458c2ecf20Sopenharmony_ci	 */
33468c2ecf20Sopenharmony_ci	return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ?
33478c2ecf20Sopenharmony_ci		false : true;
33488c2ecf20Sopenharmony_ci}
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_cistatic int __cmd_record(int argc, const char **argv)
33518c2ecf20Sopenharmony_ci{
33528c2ecf20Sopenharmony_ci	unsigned int rec_argc, i, j;
33538c2ecf20Sopenharmony_ci	const char **rec_argv;
33548c2ecf20Sopenharmony_ci	const char * const record_args[] = {
33558c2ecf20Sopenharmony_ci		"record",
33568c2ecf20Sopenharmony_ci		"-a",
33578c2ecf20Sopenharmony_ci		"-R",
33588c2ecf20Sopenharmony_ci		"-m", "1024",
33598c2ecf20Sopenharmony_ci		"-c", "1",
33608c2ecf20Sopenharmony_ci		"-e", "sched:sched_switch",
33618c2ecf20Sopenharmony_ci		"-e", "sched:sched_stat_runtime",
33628c2ecf20Sopenharmony_ci		"-e", "sched:sched_process_fork",
33638c2ecf20Sopenharmony_ci		"-e", "sched:sched_wakeup_new",
33648c2ecf20Sopenharmony_ci		"-e", "sched:sched_migrate_task",
33658c2ecf20Sopenharmony_ci	};
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci	/*
33688c2ecf20Sopenharmony_ci	 * The tracepoints trace_sched_stat_{wait, sleep, iowait}
33698c2ecf20Sopenharmony_ci	 * are not exposed to user if CONFIG_SCHEDSTATS is not set,
33708c2ecf20Sopenharmony_ci	 * to prevent "perf sched record" execution failure, determine
33718c2ecf20Sopenharmony_ci	 * whether to record schedstat events according to actual situation.
33728c2ecf20Sopenharmony_ci	 */
33738c2ecf20Sopenharmony_ci	const char * const schedstat_args[] = {
33748c2ecf20Sopenharmony_ci		"-e", "sched:sched_stat_wait",
33758c2ecf20Sopenharmony_ci		"-e", "sched:sched_stat_sleep",
33768c2ecf20Sopenharmony_ci		"-e", "sched:sched_stat_iowait",
33778c2ecf20Sopenharmony_ci	};
33788c2ecf20Sopenharmony_ci	unsigned int schedstat_argc = schedstat_events_exposed() ?
33798c2ecf20Sopenharmony_ci		ARRAY_SIZE(schedstat_args) : 0;
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci	struct tep_event *waking_event;
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ci	/*
33848c2ecf20Sopenharmony_ci	 * +2 for either "-e", "sched:sched_wakeup" or
33858c2ecf20Sopenharmony_ci	 * "-e", "sched:sched_waking"
33868c2ecf20Sopenharmony_ci	 */
33878c2ecf20Sopenharmony_ci	rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1;
33888c2ecf20Sopenharmony_ci	rec_argv = calloc(rec_argc + 1, sizeof(char *));
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci	if (rec_argv == NULL)
33918c2ecf20Sopenharmony_ci		return -ENOMEM;
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(record_args); i++)
33948c2ecf20Sopenharmony_ci		rec_argv[i] = strdup(record_args[i]);
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci	rec_argv[i++] = "-e";
33978c2ecf20Sopenharmony_ci	waking_event = trace_event__tp_format("sched", "sched_waking");
33988c2ecf20Sopenharmony_ci	if (!IS_ERR(waking_event))
33998c2ecf20Sopenharmony_ci		rec_argv[i++] = strdup("sched:sched_waking");
34008c2ecf20Sopenharmony_ci	else
34018c2ecf20Sopenharmony_ci		rec_argv[i++] = strdup("sched:sched_wakeup");
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ci	for (j = 0; j < schedstat_argc; j++)
34048c2ecf20Sopenharmony_ci		rec_argv[i++] = strdup(schedstat_args[j]);
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci	for (j = 1; j < (unsigned int)argc; j++, i++)
34078c2ecf20Sopenharmony_ci		rec_argv[i] = argv[j];
34088c2ecf20Sopenharmony_ci
34098c2ecf20Sopenharmony_ci	BUG_ON(i != rec_argc);
34108c2ecf20Sopenharmony_ci
34118c2ecf20Sopenharmony_ci	return cmd_record(i, rec_argv);
34128c2ecf20Sopenharmony_ci}
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ciint cmd_sched(int argc, const char **argv)
34158c2ecf20Sopenharmony_ci{
34168c2ecf20Sopenharmony_ci	static const char default_sort_order[] = "avg, max, switch, runtime";
34178c2ecf20Sopenharmony_ci	struct perf_sched sched = {
34188c2ecf20Sopenharmony_ci		.tool = {
34198c2ecf20Sopenharmony_ci			.sample		 = perf_sched__process_tracepoint_sample,
34208c2ecf20Sopenharmony_ci			.comm		 = perf_sched__process_comm,
34218c2ecf20Sopenharmony_ci			.namespaces	 = perf_event__process_namespaces,
34228c2ecf20Sopenharmony_ci			.lost		 = perf_event__process_lost,
34238c2ecf20Sopenharmony_ci			.fork		 = perf_sched__process_fork_event,
34248c2ecf20Sopenharmony_ci			.ordered_events = true,
34258c2ecf20Sopenharmony_ci		},
34268c2ecf20Sopenharmony_ci		.cmp_pid	      = LIST_HEAD_INIT(sched.cmp_pid),
34278c2ecf20Sopenharmony_ci		.sort_list	      = LIST_HEAD_INIT(sched.sort_list),
34288c2ecf20Sopenharmony_ci		.start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
34298c2ecf20Sopenharmony_ci		.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
34308c2ecf20Sopenharmony_ci		.sort_order	      = default_sort_order,
34318c2ecf20Sopenharmony_ci		.replay_repeat	      = 10,
34328c2ecf20Sopenharmony_ci		.profile_cpu	      = -1,
34338c2ecf20Sopenharmony_ci		.next_shortname1      = 'A',
34348c2ecf20Sopenharmony_ci		.next_shortname2      = '0',
34358c2ecf20Sopenharmony_ci		.skip_merge           = 0,
34368c2ecf20Sopenharmony_ci		.show_callchain	      = 1,
34378c2ecf20Sopenharmony_ci		.max_stack            = 5,
34388c2ecf20Sopenharmony_ci	};
34398c2ecf20Sopenharmony_ci	const struct option sched_options[] = {
34408c2ecf20Sopenharmony_ci	OPT_STRING('i', "input", &input_name, "file",
34418c2ecf20Sopenharmony_ci		    "input file name"),
34428c2ecf20Sopenharmony_ci	OPT_INCR('v', "verbose", &verbose,
34438c2ecf20Sopenharmony_ci		    "be more verbose (show symbol address, etc)"),
34448c2ecf20Sopenharmony_ci	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
34458c2ecf20Sopenharmony_ci		    "dump raw trace in ASCII"),
34468c2ecf20Sopenharmony_ci	OPT_BOOLEAN('f', "force", &sched.force, "don't complain, do it"),
34478c2ecf20Sopenharmony_ci	OPT_END()
34488c2ecf20Sopenharmony_ci	};
34498c2ecf20Sopenharmony_ci	const struct option latency_options[] = {
34508c2ecf20Sopenharmony_ci	OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
34518c2ecf20Sopenharmony_ci		   "sort by key(s): runtime, switch, avg, max"),
34528c2ecf20Sopenharmony_ci	OPT_INTEGER('C', "CPU", &sched.profile_cpu,
34538c2ecf20Sopenharmony_ci		    "CPU to profile on"),
34548c2ecf20Sopenharmony_ci	OPT_BOOLEAN('p', "pids", &sched.skip_merge,
34558c2ecf20Sopenharmony_ci		    "latency stats per pid instead of per comm"),
34568c2ecf20Sopenharmony_ci	OPT_PARENT(sched_options)
34578c2ecf20Sopenharmony_ci	};
34588c2ecf20Sopenharmony_ci	const struct option replay_options[] = {
34598c2ecf20Sopenharmony_ci	OPT_UINTEGER('r', "repeat", &sched.replay_repeat,
34608c2ecf20Sopenharmony_ci		     "repeat the workload replay N times (-1: infinite)"),
34618c2ecf20Sopenharmony_ci	OPT_PARENT(sched_options)
34628c2ecf20Sopenharmony_ci	};
34638c2ecf20Sopenharmony_ci	const struct option map_options[] = {
34648c2ecf20Sopenharmony_ci	OPT_BOOLEAN(0, "compact", &sched.map.comp,
34658c2ecf20Sopenharmony_ci		    "map output in compact mode"),
34668c2ecf20Sopenharmony_ci	OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids",
34678c2ecf20Sopenharmony_ci		   "highlight given pids in map"),
34688c2ecf20Sopenharmony_ci	OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus",
34698c2ecf20Sopenharmony_ci                    "highlight given CPUs in map"),
34708c2ecf20Sopenharmony_ci	OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus",
34718c2ecf20Sopenharmony_ci                    "display given CPUs in map"),
34728c2ecf20Sopenharmony_ci	OPT_PARENT(sched_options)
34738c2ecf20Sopenharmony_ci	};
34748c2ecf20Sopenharmony_ci	const struct option timehist_options[] = {
34758c2ecf20Sopenharmony_ci	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
34768c2ecf20Sopenharmony_ci		   "file", "vmlinux pathname"),
34778c2ecf20Sopenharmony_ci	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
34788c2ecf20Sopenharmony_ci		   "file", "kallsyms pathname"),
34798c2ecf20Sopenharmony_ci	OPT_BOOLEAN('g', "call-graph", &sched.show_callchain,
34808c2ecf20Sopenharmony_ci		    "Display call chains if present (default on)"),
34818c2ecf20Sopenharmony_ci	OPT_UINTEGER(0, "max-stack", &sched.max_stack,
34828c2ecf20Sopenharmony_ci		   "Maximum number of functions to display backtrace."),
34838c2ecf20Sopenharmony_ci	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
34848c2ecf20Sopenharmony_ci		    "Look for files with symbols relative to this directory"),
34858c2ecf20Sopenharmony_ci	OPT_BOOLEAN('s', "summary", &sched.summary_only,
34868c2ecf20Sopenharmony_ci		    "Show only syscall summary with statistics"),
34878c2ecf20Sopenharmony_ci	OPT_BOOLEAN('S', "with-summary", &sched.summary,
34888c2ecf20Sopenharmony_ci		    "Show all syscalls and summary with statistics"),
34898c2ecf20Sopenharmony_ci	OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
34908c2ecf20Sopenharmony_ci	OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"),
34918c2ecf20Sopenharmony_ci	OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
34928c2ecf20Sopenharmony_ci	OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
34938c2ecf20Sopenharmony_ci	OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
34948c2ecf20Sopenharmony_ci	OPT_STRING(0, "time", &sched.time_str, "str",
34958c2ecf20Sopenharmony_ci		   "Time span for analysis (start,stop)"),
34968c2ecf20Sopenharmony_ci	OPT_BOOLEAN(0, "state", &sched.show_state, "Show task state when sched-out"),
34978c2ecf20Sopenharmony_ci	OPT_STRING('p', "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
34988c2ecf20Sopenharmony_ci		   "analyze events only for given process id(s)"),
34998c2ecf20Sopenharmony_ci	OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
35008c2ecf20Sopenharmony_ci		   "analyze events only for given thread id(s)"),
35018c2ecf20Sopenharmony_ci	OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
35028c2ecf20Sopenharmony_ci	OPT_PARENT(sched_options)
35038c2ecf20Sopenharmony_ci	};
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	const char * const latency_usage[] = {
35068c2ecf20Sopenharmony_ci		"perf sched latency [<options>]",
35078c2ecf20Sopenharmony_ci		NULL
35088c2ecf20Sopenharmony_ci	};
35098c2ecf20Sopenharmony_ci	const char * const replay_usage[] = {
35108c2ecf20Sopenharmony_ci		"perf sched replay [<options>]",
35118c2ecf20Sopenharmony_ci		NULL
35128c2ecf20Sopenharmony_ci	};
35138c2ecf20Sopenharmony_ci	const char * const map_usage[] = {
35148c2ecf20Sopenharmony_ci		"perf sched map [<options>]",
35158c2ecf20Sopenharmony_ci		NULL
35168c2ecf20Sopenharmony_ci	};
35178c2ecf20Sopenharmony_ci	const char * const timehist_usage[] = {
35188c2ecf20Sopenharmony_ci		"perf sched timehist [<options>]",
35198c2ecf20Sopenharmony_ci		NULL
35208c2ecf20Sopenharmony_ci	};
35218c2ecf20Sopenharmony_ci	const char *const sched_subcommands[] = { "record", "latency", "map",
35228c2ecf20Sopenharmony_ci						  "replay", "script",
35238c2ecf20Sopenharmony_ci						  "timehist", NULL };
35248c2ecf20Sopenharmony_ci	const char *sched_usage[] = {
35258c2ecf20Sopenharmony_ci		NULL,
35268c2ecf20Sopenharmony_ci		NULL
35278c2ecf20Sopenharmony_ci	};
35288c2ecf20Sopenharmony_ci	struct trace_sched_handler lat_ops  = {
35298c2ecf20Sopenharmony_ci		.wakeup_event	    = latency_wakeup_event,
35308c2ecf20Sopenharmony_ci		.switch_event	    = latency_switch_event,
35318c2ecf20Sopenharmony_ci		.runtime_event	    = latency_runtime_event,
35328c2ecf20Sopenharmony_ci		.migrate_task_event = latency_migrate_task_event,
35338c2ecf20Sopenharmony_ci	};
35348c2ecf20Sopenharmony_ci	struct trace_sched_handler map_ops  = {
35358c2ecf20Sopenharmony_ci		.switch_event	    = map_switch_event,
35368c2ecf20Sopenharmony_ci	};
35378c2ecf20Sopenharmony_ci	struct trace_sched_handler replay_ops  = {
35388c2ecf20Sopenharmony_ci		.wakeup_event	    = replay_wakeup_event,
35398c2ecf20Sopenharmony_ci		.switch_event	    = replay_switch_event,
35408c2ecf20Sopenharmony_ci		.fork_event	    = replay_fork_event,
35418c2ecf20Sopenharmony_ci	};
35428c2ecf20Sopenharmony_ci	unsigned int i;
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
35458c2ecf20Sopenharmony_ci		sched.curr_pid[i] = -1;
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ci	argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
35488c2ecf20Sopenharmony_ci					sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);
35498c2ecf20Sopenharmony_ci	if (!argc)
35508c2ecf20Sopenharmony_ci		usage_with_options(sched_usage, sched_options);
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_ci	/*
35538c2ecf20Sopenharmony_ci	 * Aliased to 'perf script' for now:
35548c2ecf20Sopenharmony_ci	 */
35558c2ecf20Sopenharmony_ci	if (!strcmp(argv[0], "script"))
35568c2ecf20Sopenharmony_ci		return cmd_script(argc, argv);
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci	if (!strncmp(argv[0], "rec", 3)) {
35598c2ecf20Sopenharmony_ci		return __cmd_record(argc, argv);
35608c2ecf20Sopenharmony_ci	} else if (!strncmp(argv[0], "lat", 3)) {
35618c2ecf20Sopenharmony_ci		sched.tp_handler = &lat_ops;
35628c2ecf20Sopenharmony_ci		if (argc > 1) {
35638c2ecf20Sopenharmony_ci			argc = parse_options(argc, argv, latency_options, latency_usage, 0);
35648c2ecf20Sopenharmony_ci			if (argc)
35658c2ecf20Sopenharmony_ci				usage_with_options(latency_usage, latency_options);
35668c2ecf20Sopenharmony_ci		}
35678c2ecf20Sopenharmony_ci		setup_sorting(&sched, latency_options, latency_usage);
35688c2ecf20Sopenharmony_ci		return perf_sched__lat(&sched);
35698c2ecf20Sopenharmony_ci	} else if (!strcmp(argv[0], "map")) {
35708c2ecf20Sopenharmony_ci		if (argc) {
35718c2ecf20Sopenharmony_ci			argc = parse_options(argc, argv, map_options, map_usage, 0);
35728c2ecf20Sopenharmony_ci			if (argc)
35738c2ecf20Sopenharmony_ci				usage_with_options(map_usage, map_options);
35748c2ecf20Sopenharmony_ci		}
35758c2ecf20Sopenharmony_ci		sched.tp_handler = &map_ops;
35768c2ecf20Sopenharmony_ci		setup_sorting(&sched, latency_options, latency_usage);
35778c2ecf20Sopenharmony_ci		return perf_sched__map(&sched);
35788c2ecf20Sopenharmony_ci	} else if (!strncmp(argv[0], "rep", 3)) {
35798c2ecf20Sopenharmony_ci		sched.tp_handler = &replay_ops;
35808c2ecf20Sopenharmony_ci		if (argc) {
35818c2ecf20Sopenharmony_ci			argc = parse_options(argc, argv, replay_options, replay_usage, 0);
35828c2ecf20Sopenharmony_ci			if (argc)
35838c2ecf20Sopenharmony_ci				usage_with_options(replay_usage, replay_options);
35848c2ecf20Sopenharmony_ci		}
35858c2ecf20Sopenharmony_ci		return perf_sched__replay(&sched);
35868c2ecf20Sopenharmony_ci	} else if (!strcmp(argv[0], "timehist")) {
35878c2ecf20Sopenharmony_ci		if (argc) {
35888c2ecf20Sopenharmony_ci			argc = parse_options(argc, argv, timehist_options,
35898c2ecf20Sopenharmony_ci					     timehist_usage, 0);
35908c2ecf20Sopenharmony_ci			if (argc)
35918c2ecf20Sopenharmony_ci				usage_with_options(timehist_usage, timehist_options);
35928c2ecf20Sopenharmony_ci		}
35938c2ecf20Sopenharmony_ci		if ((sched.show_wakeups || sched.show_next) &&
35948c2ecf20Sopenharmony_ci		    sched.summary_only) {
35958c2ecf20Sopenharmony_ci			pr_err(" Error: -s and -[n|w] are mutually exclusive.\n");
35968c2ecf20Sopenharmony_ci			parse_options_usage(timehist_usage, timehist_options, "s", true);
35978c2ecf20Sopenharmony_ci			if (sched.show_wakeups)
35988c2ecf20Sopenharmony_ci				parse_options_usage(NULL, timehist_options, "w", true);
35998c2ecf20Sopenharmony_ci			if (sched.show_next)
36008c2ecf20Sopenharmony_ci				parse_options_usage(NULL, timehist_options, "n", true);
36018c2ecf20Sopenharmony_ci			return -EINVAL;
36028c2ecf20Sopenharmony_ci		}
36038c2ecf20Sopenharmony_ci
36048c2ecf20Sopenharmony_ci		return perf_sched__timehist(&sched);
36058c2ecf20Sopenharmony_ci	} else {
36068c2ecf20Sopenharmony_ci		usage_with_options(sched_usage, sched_options);
36078c2ecf20Sopenharmony_ci	}
36088c2ecf20Sopenharmony_ci
36098c2ecf20Sopenharmony_ci	return 0;
36108c2ecf20Sopenharmony_ci}
3611