linux/tools/perf/builtin-sched.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include "builtin.h"
   3#include "perf.h"
   4#include "perf-sys.h"
   5
   6#include "util/cpumap.h"
   7#include "util/evlist.h"
   8#include "util/evsel.h"
   9#include "util/evsel_fprintf.h"
  10#include "util/symbol.h"
  11#include "util/thread.h"
  12#include "util/header.h"
  13#include "util/session.h"
  14#include "util/tool.h"
  15#include "util/cloexec.h"
  16#include "util/thread_map.h"
  17#include "util/color.h"
  18#include "util/stat.h"
  19#include "util/string2.h"
  20#include "util/callchain.h"
  21#include "util/time-utils.h"
  22
  23#include <subcmd/pager.h>
  24#include <subcmd/parse-options.h>
  25#include "util/trace-event.h"
  26
  27#include "util/debug.h"
  28#include "util/event.h"
  29
  30#include <linux/kernel.h>
  31#include <linux/log2.h>
  32#include <linux/zalloc.h>
  33#include <sys/prctl.h>
  34#include <sys/resource.h>
  35#include <inttypes.h>
  36
  37#include <errno.h>
  38#include <semaphore.h>
  39#include <pthread.h>
  40#include <math.h>
  41#include <api/fs/fs.h>
  42#include <perf/cpumap.h>
  43#include <linux/time64.h>
  44#include <linux/err.h>
  45
  46#include <linux/ctype.h>
  47
  48#define PR_SET_NAME             15               /* Set process name */
  49#define MAX_CPUS                4096
  50#define COMM_LEN                20
  51#define SYM_LEN                 129
  52#define MAX_PID                 1024000
  53
  54static const char *cpu_list;
  55static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
  56
  57struct sched_atom;
  58
  59struct task_desc {
  60        unsigned long           nr;
  61        unsigned long           pid;
  62        char                    comm[COMM_LEN];
  63
  64        unsigned long           nr_events;
  65        unsigned long           curr_event;
  66        struct sched_atom       **atoms;
  67
  68        pthread_t               thread;
  69        sem_t                   sleep_sem;
  70
  71        sem_t                   ready_for_work;
  72        sem_t                   work_done_sem;
  73
  74        u64                     cpu_usage;
  75};
  76
  77enum sched_event_type {
  78        SCHED_EVENT_RUN,
  79        SCHED_EVENT_SLEEP,
  80        SCHED_EVENT_WAKEUP,
  81        SCHED_EVENT_MIGRATION,
  82};
  83
  84struct sched_atom {
  85        enum sched_event_type   type;
  86        int                     specific_wait;
  87        u64                     timestamp;
  88        u64                     duration;
  89        unsigned long           nr;
  90        sem_t                   *wait_sem;
  91        struct task_desc        *wakee;
  92};
  93
  94#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
  95
  96/* task state bitmask, copied from include/linux/sched.h */
  97#define TASK_RUNNING            0
  98#define TASK_INTERRUPTIBLE      1
  99#define TASK_UNINTERRUPTIBLE    2
 100#define __TASK_STOPPED          4
 101#define __TASK_TRACED           8
 102/* in tsk->exit_state */
 103#define EXIT_DEAD               16
 104#define EXIT_ZOMBIE             32
 105#define EXIT_TRACE              (EXIT_ZOMBIE | EXIT_DEAD)
 106/* in tsk->state again */
 107#define TASK_DEAD               64
 108#define TASK_WAKEKILL           128
 109#define TASK_WAKING             256
 110#define TASK_PARKED             512
 111
 112enum thread_state {
 113        THREAD_SLEEPING = 0,
 114        THREAD_WAIT_CPU,
 115        THREAD_SCHED_IN,
 116        THREAD_IGNORE
 117};
 118
 119struct work_atom {
 120        struct list_head        list;
 121        enum thread_state       state;
 122        u64                     sched_out_time;
 123        u64                     wake_up_time;
 124        u64                     sched_in_time;
 125        u64                     runtime;
 126};
 127
 128struct work_atoms {
 129        struct list_head        work_list;
 130        struct thread           *thread;
 131        struct rb_node          node;
 132        u64                     max_lat;
 133        u64                     max_lat_start;
 134        u64                     max_lat_end;
 135        u64                     total_lat;
 136        u64                     nb_atoms;
 137        u64                     total_runtime;
 138        int                     num_merged;
 139};
 140
 141typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
 142
 143struct perf_sched;
 144
 145struct trace_sched_handler {
 146        int (*switch_event)(struct perf_sched *sched, struct evsel *evsel,
 147                            struct perf_sample *sample, struct machine *machine);
 148
 149        int (*runtime_event)(struct perf_sched *sched, struct evsel *evsel,
 150                             struct perf_sample *sample, struct machine *machine);
 151
 152        int (*wakeup_event)(struct perf_sched *sched, struct evsel *evsel,
 153                            struct perf_sample *sample, struct machine *machine);
 154
 155        /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
 156        int (*fork_event)(struct perf_sched *sched, union perf_event *event,
 157                          struct machine *machine);
 158
 159        int (*migrate_task_event)(struct perf_sched *sched,
 160                                  struct evsel *evsel,
 161                                  struct perf_sample *sample,
 162                                  struct machine *machine);
 163};
 164
 165#define COLOR_PIDS PERF_COLOR_BLUE
 166#define COLOR_CPUS PERF_COLOR_BG_RED
 167
 168struct perf_sched_map {
 169        DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS);
 170        int                     *comp_cpus;
 171        bool                     comp;
 172        struct perf_thread_map *color_pids;
 173        const char              *color_pids_str;
 174        struct perf_cpu_map     *color_cpus;
 175        const char              *color_cpus_str;
 176        struct perf_cpu_map     *cpus;
 177        const char              *cpus_str;
 178};
 179
 180struct perf_sched {
 181        struct perf_tool tool;
 182        const char       *sort_order;
 183        unsigned long    nr_tasks;
 184        struct task_desc **pid_to_task;
 185        struct task_desc **tasks;
 186        const struct trace_sched_handler *tp_handler;
 187        pthread_mutex_t  start_work_mutex;
 188        pthread_mutex_t  work_done_wait_mutex;
 189        int              profile_cpu;
 190/*
 191 * Track the current task - that way we can know whether there's any
 192 * weird events, such as a task being switched away that is not current.
 193 */
 194        int              max_cpu;
 195        u32              curr_pid[MAX_CPUS];
 196        struct thread    *curr_thread[MAX_CPUS];
 197        char             next_shortname1;
 198        char             next_shortname2;
 199        unsigned int     replay_repeat;
 200        unsigned long    nr_run_events;
 201        unsigned long    nr_sleep_events;
 202        unsigned long    nr_wakeup_events;
 203        unsigned long    nr_sleep_corrections;
 204        unsigned long    nr_run_events_optimized;
 205        unsigned long    targetless_wakeups;
 206        unsigned long    multitarget_wakeups;
 207        unsigned long    nr_runs;
 208        unsigned long    nr_timestamps;
 209        unsigned long    nr_unordered_timestamps;
 210        unsigned long    nr_context_switch_bugs;
 211        unsigned long    nr_events;
 212        unsigned long    nr_lost_chunks;
 213        unsigned long    nr_lost_events;
 214        u64              run_measurement_overhead;
 215        u64              sleep_measurement_overhead;
 216        u64              start_time;
 217        u64              cpu_usage;
 218        u64              runavg_cpu_usage;
 219        u64              parent_cpu_usage;
 220        u64              runavg_parent_cpu_usage;
 221        u64              sum_runtime;
 222        u64              sum_fluct;
 223        u64              run_avg;
 224        u64              all_runtime;
 225        u64              all_count;
 226        u64              cpu_last_switched[MAX_CPUS];
 227        struct rb_root_cached atom_root, sorted_atom_root, merged_atom_root;
 228        struct list_head sort_list, cmp_pid;
 229        bool force;
 230        bool skip_merge;
 231        struct perf_sched_map map;
 232
 233        /* options for timehist command */
 234        bool            summary;
 235        bool            summary_only;
 236        bool            idle_hist;
 237        bool            show_callchain;
 238        unsigned int    max_stack;
 239        bool            show_cpu_visual;
 240        bool            show_wakeups;
 241        bool            show_next;
 242        bool            show_migrations;
 243        bool            show_state;
 244        u64             skipped_samples;
 245        const char      *time_str;
 246        struct perf_time_interval ptime;
 247        struct perf_time_interval hist_time;
 248};
 249
 250/* per thread run time data */
 251struct thread_runtime {
 252        u64 last_time;      /* time of previous sched in/out event */
 253        u64 dt_run;         /* run time */
 254        u64 dt_sleep;       /* time between CPU access by sleep (off cpu) */
 255        u64 dt_iowait;      /* time between CPU access by iowait (off cpu) */
 256        u64 dt_preempt;     /* time between CPU access by preempt (off cpu) */
 257        u64 dt_delay;       /* time between wakeup and sched-in */
 258        u64 ready_to_run;   /* time of wakeup */
 259
 260        struct stats run_stats;
 261        u64 total_run_time;
 262        u64 total_sleep_time;
 263        u64 total_iowait_time;
 264        u64 total_preempt_time;
 265        u64 total_delay_time;
 266
 267        int last_state;
 268
 269        char shortname[3];
 270        bool comm_changed;
 271
 272        u64 migrations;
 273};
 274
 275/* per event run time data */
 276struct evsel_runtime {
 277        u64 *last_time; /* time this event was last seen per cpu */
 278        u32 ncpu;       /* highest cpu slot allocated */
 279};
 280
 281/* per cpu idle time data */
 282struct idle_thread_runtime {
 283        struct thread_runtime   tr;
 284        struct thread           *last_thread;
 285        struct rb_root_cached   sorted_root;
 286        struct callchain_root   callchain;
 287        struct callchain_cursor cursor;
 288};
 289
 290/* track idle times per cpu */
 291static struct thread **idle_threads;
 292static int idle_max_cpu;
 293static char idle_comm[] = "<idle>";
 294
 295static u64 get_nsecs(void)
 296{
 297        struct timespec ts;
 298
 299        clock_gettime(CLOCK_MONOTONIC, &ts);
 300
 301        return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
 302}
 303
 304static void burn_nsecs(struct perf_sched *sched, u64 nsecs)
 305{
 306        u64 T0 = get_nsecs(), T1;
 307
 308        do {
 309                T1 = get_nsecs();
 310        } while (T1 + sched->run_measurement_overhead < T0 + nsecs);
 311}
 312
 313static void sleep_nsecs(u64 nsecs)
 314{
 315        struct timespec ts;
 316
 317        ts.tv_nsec = nsecs % 999999999;
 318        ts.tv_sec = nsecs / 999999999;
 319
 320        nanosleep(&ts, NULL);
 321}
 322
 323static void calibrate_run_measurement_overhead(struct perf_sched *sched)
 324{
 325        u64 T0, T1, delta, min_delta = NSEC_PER_SEC;
 326        int i;
 327
 328        for (i = 0; i < 10; i++) {
 329                T0 = get_nsecs();
 330                burn_nsecs(sched, 0);
 331                T1 = get_nsecs();
 332                delta = T1-T0;
 333                min_delta = min(min_delta, delta);
 334        }
 335        sched->run_measurement_overhead = min_delta;
 336
 337        printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
 338}
 339
 340static void calibrate_sleep_measurement_overhead(struct perf_sched *sched)
 341{
 342        u64 T0, T1, delta, min_delta = NSEC_PER_SEC;
 343        int i;
 344
 345        for (i = 0; i < 10; i++) {
 346                T0 = get_nsecs();
 347                sleep_nsecs(10000);
 348                T1 = get_nsecs();
 349                delta = T1-T0;
 350                min_delta = min(min_delta, delta);
 351        }
 352        min_delta -= 10000;
 353        sched->sleep_measurement_overhead = min_delta;
 354
 355        printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
 356}
 357
 358static struct sched_atom *
 359get_new_event(struct task_desc *task, u64 timestamp)
 360{
 361        struct sched_atom *event = zalloc(sizeof(*event));
 362        unsigned long idx = task->nr_events;
 363        size_t size;
 364
 365        event->timestamp = timestamp;
 366        event->nr = idx;
 367
 368        task->nr_events++;
 369        size = sizeof(struct sched_atom *) * task->nr_events;
 370        task->atoms = realloc(task->atoms, size);
 371        BUG_ON(!task->atoms);
 372
 373        task->atoms[idx] = event;
 374
 375        return event;
 376}
 377
 378static struct sched_atom *last_event(struct task_desc *task)
 379{
 380        if (!task->nr_events)
 381                return NULL;
 382
 383        return task->atoms[task->nr_events - 1];
 384}
 385
 386static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task,
 387                                u64 timestamp, u64 duration)
 388{
 389        struct sched_atom *event, *curr_event = last_event(task);
 390
 391        /*
 392         * optimize an existing RUN event by merging this one
 393         * to it:
 394         */
 395        if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
 396                sched->nr_run_events_optimized++;
 397                curr_event->duration += duration;
 398                return;
 399        }
 400
 401        event = get_new_event(task, timestamp);
 402
 403        event->type = SCHED_EVENT_RUN;
 404        event->duration = duration;
 405
 406        sched->nr_run_events++;
 407}
 408
 409static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *task,
 410                                   u64 timestamp, struct task_desc *wakee)
 411{
 412        struct sched_atom *event, *wakee_event;
 413
 414        event = get_new_event(task, timestamp);
 415        event->type = SCHED_EVENT_WAKEUP;
 416        event->wakee = wakee;
 417
 418        wakee_event = last_event(wakee);
 419        if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
 420                sched->targetless_wakeups++;
 421                return;
 422        }
 423        if (wakee_event->wait_sem) {
 424                sched->multitarget_wakeups++;
 425                return;
 426        }
 427
 428        wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
 429        sem_init(wakee_event->wait_sem, 0, 0);
 430        wakee_event->specific_wait = 1;
 431        event->wait_sem = wakee_event->wait_sem;
 432
 433        sched->nr_wakeup_events++;
 434}
 435
 436static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task,
 437                                  u64 timestamp, u64 task_state __maybe_unused)
 438{
 439        struct sched_atom *event = get_new_event(task, timestamp);
 440
 441        event->type = SCHED_EVENT_SLEEP;
 442
 443        sched->nr_sleep_events++;
 444}
 445
 446static struct task_desc *register_pid(struct perf_sched *sched,
 447                                      unsigned long pid, const char *comm)
 448{
 449        struct task_desc *task;
 450        static int pid_max;
 451
 452        if (sched->pid_to_task == NULL) {
 453                if (sysctl__read_int("kernel/pid_max", &pid_max) < 0)
 454                        pid_max = MAX_PID;
 455                BUG_ON((sched->pid_to_task = calloc(pid_max, sizeof(struct task_desc *))) == NULL);
 456        }
 457        if (pid >= (unsigned long)pid_max) {
 458                BUG_ON((sched->pid_to_task = realloc(sched->pid_to_task, (pid + 1) *
 459                        sizeof(struct task_desc *))) == NULL);
 460                while (pid >= (unsigned long)pid_max)
 461                        sched->pid_to_task[pid_max++] = NULL;
 462        }
 463
 464        task = sched->pid_to_task[pid];
 465
 466        if (task)
 467                return task;
 468
 469        task = zalloc(sizeof(*task));
 470        task->pid = pid;
 471        task->nr = sched->nr_tasks;
 472        strcpy(task->comm, comm);
 473        /*
 474         * every task starts in sleeping state - this gets ignored
 475         * if there's no wakeup pointing to this sleep state:
 476         */
 477        add_sched_event_sleep(sched, task, 0, 0);
 478
 479        sched->pid_to_task[pid] = task;
 480        sched->nr_tasks++;
 481        sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_desc *));
 482        BUG_ON(!sched->tasks);
 483        sched->tasks[task->nr] = task;
 484
 485        if (verbose > 0)
 486                printf("registered task #%ld, PID %ld (%s)\n", sched->nr_tasks, pid, comm);
 487
 488        return task;
 489}
 490
 491
 492static void print_task_traces(struct perf_sched *sched)
 493{
 494        struct task_desc *task;
 495        unsigned long i;
 496
 497        for (i = 0; i < sched->nr_tasks; i++) {
 498                task = sched->tasks[i];
 499                printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
 500                        task->nr, task->comm, task->pid, task->nr_events);
 501        }
 502}
 503
 504static void add_cross_task_wakeups(struct perf_sched *sched)
 505{
 506        struct task_desc *task1, *task2;
 507        unsigned long i, j;
 508
 509        for (i = 0; i < sched->nr_tasks; i++) {
 510                task1 = sched->tasks[i];
 511                j = i + 1;
 512                if (j == sched->nr_tasks)
 513                        j = 0;
 514                task2 = sched->tasks[j];
 515                add_sched_event_wakeup(sched, task1, 0, task2);
 516        }
 517}
 518
 519static void perf_sched__process_event(struct perf_sched *sched,
 520                                      struct sched_atom *atom)
 521{
 522        int ret = 0;
 523
 524        switch (atom->type) {
 525                case SCHED_EVENT_RUN:
 526                        burn_nsecs(sched, atom->duration);
 527                        break;
 528                case SCHED_EVENT_SLEEP:
 529                        if (atom->wait_sem)
 530                                ret = sem_wait(atom->wait_sem);
 531                        BUG_ON(ret);
 532                        break;
 533                case SCHED_EVENT_WAKEUP:
 534                        if (atom->wait_sem)
 535                                ret = sem_post(atom->wait_sem);
 536                        BUG_ON(ret);
 537                        break;
 538                case SCHED_EVENT_MIGRATION:
 539                        break;
 540                default:
 541                        BUG_ON(1);
 542        }
 543}
 544
 545static u64 get_cpu_usage_nsec_parent(void)
 546{
 547        struct rusage ru;
 548        u64 sum;
 549        int err;
 550
 551        err = getrusage(RUSAGE_SELF, &ru);
 552        BUG_ON(err);
 553
 554        sum =  ru.ru_utime.tv_sec * NSEC_PER_SEC + ru.ru_utime.tv_usec * NSEC_PER_USEC;
 555        sum += ru.ru_stime.tv_sec * NSEC_PER_SEC + ru.ru_stime.tv_usec * NSEC_PER_USEC;
 556
 557        return sum;
 558}
 559
 560static int self_open_counters(struct perf_sched *sched, unsigned long cur_task)
 561{
 562        struct perf_event_attr attr;
 563        char sbuf[STRERR_BUFSIZE], info[STRERR_BUFSIZE];
 564        int fd;
 565        struct rlimit limit;
 566        bool need_privilege = false;
 567
 568        memset(&attr, 0, sizeof(attr));
 569
 570        attr.type = PERF_TYPE_SOFTWARE;
 571        attr.config = PERF_COUNT_SW_TASK_CLOCK;
 572
 573force_again:
 574        fd = sys_perf_event_open(&attr, 0, -1, -1,
 575                                 perf_event_open_cloexec_flag());
 576
 577        if (fd < 0) {
 578                if (errno == EMFILE) {
 579                        if (sched->force) {
 580                                BUG_ON(getrlimit(RLIMIT_NOFILE, &limit) == -1);
 581                                limit.rlim_cur += sched->nr_tasks - cur_task;
 582                                if (limit.rlim_cur > limit.rlim_max) {
 583                                        limit.rlim_max = limit.rlim_cur;
 584                                        need_privilege = true;
 585                                }
 586                                if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
 587                                        if (need_privilege && errno == EPERM)
 588                                                strcpy(info, "Need privilege\n");
 589                                } else
 590                                        goto force_again;
 591                        } else
 592                                strcpy(info, "Have a try with -f option\n");
 593                }
 594                pr_err("Error: sys_perf_event_open() syscall returned "
 595                       "with %d (%s)\n%s", fd,
 596                       str_error_r(errno, sbuf, sizeof(sbuf)), info);
 597                exit(EXIT_FAILURE);
 598        }
 599        return fd;
 600}
 601
 602static u64 get_cpu_usage_nsec_self(int fd)
 603{
 604        u64 runtime;
 605        int ret;
 606
 607        ret = read(fd, &runtime, sizeof(runtime));
 608        BUG_ON(ret != sizeof(runtime));
 609
 610        return runtime;
 611}
 612
 613struct sched_thread_parms {
 614        struct task_desc  *task;
 615        struct perf_sched *sched;
 616        int fd;
 617};
 618
 619static void *thread_func(void *ctx)
 620{
 621        struct sched_thread_parms *parms = ctx;
 622        struct task_desc *this_task = parms->task;
 623        struct perf_sched *sched = parms->sched;
 624        u64 cpu_usage_0, cpu_usage_1;
 625        unsigned long i, ret;
 626        char comm2[22];
 627        int fd = parms->fd;
 628
 629        zfree(&parms);
 630
 631        sprintf(comm2, ":%s", this_task->comm);
 632        prctl(PR_SET_NAME, comm2);
 633        if (fd < 0)
 634                return NULL;
 635again:
 636        ret = sem_post(&this_task->ready_for_work);
 637        BUG_ON(ret);
 638        ret = pthread_mutex_lock(&sched->start_work_mutex);
 639        BUG_ON(ret);
 640        ret = pthread_mutex_unlock(&sched->start_work_mutex);
 641        BUG_ON(ret);
 642
 643        cpu_usage_0 = get_cpu_usage_nsec_self(fd);
 644
 645        for (i = 0; i < this_task->nr_events; i++) {
 646                this_task->curr_event = i;
 647                perf_sched__process_event(sched, this_task->atoms[i]);
 648        }
 649
 650        cpu_usage_1 = get_cpu_usage_nsec_self(fd);
 651        this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
 652        ret = sem_post(&this_task->work_done_sem);
 653        BUG_ON(ret);
 654
 655        ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
 656        BUG_ON(ret);
 657        ret = pthread_mutex_unlock(&sched->work_done_wait_mutex);
 658        BUG_ON(ret);
 659
 660        goto again;
 661}
 662
 663static void create_tasks(struct perf_sched *sched)
 664{
 665        struct task_desc *task;
 666        pthread_attr_t attr;
 667        unsigned long i;
 668        int err;
 669
 670        err = pthread_attr_init(&attr);
 671        BUG_ON(err);
 672        err = pthread_attr_setstacksize(&attr,
 673                        (size_t) max(16 * 1024, (int)PTHREAD_STACK_MIN));
 674        BUG_ON(err);
 675        err = pthread_mutex_lock(&sched->start_work_mutex);
 676        BUG_ON(err);
 677        err = pthread_mutex_lock(&sched->work_done_wait_mutex);
 678        BUG_ON(err);
 679        for (i = 0; i < sched->nr_tasks; i++) {
 680                struct sched_thread_parms *parms = malloc(sizeof(*parms));
 681                BUG_ON(parms == NULL);
 682                parms->task = task = sched->tasks[i];
 683                parms->sched = sched;
 684                parms->fd = self_open_counters(sched, i);
 685                sem_init(&task->sleep_sem, 0, 0);
 686                sem_init(&task->ready_for_work, 0, 0);
 687                sem_init(&task->work_done_sem, 0, 0);
 688                task->curr_event = 0;
 689                err = pthread_create(&task->thread, &attr, thread_func, parms);
 690                BUG_ON(err);
 691        }
 692}
 693
 694static void wait_for_tasks(struct perf_sched *sched)
 695{
 696        u64 cpu_usage_0, cpu_usage_1;
 697        struct task_desc *task;
 698        unsigned long i, ret;
 699
 700        sched->start_time = get_nsecs();
 701        sched->cpu_usage = 0;
 702        pthread_mutex_unlock(&sched->work_done_wait_mutex);
 703
 704        for (i = 0; i < sched->nr_tasks; i++) {
 705                task = sched->tasks[i];
 706                ret = sem_wait(&task->ready_for_work);
 707                BUG_ON(ret);
 708                sem_init(&task->ready_for_work, 0, 0);
 709        }
 710        ret = pthread_mutex_lock(&sched->work_done_wait_mutex);
 711        BUG_ON(ret);
 712
 713        cpu_usage_0 = get_cpu_usage_nsec_parent();
 714
 715        pthread_mutex_unlock(&sched->start_work_mutex);
 716
 717        for (i = 0; i < sched->nr_tasks; i++) {
 718                task = sched->tasks[i];
 719                ret = sem_wait(&task->work_done_sem);
 720                BUG_ON(ret);
 721                sem_init(&task->work_done_sem, 0, 0);
 722                sched->cpu_usage += task->cpu_usage;
 723                task->cpu_usage = 0;
 724        }
 725
 726        cpu_usage_1 = get_cpu_usage_nsec_parent();
 727        if (!sched->runavg_cpu_usage)
 728                sched->runavg_cpu_usage = sched->cpu_usage;
 729        sched->runavg_cpu_usage = (sched->runavg_cpu_usage * (sched->replay_repeat - 1) + sched->cpu_usage) / sched->replay_repeat;
 730
 731        sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
 732        if (!sched->runavg_parent_cpu_usage)
 733                sched->runavg_parent_cpu_usage = sched->parent_cpu_usage;
 734        sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * (sched->replay_repeat - 1) +
 735                                         sched->parent_cpu_usage)/sched->replay_repeat;
 736
 737        ret = pthread_mutex_lock(&sched->start_work_mutex);
 738        BUG_ON(ret);
 739
 740        for (i = 0; i < sched->nr_tasks; i++) {
 741                task = sched->tasks[i];
 742                sem_init(&task->sleep_sem, 0, 0);
 743                task->curr_event = 0;
 744        }
 745}
 746
 747static void run_one_test(struct perf_sched *sched)
 748{
 749        u64 T0, T1, delta, avg_delta, fluct;
 750
 751        T0 = get_nsecs();
 752        wait_for_tasks(sched);
 753        T1 = get_nsecs();
 754
 755        delta = T1 - T0;
 756        sched->sum_runtime += delta;
 757        sched->nr_runs++;
 758
 759        avg_delta = sched->sum_runtime / sched->nr_runs;
 760        if (delta < avg_delta)
 761                fluct = avg_delta - delta;
 762        else
 763                fluct = delta - avg_delta;
 764        sched->sum_fluct += fluct;
 765        if (!sched->run_avg)
 766                sched->run_avg = delta;
 767        sched->run_avg = (sched->run_avg * (sched->replay_repeat - 1) + delta) / sched->replay_repeat;
 768
 769        printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / NSEC_PER_MSEC);
 770
 771        printf("ravg: %0.2f, ", (double)sched->run_avg / NSEC_PER_MSEC);
 772
 773        printf("cpu: %0.2f / %0.2f",
 774                (double)sched->cpu_usage / NSEC_PER_MSEC, (double)sched->runavg_cpu_usage / NSEC_PER_MSEC);
 775
 776#if 0
 777        /*
 778         * rusage statistics done by the parent, these are less
 779         * accurate than the sched->sum_exec_runtime based statistics:
 780         */
 781        printf(" [%0.2f / %0.2f]",
 782                (double)sched->parent_cpu_usage / NSEC_PER_MSEC,
 783                (double)sched->runavg_parent_cpu_usage / NSEC_PER_MSEC);
 784#endif
 785
 786        printf("\n");
 787
 788        if (sched->nr_sleep_corrections)
 789                printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections);
 790        sched->nr_sleep_corrections = 0;
 791}
 792
 793static void test_calibrations(struct perf_sched *sched)
 794{
 795        u64 T0, T1;
 796
 797        T0 = get_nsecs();
 798        burn_nsecs(sched, NSEC_PER_MSEC);
 799        T1 = get_nsecs();
 800
 801        printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
 802
 803        T0 = get_nsecs();
 804        sleep_nsecs(NSEC_PER_MSEC);
 805        T1 = get_nsecs();
 806
 807        printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
 808}
 809
 810static int
 811replay_wakeup_event(struct perf_sched *sched,
 812                    struct evsel *evsel, struct perf_sample *sample,
 813                    struct machine *machine __maybe_unused)
 814{
 815        const char *comm = evsel__strval(evsel, sample, "comm");
 816        const u32 pid    = evsel__intval(evsel, sample, "pid");
 817        struct task_desc *waker, *wakee;
 818
 819        if (verbose > 0) {
 820                printf("sched_wakeup event %p\n", evsel);
 821
 822                printf(" ... pid %d woke up %s/%d\n", sample->tid, comm, pid);
 823        }
 824
 825        waker = register_pid(sched, sample->tid, "<unknown>");
 826        wakee = register_pid(sched, pid, comm);
 827
 828        add_sched_event_wakeup(sched, waker, sample->time, wakee);
 829        return 0;
 830}
 831
 832static int replay_switch_event(struct perf_sched *sched,
 833                               struct evsel *evsel,
 834                               struct perf_sample *sample,
 835                               struct machine *machine __maybe_unused)
 836{
 837        const char *prev_comm  = evsel__strval(evsel, sample, "prev_comm"),
 838                   *next_comm  = evsel__strval(evsel, sample, "next_comm");
 839        const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"),
 840                  next_pid = evsel__intval(evsel, sample, "next_pid");
 841        const u64 prev_state = evsel__intval(evsel, sample, "prev_state");
 842        struct task_desc *prev, __maybe_unused *next;
 843        u64 timestamp0, timestamp = sample->time;
 844        int cpu = sample->cpu;
 845        s64 delta;
 846
 847        if (verbose > 0)
 848                printf("sched_switch event %p\n", evsel);
 849
 850        if (cpu >= MAX_CPUS || cpu < 0)
 851                return 0;
 852
 853        timestamp0 = sched->cpu_last_switched[cpu];
 854        if (timestamp0)
 855                delta = timestamp - timestamp0;
 856        else
 857                delta = 0;
 858
 859        if (delta < 0) {
 860                pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
 861                return -1;
 862        }
 863
 864        pr_debug(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
 865                 prev_comm, prev_pid, next_comm, next_pid, delta);
 866
 867        prev = register_pid(sched, prev_pid, prev_comm);
 868        next = register_pid(sched, next_pid, next_comm);
 869
 870        sched->cpu_last_switched[cpu] = timestamp;
 871
 872        add_sched_event_run(sched, prev, timestamp, delta);
 873        add_sched_event_sleep(sched, prev, timestamp, prev_state);
 874
 875        return 0;
 876}
 877
 878static int replay_fork_event(struct perf_sched *sched,
 879                             union perf_event *event,
 880                             struct machine *machine)
 881{
 882        struct thread *child, *parent;
 883
 884        child = machine__findnew_thread(machine, event->fork.pid,
 885                                        event->fork.tid);
 886        parent = machine__findnew_thread(machine, event->fork.ppid,
 887                                         event->fork.ptid);
 888
 889        if (child == NULL || parent == NULL) {
 890                pr_debug("thread does not exist on fork event: child %p, parent %p\n",
 891                                 child, parent);
 892                goto out_put;
 893        }
 894
 895        if (verbose > 0) {
 896                printf("fork event\n");
 897                printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
 898                printf("...  child: %s/%d\n", thread__comm_str(child), child->tid);
 899        }
 900
 901        register_pid(sched, parent->tid, thread__comm_str(parent));
 902        register_pid(sched, child->tid, thread__comm_str(child));
 903out_put:
 904        thread__put(child);
 905        thread__put(parent);
 906        return 0;
 907}
 908
 909struct sort_dimension {
 910        const char              *name;
 911        sort_fn_t               cmp;
 912        struct list_head        list;
 913};
 914
 915/*
 916 * handle runtime stats saved per thread
 917 */
 918static struct thread_runtime *thread__init_runtime(struct thread *thread)
 919{
 920        struct thread_runtime *r;
 921
 922        r = zalloc(sizeof(struct thread_runtime));
 923        if (!r)
 924                return NULL;
 925
 926        init_stats(&r->run_stats);
 927        thread__set_priv(thread, r);
 928
 929        return r;
 930}
 931
 932static struct thread_runtime *thread__get_runtime(struct thread *thread)
 933{
 934        struct thread_runtime *tr;
 935
 936        tr = thread__priv(thread);
 937        if (tr == NULL) {
 938                tr = thread__init_runtime(thread);
 939                if (tr == NULL)
 940                        pr_debug("Failed to malloc memory for runtime data.\n");
 941        }
 942
 943        return tr;
 944}
 945
 946static int
 947thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
 948{
 949        struct sort_dimension *sort;
 950        int ret = 0;
 951
 952        BUG_ON(list_empty(list));
 953
 954        list_for_each_entry(sort, list, list) {
 955                ret = sort->cmp(l, r);
 956                if (ret)
 957                        return ret;
 958        }
 959
 960        return ret;
 961}
 962
 963static struct work_atoms *
 964thread_atoms_search(struct rb_root_cached *root, struct thread *thread,
 965                         struct list_head *sort_list)
 966{
 967        struct rb_node *node = root->rb_root.rb_node;
 968        struct work_atoms key = { .thread = thread };
 969
 970        while (node) {
 971                struct work_atoms *atoms;
 972                int cmp;
 973
 974                atoms = container_of(node, struct work_atoms, node);
 975
 976                cmp = thread_lat_cmp(sort_list, &key, atoms);
 977                if (cmp > 0)
 978                        node = node->rb_left;
 979                else if (cmp < 0)
 980                        node = node->rb_right;
 981                else {
 982                        BUG_ON(thread != atoms->thread);
 983                        return atoms;
 984                }
 985        }
 986        return NULL;
 987}
 988
 989static void
 990__thread_latency_insert(struct rb_root_cached *root, struct work_atoms *data,
 991                         struct list_head *sort_list)
 992{
 993        struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
 994        bool leftmost = true;
 995
 996        while (*new) {
 997                struct work_atoms *this;
 998                int cmp;
 999
1000                this = container_of(*new, struct work_atoms, node);
1001                parent = *new;
1002
1003                cmp = thread_lat_cmp(sort_list, data, this);
1004
1005                if (cmp > 0)
1006                        new = &((*new)->rb_left);
1007                else {
1008                        new = &((*new)->rb_right);
1009                        leftmost = false;
1010                }
1011        }
1012
1013        rb_link_node(&data->node, parent, new);
1014        rb_insert_color_cached(&data->node, root, leftmost);
1015}
1016
1017static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
1018{
1019        struct work_atoms *atoms = zalloc(sizeof(*atoms));
1020        if (!atoms) {
1021                pr_err("No memory at %s\n", __func__);
1022                return -1;
1023        }
1024
1025        atoms->thread = thread__get(thread);
1026        INIT_LIST_HEAD(&atoms->work_list);
1027        __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid);
1028        return 0;
1029}
1030
1031static char sched_out_state(u64 prev_state)
1032{
1033        const char *str = TASK_STATE_TO_CHAR_STR;
1034
1035        return str[prev_state];
1036}
1037
1038static int
1039add_sched_out_event(struct work_atoms *atoms,
1040                    char run_state,
1041                    u64 timestamp)
1042{
1043        struct work_atom *atom = zalloc(sizeof(*atom));
1044        if (!atom) {
1045                pr_err("Non memory at %s", __func__);
1046                return -1;
1047        }
1048
1049        atom->sched_out_time = timestamp;
1050
1051        if (run_state == 'R') {
1052                atom->state = THREAD_WAIT_CPU;
1053                atom->wake_up_time = atom->sched_out_time;
1054        }
1055
1056        list_add_tail(&atom->list, &atoms->work_list);
1057        return 0;
1058}
1059
1060static void
1061add_runtime_event(struct work_atoms *atoms, u64 delta,
1062                  u64 timestamp __maybe_unused)
1063{
1064        struct work_atom *atom;
1065
1066        BUG_ON(list_empty(&atoms->work_list));
1067
1068        atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1069
1070        atom->runtime += delta;
1071        atoms->total_runtime += delta;
1072}
1073
1074static void
1075add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1076{
1077        struct work_atom *atom;
1078        u64 delta;
1079
1080        if (list_empty(&atoms->work_list))
1081                return;
1082
1083        atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1084
1085        if (atom->state != THREAD_WAIT_CPU)
1086                return;
1087
1088        if (timestamp < atom->wake_up_time) {
1089                atom->state = THREAD_IGNORE;
1090                return;
1091        }
1092
1093        atom->state = THREAD_SCHED_IN;
1094        atom->sched_in_time = timestamp;
1095
1096        delta = atom->sched_in_time - atom->wake_up_time;
1097        atoms->total_lat += delta;
1098        if (delta > atoms->max_lat) {
1099                atoms->max_lat = delta;
1100                atoms->max_lat_start = atom->wake_up_time;
1101                atoms->max_lat_end = timestamp;
1102        }
1103        atoms->nb_atoms++;
1104}
1105
1106static int latency_switch_event(struct perf_sched *sched,
1107                                struct evsel *evsel,
1108                                struct perf_sample *sample,
1109                                struct machine *machine)
1110{
1111        const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"),
1112                  next_pid = evsel__intval(evsel, sample, "next_pid");
1113        const u64 prev_state = evsel__intval(evsel, sample, "prev_state");
1114        struct work_atoms *out_events, *in_events;
1115        struct thread *sched_out, *sched_in;
1116        u64 timestamp0, timestamp = sample->time;
1117        int cpu = sample->cpu, err = -1;
1118        s64 delta;
1119
1120        BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1121
1122        timestamp0 = sched->cpu_last_switched[cpu];
1123        sched->cpu_last_switched[cpu] = timestamp;
1124        if (timestamp0)
1125                delta = timestamp - timestamp0;
1126        else
1127                delta = 0;
1128
1129        if (delta < 0) {
1130                pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1131                return -1;
1132        }
1133
1134        sched_out = machine__findnew_thread(machine, -1, prev_pid);
1135        sched_in = machine__findnew_thread(machine, -1, next_pid);
1136        if (sched_out == NULL || sched_in == NULL)
1137                goto out_put;
1138
1139        out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
1140        if (!out_events) {
1141                if (thread_atoms_insert(sched, sched_out))
1142                        goto out_put;
1143                out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
1144                if (!out_events) {
1145                        pr_err("out-event: Internal tree error");
1146                        goto out_put;
1147                }
1148        }
1149        if (add_sched_out_event(out_events, sched_out_state(prev_state), timestamp))
1150                return -1;
1151
1152        in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
1153        if (!in_events) {
1154                if (thread_atoms_insert(sched, sched_in))
1155                        goto out_put;
1156                in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid);
1157                if (!in_events) {
1158                        pr_err("in-event: Internal tree error");
1159                        goto out_put;
1160                }
1161                /*
1162                 * Take came in we have not heard about yet,
1163                 * add in an initial atom in runnable state:
1164                 */
1165                if (add_sched_out_event(in_events, 'R', timestamp))
1166                        goto out_put;
1167        }
1168        add_sched_in_event(in_events, timestamp);
1169        err = 0;
1170out_put:
1171        thread__put(sched_out);
1172        thread__put(sched_in);
1173        return err;
1174}
1175
1176static int latency_runtime_event(struct perf_sched *sched,
1177                                 struct evsel *evsel,
1178                                 struct perf_sample *sample,
1179                                 struct machine *machine)
1180{
1181        const u32 pid      = evsel__intval(evsel, sample, "pid");
1182        const u64 runtime  = evsel__intval(evsel, sample, "runtime");
1183        struct thread *thread = machine__findnew_thread(machine, -1, pid);
1184        struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
1185        u64 timestamp = sample->time;
1186        int cpu = sample->cpu, err = -1;
1187
1188        if (thread == NULL)
1189                return -1;
1190
1191        BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1192        if (!atoms) {
1193                if (thread_atoms_insert(sched, thread))
1194                        goto out_put;
1195                atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
1196                if (!atoms) {
1197                        pr_err("in-event: Internal tree error");
1198                        goto out_put;
1199                }
1200                if (add_sched_out_event(atoms, 'R', timestamp))
1201                        goto out_put;
1202        }
1203
1204        add_runtime_event(atoms, runtime, timestamp);
1205        err = 0;
1206out_put:
1207        thread__put(thread);
1208        return err;
1209}
1210
1211static int latency_wakeup_event(struct perf_sched *sched,
1212                                struct evsel *evsel,
1213                                struct perf_sample *sample,
1214                                struct machine *machine)
1215{
1216        const u32 pid     = evsel__intval(evsel, sample, "pid");
1217        struct work_atoms *atoms;
1218        struct work_atom *atom;
1219        struct thread *wakee;
1220        u64 timestamp = sample->time;
1221        int err = -1;
1222
1223        wakee = machine__findnew_thread(machine, -1, pid);
1224        if (wakee == NULL)
1225                return -1;
1226        atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1227        if (!atoms) {
1228                if (thread_atoms_insert(sched, wakee))
1229                        goto out_put;
1230                atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1231                if (!atoms) {
1232                        pr_err("wakeup-event: Internal tree error");
1233                        goto out_put;
1234                }
1235                if (add_sched_out_event(atoms, 'S', timestamp))
1236                        goto out_put;
1237        }
1238
1239        BUG_ON(list_empty(&atoms->work_list));
1240
1241        atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1242
1243        /*
1244         * As we do not guarantee the wakeup event happens when
1245         * task is out of run queue, also may happen when task is
1246         * on run queue and wakeup only change ->state to TASK_RUNNING,
1247         * then we should not set the ->wake_up_time when wake up a
1248         * task which is on run queue.
1249         *
1250         * You WILL be missing events if you've recorded only
1251         * one CPU, or are only looking at only one, so don't
1252         * skip in this case.
1253         */
1254        if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1255                goto out_ok;
1256
1257        sched->nr_timestamps++;
1258        if (atom->sched_out_time > timestamp) {
1259                sched->nr_unordered_timestamps++;
1260                goto out_ok;
1261        }
1262
1263        atom->state = THREAD_WAIT_CPU;
1264        atom->wake_up_time = timestamp;
1265out_ok:
1266        err = 0;
1267out_put:
1268        thread__put(wakee);
1269        return err;
1270}
1271
1272static int latency_migrate_task_event(struct perf_sched *sched,
1273                                      struct evsel *evsel,
1274                                      struct perf_sample *sample,
1275                                      struct machine *machine)
1276{
1277        const u32 pid = evsel__intval(evsel, sample, "pid");
1278        u64 timestamp = sample->time;
1279        struct work_atoms *atoms;
1280        struct work_atom *atom;
1281        struct thread *migrant;
1282        int err = -1;
1283
1284        /*
1285         * Only need to worry about migration when profiling one CPU.
1286         */
1287        if (sched->profile_cpu == -1)
1288                return 0;
1289
1290        migrant = machine__findnew_thread(machine, -1, pid);
1291        if (migrant == NULL)
1292                return -1;
1293        atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1294        if (!atoms) {
1295                if (thread_atoms_insert(sched, migrant))
1296                        goto out_put;
1297                register_pid(sched, migrant->tid, thread__comm_str(migrant));
1298                atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1299                if (!atoms) {
1300                        pr_err("migration-event: Internal tree error");
1301                        goto out_put;
1302                }
1303                if (add_sched_out_event(atoms, 'R', timestamp))
1304                        goto out_put;
1305        }
1306
1307        BUG_ON(list_empty(&atoms->work_list));
1308
1309        atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1310        atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1311
1312        sched->nr_timestamps++;
1313
1314        if (atom->sched_out_time > timestamp)
1315                sched->nr_unordered_timestamps++;
1316        err = 0;
1317out_put:
1318        thread__put(migrant);
1319        return err;
1320}
1321
1322static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_list)
1323{
1324        int i;
1325        int ret;
1326        u64 avg;
1327        char max_lat_start[32], max_lat_end[32];
1328
1329        if (!work_list->nb_atoms)
1330                return;
1331        /*
1332         * Ignore idle threads:
1333         */
1334        if (!strcmp(thread__comm_str(work_list->thread), "swapper"))
1335                return;
1336
1337        sched->all_runtime += work_list->total_runtime;
1338        sched->all_count   += work_list->nb_atoms;
1339
1340        if (work_list->num_merged > 1)
1341                ret = printf("  %s:(%d) ", thread__comm_str(work_list->thread), work_list->num_merged);
1342        else
1343                ret = printf("  %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid);
1344
1345        for (i = 0; i < 24 - ret; i++)
1346                printf(" ");
1347
1348        avg = work_list->total_lat / work_list->nb_atoms;
1349        timestamp__scnprintf_usec(work_list->max_lat_start, max_lat_start, sizeof(max_lat_start));
1350        timestamp__scnprintf_usec(work_list->max_lat_end, max_lat_end, sizeof(max_lat_end));
1351
1352        printf("|%11.3f ms |%9" PRIu64 " | avg:%8.3f ms | max:%8.3f ms | max start: %12s s | max end: %12s s\n",
1353              (double)work_list->total_runtime / NSEC_PER_MSEC,
1354                 work_list->nb_atoms, (double)avg / NSEC_PER_MSEC,
1355                 (double)work_list->max_lat / NSEC_PER_MSEC,
1356                 max_lat_start, max_lat_end);
1357}
1358
1359static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1360{
1361        if (l->thread == r->thread)
1362                return 0;
1363        if (l->thread->tid < r->thread->tid)
1364                return -1;
1365        if (l->thread->tid > r->thread->tid)
1366                return 1;
1367        return (int)(l->thread - r->thread);
1368}
1369
1370static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
1371{
1372        u64 avgl, avgr;
1373
1374        if (!l->nb_atoms)
1375                return -1;
1376
1377        if (!r->nb_atoms)
1378                return 1;
1379
1380        avgl = l->total_lat / l->nb_atoms;
1381        avgr = r->total_lat / r->nb_atoms;
1382
1383        if (avgl < avgr)
1384                return -1;
1385        if (avgl > avgr)
1386                return 1;
1387
1388        return 0;
1389}
1390
1391static int max_cmp(struct work_atoms *l, struct work_atoms *r)
1392{
1393        if (l->max_lat < r->max_lat)
1394                return -1;
1395        if (l->max_lat > r->max_lat)
1396                return 1;
1397
1398        return 0;
1399}
1400
1401static int switch_cmp(struct work_atoms *l, struct work_atoms *r)
1402{
1403        if (l->nb_atoms < r->nb_atoms)
1404                return -1;
1405        if (l->nb_atoms > r->nb_atoms)
1406                return 1;
1407
1408        return 0;
1409}
1410
1411static int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
1412{
1413        if (l->total_runtime < r->total_runtime)
1414                return -1;
1415        if (l->total_runtime > r->total_runtime)
1416                return 1;
1417
1418        return 0;
1419}
1420
1421static int sort_dimension__add(const char *tok, struct list_head *list)
1422{
1423        size_t i;
1424        static struct sort_dimension avg_sort_dimension = {
1425                .name = "avg",
1426                .cmp  = avg_cmp,
1427        };
1428        static struct sort_dimension max_sort_dimension = {
1429                .name = "max",
1430                .cmp  = max_cmp,
1431        };
1432        static struct sort_dimension pid_sort_dimension = {
1433                .name = "pid",
1434                .cmp  = pid_cmp,
1435        };
1436        static struct sort_dimension runtime_sort_dimension = {
1437                .name = "runtime",
1438                .cmp  = runtime_cmp,
1439        };
1440        static struct sort_dimension switch_sort_dimension = {
1441                .name = "switch",
1442                .cmp  = switch_cmp,
1443        };
1444        struct sort_dimension *available_sorts[] = {
1445                &pid_sort_dimension,
1446                &avg_sort_dimension,
1447                &max_sort_dimension,
1448                &switch_sort_dimension,
1449                &runtime_sort_dimension,
1450        };
1451
1452        for (i = 0; i < ARRAY_SIZE(available_sorts); i++) {
1453                if (!strcmp(available_sorts[i]->name, tok)) {
1454                        list_add_tail(&available_sorts[i]->list, list);
1455
1456                        return 0;
1457                }
1458        }
1459
1460        return -1;
1461}
1462
1463static void perf_sched__sort_lat(struct perf_sched *sched)
1464{
1465        struct rb_node *node;
1466        struct rb_root_cached *root = &sched->atom_root;
1467again:
1468        for (;;) {
1469                struct work_atoms *data;
1470                node = rb_first_cached(root);
1471                if (!node)
1472                        break;
1473
1474                rb_erase_cached(node, root);
1475                data = rb_entry(node, struct work_atoms, node);
1476                __thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list);
1477        }
1478        if (root == &sched->atom_root) {
1479                root = &sched->merged_atom_root;
1480                goto again;
1481        }
1482}
1483
1484static int process_sched_wakeup_event(struct perf_tool *tool,
1485                                      struct evsel *evsel,
1486                                      struct perf_sample *sample,
1487                                      struct machine *machine)
1488{
1489        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1490
1491        if (sched->tp_handler->wakeup_event)
1492                return sched->tp_handler->wakeup_event(sched, evsel, sample, machine);
1493
1494        return 0;
1495}
1496
1497union map_priv {
1498        void    *ptr;
1499        bool     color;
1500};
1501
1502static bool thread__has_color(struct thread *thread)
1503{
1504        union map_priv priv = {
1505                .ptr = thread__priv(thread),
1506        };
1507
1508        return priv.color;
1509}
1510
1511static struct thread*
1512map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid)
1513{
1514        struct thread *thread = machine__findnew_thread(machine, pid, tid);
1515        union map_priv priv = {
1516                .color = false,
1517        };
1518
1519        if (!sched->map.color_pids || !thread || thread__priv(thread))
1520                return thread;
1521
1522        if (thread_map__has(sched->map.color_pids, tid))
1523                priv.color = true;
1524
1525        thread__set_priv(thread, priv.ptr);
1526        return thread;
1527}
1528
1529static int map_switch_event(struct perf_sched *sched, struct evsel *evsel,
1530                            struct perf_sample *sample, struct machine *machine)
1531{
1532        const u32 next_pid = evsel__intval(evsel, sample, "next_pid");
1533        struct thread *sched_in;
1534        struct thread_runtime *tr;
1535        int new_shortname;
1536        u64 timestamp0, timestamp = sample->time;
1537        s64 delta;
1538        int i, this_cpu = sample->cpu;
1539        int cpus_nr;
1540        bool new_cpu = false;
1541        const char *color = PERF_COLOR_NORMAL;
1542        char stimestamp[32];
1543
1544        BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
1545
1546        if (this_cpu > sched->max_cpu)
1547                sched->max_cpu = this_cpu;
1548
1549        if (sched->map.comp) {
1550                cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS);
1551                if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) {
1552                        sched->map.comp_cpus[cpus_nr++] = this_cpu;
1553                        new_cpu = true;
1554                }
1555        } else
1556                cpus_nr = sched->max_cpu;
1557
1558        timestamp0 = sched->cpu_last_switched[this_cpu];
1559        sched->cpu_last_switched[this_cpu] = timestamp;
1560        if (timestamp0)
1561                delta = timestamp - timestamp0;
1562        else
1563                delta = 0;
1564
1565        if (delta < 0) {
1566                pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1567                return -1;
1568        }
1569
1570        sched_in = map__findnew_thread(sched, machine, -1, next_pid);
1571        if (sched_in == NULL)
1572                return -1;
1573
1574        tr = thread__get_runtime(sched_in);
1575        if (tr == NULL) {
1576                thread__put(sched_in);
1577                return -1;
1578        }
1579
1580        sched->curr_thread[this_cpu] = thread__get(sched_in);
1581
1582        printf("  ");
1583
1584        new_shortname = 0;
1585        if (!tr->shortname[0]) {
1586                if (!strcmp(thread__comm_str(sched_in), "swapper")) {
1587                        /*
1588                         * Don't allocate a letter-number for swapper:0
1589                         * as a shortname. Instead, we use '.' for it.
1590                         */
1591                        tr->shortname[0] = '.';
1592                        tr->shortname[1] = ' ';
1593                } else {
1594                        tr->shortname[0] = sched->next_shortname1;
1595                        tr->shortname[1] = sched->next_shortname2;
1596
1597                        if (sched->next_shortname1 < 'Z') {
1598                                sched->next_shortname1++;
1599                        } else {
1600                                sched->next_shortname1 = 'A';
1601                                if (sched->next_shortname2 < '9')
1602                                        sched->next_shortname2++;
1603                                else
1604                                        sched->next_shortname2 = '0';
1605                        }
1606                }
1607                new_shortname = 1;
1608        }
1609
1610        for (i = 0; i < cpus_nr; i++) {
1611                int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i;
1612                struct thread *curr_thread = sched->curr_thread[cpu];
1613                struct thread_runtime *curr_tr;
1614                const char *pid_color = color;
1615                const char *cpu_color = color;
1616
1617                if (curr_thread && thread__has_color(curr_thread))
1618                        pid_color = COLOR_PIDS;
1619
1620                if (sched->map.cpus && !cpu_map__has(sched->map.cpus, cpu))
1621                        continue;
1622
1623                if (sched->map.color_cpus && cpu_map__has(sched->map.color_cpus, cpu))
1624                        cpu_color = COLOR_CPUS;
1625
1626                if (cpu != this_cpu)
1627                        color_fprintf(stdout, color, " ");
1628                else
1629                        color_fprintf(stdout, cpu_color, "*");
1630
1631                if (sched->curr_thread[cpu]) {
1632                        curr_tr = thread__get_runtime(sched->curr_thread[cpu]);
1633                        if (curr_tr == NULL) {
1634                                thread__put(sched_in);
1635                                return -1;
1636                        }
1637                        color_fprintf(stdout, pid_color, "%2s ", curr_tr->shortname);
1638                } else
1639                        color_fprintf(stdout, color, "   ");
1640        }
1641
1642        if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu))
1643                goto out;
1644
1645        timestamp__scnprintf_usec(timestamp, stimestamp, sizeof(stimestamp));
1646        color_fprintf(stdout, color, "  %12s secs ", stimestamp);
1647        if (new_shortname || tr->comm_changed || (verbose > 0 && sched_in->tid)) {
1648                const char *pid_color = color;
1649
1650                if (thread__has_color(sched_in))
1651                        pid_color = COLOR_PIDS;
1652
1653                color_fprintf(stdout, pid_color, "%s => %s:%d",
1654                       tr->shortname, thread__comm_str(sched_in), sched_in->tid);
1655                tr->comm_changed = false;
1656        }
1657
1658        if (sched->map.comp && new_cpu)
1659                color_fprintf(stdout, color, " (CPU %d)", this_cpu);
1660
1661out:
1662        color_fprintf(stdout, color, "\n");
1663
1664        thread__put(sched_in);
1665
1666        return 0;
1667}
1668
1669static int process_sched_switch_event(struct perf_tool *tool,
1670                                      struct evsel *evsel,
1671                                      struct perf_sample *sample,
1672                                      struct machine *machine)
1673{
1674        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1675        int this_cpu = sample->cpu, err = 0;
1676        u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"),
1677            next_pid = evsel__intval(evsel, sample, "next_pid");
1678
1679        if (sched->curr_pid[this_cpu] != (u32)-1) {
1680                /*
1681                 * Are we trying to switch away a PID that is
1682                 * not current?
1683                 */
1684                if (sched->curr_pid[this_cpu] != prev_pid)
1685                        sched->nr_context_switch_bugs++;
1686        }
1687
1688        if (sched->tp_handler->switch_event)
1689                err = sched->tp_handler->switch_event(sched, evsel, sample, machine);
1690
1691        sched->curr_pid[this_cpu] = next_pid;
1692        return err;
1693}
1694
1695static int process_sched_runtime_event(struct perf_tool *tool,
1696                                       struct evsel *evsel,
1697                                       struct perf_sample *sample,
1698                                       struct machine *machine)
1699{
1700        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1701
1702        if (sched->tp_handler->runtime_event)
1703                return sched->tp_handler->runtime_event(sched, evsel, sample, machine);
1704
1705        return 0;
1706}
1707
1708static int perf_sched__process_fork_event(struct perf_tool *tool,
1709                                          union perf_event *event,
1710                                          struct perf_sample *sample,
1711                                          struct machine *machine)
1712{
1713        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1714
1715        /* run the fork event through the perf machinery */
1716        perf_event__process_fork(tool, event, sample, machine);
1717
1718        /* and then run additional processing needed for this command */
1719        if (sched->tp_handler->fork_event)
1720                return sched->tp_handler->fork_event(sched, event, machine);
1721
1722        return 0;
1723}
1724
1725static int process_sched_migrate_task_event(struct perf_tool *tool,
1726                                            struct evsel *evsel,
1727                                            struct perf_sample *sample,
1728                                            struct machine *machine)
1729{
1730        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1731
1732        if (sched->tp_handler->migrate_task_event)
1733                return sched->tp_handler->migrate_task_event(sched, evsel, sample, machine);
1734
1735        return 0;
1736}
1737
1738typedef int (*tracepoint_handler)(struct perf_tool *tool,
1739                                  struct evsel *evsel,
1740                                  struct perf_sample *sample,
1741                                  struct machine *machine);
1742
1743static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused,
1744                                                 union perf_event *event __maybe_unused,
1745                                                 struct perf_sample *sample,
1746                                                 struct evsel *evsel,
1747                                                 struct machine *machine)
1748{
1749        int err = 0;
1750
1751        if (evsel->handler != NULL) {
1752                tracepoint_handler f = evsel->handler;
1753                err = f(tool, evsel, sample, machine);
1754        }
1755
1756        return err;
1757}
1758
1759static int perf_sched__process_comm(struct perf_tool *tool __maybe_unused,
1760                                    union perf_event *event,
1761                                    struct perf_sample *sample,
1762                                    struct machine *machine)
1763{
1764        struct thread *thread;
1765        struct thread_runtime *tr;
1766        int err;
1767
1768        err = perf_event__process_comm(tool, event, sample, machine);
1769        if (err)
1770                return err;
1771
1772        thread = machine__find_thread(machine, sample->pid, sample->tid);
1773        if (!thread) {
1774                pr_err("Internal error: can't find thread\n");
1775                return -1;
1776        }
1777
1778        tr = thread__get_runtime(thread);
1779        if (tr == NULL) {
1780                thread__put(thread);
1781                return -1;
1782        }
1783
1784        tr->comm_changed = true;
1785        thread__put(thread);
1786
1787        return 0;
1788}
1789
1790static int perf_sched__read_events(struct perf_sched *sched)
1791{
1792        const struct evsel_str_handler handlers[] = {
1793                { "sched:sched_switch",       process_sched_switch_event, },
1794                { "sched:sched_stat_runtime", process_sched_runtime_event, },
1795                { "sched:sched_wakeup",       process_sched_wakeup_event, },
1796                { "sched:sched_wakeup_new",   process_sched_wakeup_event, },
1797                { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1798        };
1799        struct perf_session *session;
1800        struct perf_data data = {
1801                .path  = input_name,
1802                .mode  = PERF_DATA_MODE_READ,
1803                .force = sched->force,
1804        };
1805        int rc = -1;
1806
1807        session = perf_session__new(&data, false, &sched->tool);
1808        if (IS_ERR(session)) {
1809                pr_debug("Error creating perf session");
1810                return PTR_ERR(session);
1811        }
1812
1813        symbol__init(&session->header.env);
1814
1815        if (perf_session__set_tracepoints_handlers(session, handlers))
1816                goto out_delete;
1817
1818        if (perf_session__has_traces(session, "record -R")) {
1819                int err = perf_session__process_events(session);
1820                if (err) {
1821                        pr_err("Failed to process events, error %d", err);
1822                        goto out_delete;
1823                }
1824
1825                sched->nr_events      = session->evlist->stats.nr_events[0];
1826                sched->nr_lost_events = session->evlist->stats.total_lost;
1827                sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST];
1828        }
1829
1830        rc = 0;
1831out_delete:
1832        perf_session__delete(session);
1833        return rc;
1834}
1835
1836/*
1837 * scheduling times are printed as msec.usec
1838 */
1839static inline void print_sched_time(unsigned long long nsecs, int width)
1840{
1841        unsigned long msecs;
1842        unsigned long usecs;
1843
1844        msecs  = nsecs / NSEC_PER_MSEC;
1845        nsecs -= msecs * NSEC_PER_MSEC;
1846        usecs  = nsecs / NSEC_PER_USEC;
1847        printf("%*lu.%03lu ", width, msecs, usecs);
1848}
1849
1850/*
1851 * returns runtime data for event, allocating memory for it the
1852 * first time it is used.
1853 */
1854static struct evsel_runtime *evsel__get_runtime(struct evsel *evsel)
1855{
1856        struct evsel_runtime *r = evsel->priv;
1857
1858        if (r == NULL) {
1859                r = zalloc(sizeof(struct evsel_runtime));
1860                evsel->priv = r;
1861        }
1862
1863        return r;
1864}
1865
1866/*
1867 * save last time event was seen per cpu
1868 */
1869static void evsel__save_time(struct evsel *evsel, u64 timestamp, u32 cpu)
1870{
1871        struct evsel_runtime *r = evsel__get_runtime(evsel);
1872
1873        if (r == NULL)
1874                return;
1875
1876        if ((cpu >= r->ncpu) || (r->last_time == NULL)) {
1877                int i, n = __roundup_pow_of_two(cpu+1);
1878                void *p = r->last_time;
1879
1880                p = realloc(r->last_time, n * sizeof(u64));
1881                if (!p)
1882                        return;
1883
1884                r->last_time = p;
1885                for (i = r->ncpu; i < n; ++i)
1886                        r->last_time[i] = (u64) 0;
1887
1888                r->ncpu = n;
1889        }
1890
1891        r->last_time[cpu] = timestamp;
1892}
1893
1894/* returns last time this event was seen on the given cpu */
1895static u64 evsel__get_time(struct evsel *evsel, u32 cpu)
1896{
1897        struct evsel_runtime *r = evsel__get_runtime(evsel);
1898
1899        if ((r == NULL) || (r->last_time == NULL) || (cpu >= r->ncpu))
1900                return 0;
1901
1902        return r->last_time[cpu];
1903}
1904
1905static int comm_width = 30;
1906
1907static char *timehist_get_commstr(struct thread *thread)
1908{
1909        static char str[32];
1910        const char *comm = thread__comm_str(thread);
1911        pid_t tid = thread->tid;
1912        pid_t pid = thread->pid_;
1913        int n;
1914
1915        if (pid == 0)
1916                n = scnprintf(str, sizeof(str), "%s", comm);
1917
1918        else if (tid != pid)
1919                n = scnprintf(str, sizeof(str), "%s[%d/%d]", comm, tid, pid);
1920
1921        else
1922                n = scnprintf(str, sizeof(str), "%s[%d]", comm, tid);
1923
1924        if (n > comm_width)
1925                comm_width = n;
1926
1927        return str;
1928}
1929
1930static void timehist_header(struct perf_sched *sched)
1931{
1932        u32 ncpus = sched->max_cpu + 1;
1933        u32 i, j;
1934
1935        printf("%15s %6s ", "time", "cpu");
1936
1937        if (sched->show_cpu_visual) {
1938                printf(" ");
1939                for (i = 0, j = 0; i < ncpus; ++i) {
1940                        printf("%x", j++);
1941                        if (j > 15)
1942                                j = 0;
1943                }
1944                printf(" ");
1945        }
1946
1947        printf(" %-*s  %9s  %9s  %9s", comm_width,
1948                "task name", "wait time", "sch delay", "run time");
1949
1950        if (sched->show_state)
1951                printf("  %s", "state");
1952
1953        printf("\n");
1954
1955        /*
1956         * units row
1957         */
1958        printf("%15s %-6s ", "", "");
1959
1960        if (sched->show_cpu_visual)
1961                printf(" %*s ", ncpus, "");
1962
1963        printf(" %-*s  %9s  %9s  %9s", comm_width,
1964               "[tid/pid]", "(msec)", "(msec)", "(msec)");
1965
1966        if (sched->show_state)
1967                printf("  %5s", "");
1968
1969        printf("\n");
1970
1971        /*
1972         * separator
1973         */
1974        printf("%.15s %.6s ", graph_dotted_line, graph_dotted_line);
1975
1976        if (sched->show_cpu_visual)
1977                printf(" %.*s ", ncpus, graph_dotted_line);
1978
1979        printf(" %.*s  %.9s  %.9s  %.9s", comm_width,
1980                graph_dotted_line, graph_dotted_line, graph_dotted_line,
1981                graph_dotted_line);
1982
1983        if (sched->show_state)
1984                printf("  %.5s", graph_dotted_line);
1985
1986        printf("\n");
1987}
1988
1989static char task_state_char(struct thread *thread, int state)
1990{
1991        static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
1992        unsigned bit = state ? ffs(state) : 0;
1993
1994        /* 'I' for idle */
1995        if (thread->tid == 0)
1996                return 'I';
1997
1998        return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
1999}
2000
2001static void timehist_print_sample(struct perf_sched *sched,
2002                                  struct evsel *evsel,
2003                                  struct perf_sample *sample,
2004                                  struct addr_location *al,
2005                                  struct thread *thread,
2006                                  u64 t, int state)
2007{
2008        struct thread_runtime *tr = thread__priv(thread);
2009        const char *next_comm = evsel__strval(evsel, sample, "next_comm");
2010        const u32 next_pid = evsel__intval(evsel, sample, "next_pid");
2011        u32 max_cpus = sched->max_cpu + 1;
2012        char tstr[64];
2013        char nstr[30];
2014        u64 wait_time;
2015
2016        if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
2017                return;
2018
2019        timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
2020        printf("%15s [%04d] ", tstr, sample->cpu);
2021
2022        if (sched->show_cpu_visual) {
2023                u32 i;
2024                char c;
2025
2026                printf(" ");
2027                for (i = 0; i < max_cpus; ++i) {
2028                        /* flag idle times with 'i'; others are sched events */
2029                        if (i == sample->cpu)
2030                                c = (thread->tid == 0) ? 'i' : 's';
2031                        else
2032                                c = ' ';
2033                        printf("%c", c);
2034                }
2035                printf(" ");
2036        }
2037
2038        printf(" %-*s ", comm_width, timehist_get_commstr(thread));
2039
2040        wait_time = tr->dt_sleep + tr->dt_iowait + tr->dt_preempt;
2041        print_sched_time(wait_time, 6);
2042
2043        print_sched_time(tr->dt_delay, 6);
2044        print_sched_time(tr->dt_run, 6);
2045
2046        if (sched->show_state)
2047                printf(" %5c ", task_state_char(thread, state));
2048
2049        if (sched->show_next) {
2050                snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid);
2051                printf(" %-*s", comm_width, nstr);
2052        }
2053
2054        if (sched->show_wakeups && !sched->show_next)
2055                printf("  %-*s", comm_width, "");
2056
2057        if (thread->tid == 0)
2058                goto out;
2059
2060        if (sched->show_callchain)
2061                printf("  ");
2062
2063        sample__fprintf_sym(sample, al, 0,
2064                            EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
2065                            EVSEL__PRINT_CALLCHAIN_ARROW |
2066                            EVSEL__PRINT_SKIP_IGNORED,
2067                            &callchain_cursor, symbol_conf.bt_stop_list,  stdout);
2068
2069out:
2070        printf("\n");
2071}
2072
2073/*
2074 * Explanation of delta-time stats:
2075 *
2076 *            t = time of current schedule out event
2077 *        tprev = time of previous sched out event
2078 *                also time of schedule-in event for current task
2079 *    last_time = time of last sched change event for current task
2080 *                (i.e, time process was last scheduled out)
2081 * ready_to_run = time of wakeup for current task
2082 *
2083 * -----|------------|------------|------------|------
2084 *    last         ready        tprev          t
2085 *    time         to run
2086 *
2087 *      |-------- dt_wait --------|
2088 *                   |- dt_delay -|-- dt_run --|
2089 *
2090 *   dt_run = run time of current task
2091 *  dt_wait = time between last schedule out event for task and tprev
2092 *            represents time spent off the cpu
2093 * dt_delay = time between wakeup and schedule-in of task
2094 */
2095
2096static void timehist_update_runtime_stats(struct thread_runtime *r,
2097                                         u64 t, u64 tprev)
2098{
2099        r->dt_delay   = 0;
2100        r->dt_sleep   = 0;
2101        r->dt_iowait  = 0;
2102        r->dt_preempt = 0;
2103        r->dt_run     = 0;
2104
2105        if (tprev) {
2106                r->dt_run = t - tprev;
2107                if (r->ready_to_run) {
2108                        if (r->ready_to_run > tprev)
2109                                pr_debug("time travel: wakeup time for task > previous sched_switch event\n");
2110                        else
2111                                r->dt_delay = tprev - r->ready_to_run;
2112                }
2113
2114                if (r->last_time > tprev)
2115                        pr_debug("time travel: last sched out time for task > previous sched_switch event\n");
2116                else if (r->last_time) {
2117                        u64 dt_wait = tprev - r->last_time;
2118
2119                        if (r->last_state == TASK_RUNNING)
2120                                r->dt_preempt = dt_wait;
2121                        else if (r->last_state == TASK_UNINTERRUPTIBLE)
2122                                r->dt_iowait = dt_wait;
2123                        else
2124                                r->dt_sleep = dt_wait;
2125                }
2126        }
2127
2128        update_stats(&r->run_stats, r->dt_run);
2129
2130        r->total_run_time     += r->dt_run;
2131        r->total_delay_time   += r->dt_delay;
2132        r->total_sleep_time   += r->dt_sleep;
2133        r->total_iowait_time  += r->dt_iowait;
2134        r->total_preempt_time += r->dt_preempt;
2135}
2136
2137static bool is_idle_sample(struct perf_sample *sample,
2138                           struct evsel *evsel)
2139{
2140        /* pid 0 == swapper == idle task */
2141        if (strcmp(evsel__name(evsel), "sched:sched_switch") == 0)
2142                return evsel__intval(evsel, sample, "prev_pid") == 0;
2143
2144        return sample->pid == 0;
2145}
2146
2147static void save_task_callchain(struct perf_sched *sched,
2148                                struct perf_sample *sample,
2149                                struct evsel *evsel,
2150                                struct machine *machine)
2151{
2152        struct callchain_cursor *cursor = &callchain_cursor;
2153        struct thread *thread;
2154
2155        /* want main thread for process - has maps */
2156        thread = machine__findnew_thread(machine, sample->pid, sample->pid);
2157        if (thread == NULL) {
2158                pr_debug("Failed to get thread for pid %d.\n", sample->pid);
2159                return;
2160        }
2161
2162        if (!sched->show_callchain || sample->callchain == NULL)
2163                return;
2164
2165        if (thread__resolve_callchain(thread, cursor, evsel, sample,
2166                                      NULL, NULL, sched->max_stack + 2) != 0) {
2167                if (verbose > 0)
2168                        pr_err("Failed to resolve callchain. Skipping\n");
2169
2170                return;
2171        }
2172
2173        callchain_cursor_commit(cursor);
2174
2175        while (true) {
2176                struct callchain_cursor_node *node;
2177                struct symbol *sym;
2178
2179                node = callchain_cursor_current(cursor);
2180                if (node == NULL)
2181                        break;
2182
2183                sym = node->ms.sym;
2184                if (sym) {
2185                        if (!strcmp(sym->name, "schedule") ||
2186                            !strcmp(sym->name, "__schedule") ||
2187                            !strcmp(sym->name, "preempt_schedule"))
2188                                sym->ignore = 1;
2189                }
2190
2191                callchain_cursor_advance(cursor);
2192        }
2193}
2194
2195static int init_idle_thread(struct thread *thread)
2196{
2197        struct idle_thread_runtime *itr;
2198
2199        thread__set_comm(thread, idle_comm, 0);
2200
2201        itr = zalloc(sizeof(*itr));
2202        if (itr == NULL)
2203                return -ENOMEM;
2204
2205        init_stats(&itr->tr.run_stats);
2206        callchain_init(&itr->callchain);
2207        callchain_cursor_reset(&itr->cursor);
2208        thread__set_priv(thread, itr);
2209
2210        return 0;
2211}
2212
2213/*
2214 * Track idle stats per cpu by maintaining a local thread
2215 * struct for the idle task on each cpu.
2216 */
2217static int init_idle_threads(int ncpu)
2218{
2219        int i, ret;
2220
2221        idle_threads = zalloc(ncpu * sizeof(struct thread *));
2222        if (!idle_threads)
2223                return -ENOMEM;
2224
2225        idle_max_cpu = ncpu;
2226
2227        /* allocate the actual thread struct if needed */
2228        for (i = 0; i < ncpu; ++i) {
2229                idle_threads[i] = thread__new(0, 0);
2230                if (idle_threads[i] == NULL)
2231                        return -ENOMEM;
2232
2233                ret = init_idle_thread(idle_threads[i]);
2234                if (ret < 0)
2235                        return ret;
2236        }
2237
2238        return 0;
2239}
2240
2241static void free_idle_threads(void)
2242{
2243        int i;
2244
2245        if (idle_threads == NULL)
2246                return;
2247
2248        for (i = 0; i < idle_max_cpu; ++i) {
2249                if ((idle_threads[i]))
2250                        thread__delete(idle_threads[i]);
2251        }
2252
2253        free(idle_threads);
2254}
2255
2256static struct thread *get_idle_thread(int cpu)
2257{
2258        /*
2259         * expand/allocate array of pointers to local thread
2260         * structs if needed
2261         */
2262        if ((cpu >= idle_max_cpu) || (idle_threads == NULL)) {
2263                int i, j = __roundup_pow_of_two(cpu+1);
2264                void *p;
2265
2266                p = realloc(idle_threads, j * sizeof(struct thread *));
2267                if (!p)
2268                        return NULL;
2269
2270                idle_threads = (struct thread **) p;
2271                for (i = idle_max_cpu; i < j; ++i)
2272                        idle_threads[i] = NULL;
2273
2274                idle_max_cpu = j;
2275        }
2276
2277        /* allocate a new thread struct if needed */
2278        if (idle_threads[cpu] == NULL) {
2279                idle_threads[cpu] = thread__new(0, 0);
2280
2281                if (idle_threads[cpu]) {
2282                        if (init_idle_thread(idle_threads[cpu]) < 0)
2283                                return NULL;
2284                }
2285        }
2286
2287        return idle_threads[cpu];
2288}
2289
2290static void save_idle_callchain(struct perf_sched *sched,
2291                                struct idle_thread_runtime *itr,
2292                                struct perf_sample *sample)
2293{
2294        if (!sched->show_callchain || sample->callchain == NULL)
2295                return;
2296
2297        callchain_cursor__copy(&itr->cursor, &callchain_cursor);
2298}
2299
2300static struct thread *timehist_get_thread(struct perf_sched *sched,
2301                                          struct perf_sample *sample,
2302                                          struct machine *machine,
2303                                          struct evsel *evsel)
2304{
2305        struct thread *thread;
2306
2307        if (is_idle_sample(sample, evsel)) {
2308                thread = get_idle_thread(sample->cpu);
2309                if (thread == NULL)
2310                        pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
2311
2312        } else {
2313                /* there were samples with tid 0 but non-zero pid */
2314                thread = machine__findnew_thread(machine, sample->pid,
2315                                                 sample->tid ?: sample->pid);
2316                if (thread == NULL) {
2317                        pr_debug("Failed to get thread for tid %d. skipping sample.\n",
2318                                 sample->tid);
2319                }
2320
2321                save_task_callchain(sched, sample, evsel, machine);
2322                if (sched->idle_hist) {
2323                        struct thread *idle;
2324                        struct idle_thread_runtime *itr;
2325
2326                        idle = get_idle_thread(sample->cpu);
2327                        if (idle == NULL) {
2328                                pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
2329                                return NULL;
2330                        }
2331
2332                        itr = thread__priv(idle);
2333                        if (itr == NULL)
2334                                return NULL;
2335
2336                        itr->last_thread = thread;
2337
2338                        /* copy task callchain when entering to idle */
2339                        if (evsel__intval(evsel, sample, "next_pid") == 0)
2340                                save_idle_callchain(sched, itr, sample);
2341                }
2342        }
2343
2344        return thread;
2345}
2346
2347static bool timehist_skip_sample(struct perf_sched *sched,
2348                                 struct thread *thread,
2349                                 struct evsel *evsel,
2350                                 struct perf_sample *sample)
2351{
2352        bool rc = false;
2353
2354        if (thread__is_filtered(thread)) {
2355                rc = true;
2356                sched->skipped_samples++;
2357        }
2358
2359        if (sched->idle_hist) {
2360                if (strcmp(evsel__name(evsel), "sched:sched_switch"))
2361                        rc = true;
2362                else if (evsel__intval(evsel, sample, "prev_pid") != 0 &&
2363                         evsel__intval(evsel, sample, "next_pid") != 0)
2364                        rc = true;
2365        }
2366
2367        return rc;
2368}
2369
2370static void timehist_print_wakeup_event(struct perf_sched *sched,
2371                                        struct evsel *evsel,
2372                                        struct perf_sample *sample,
2373                                        struct machine *machine,
2374                                        struct thread *awakened)
2375{
2376        struct thread *thread;
2377        char tstr[64];
2378
2379        thread = machine__findnew_thread(machine, sample->pid, sample->tid);
2380        if (thread == NULL)
2381                return;
2382
2383        /* show wakeup unless both awakee and awaker are filtered */
2384        if (timehist_skip_sample(sched, thread, evsel, sample) &&
2385            timehist_skip_sample(sched, awakened, evsel, sample)) {
2386                return;
2387        }
2388
2389        timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
2390        printf("%15s [%04d] ", tstr, sample->cpu);
2391        if (sched->show_cpu_visual)
2392                printf(" %*s ", sched->max_cpu + 1, "");
2393
2394        printf(" %-*s ", comm_width, timehist_get_commstr(thread));
2395
2396        /* dt spacer */
2397        printf("  %9s  %9s  %9s ", "", "", "");
2398
2399        printf("awakened: %s", timehist_get_commstr(awakened));
2400
2401        printf("\n");
2402}
2403
2404static int timehist_sched_wakeup_ignore(struct perf_tool *tool __maybe_unused,
2405                                        union perf_event *event __maybe_unused,
2406                                        struct evsel *evsel __maybe_unused,
2407                                        struct perf_sample *sample __maybe_unused,
2408                                        struct machine *machine __maybe_unused)
2409{
2410        return 0;
2411}
2412
2413static int timehist_sched_wakeup_event(struct perf_tool *tool,
2414                                       union perf_event *event __maybe_unused,
2415                                       struct evsel *evsel,
2416                                       struct perf_sample *sample,
2417                                       struct machine *machine)
2418{
2419        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
2420        struct thread *thread;
2421        struct thread_runtime *tr = NULL;
2422        /* want pid of awakened task not pid in sample */
2423        const u32 pid = evsel__intval(evsel, sample, "pid");
2424
2425        thread = machine__findnew_thread(machine, 0, pid);
2426        if (thread == NULL)
2427                return -1;
2428
2429        tr = thread__get_runtime(thread);
2430        if (tr == NULL)
2431                return -1;
2432
2433        if (tr->ready_to_run == 0)
2434                tr->ready_to_run = sample->time;
2435
2436        /* show wakeups if requested */
2437        if (sched->show_wakeups &&
2438            !perf_time__skip_sample(&sched->ptime, sample->time))
2439                timehist_print_wakeup_event(sched, evsel, sample, machine, thread);
2440
2441        return 0;
2442}
2443
2444static void timehist_print_migration_event(struct perf_sched *sched,
2445                                        struct evsel *evsel,
2446                                        struct perf_sample *sample,
2447                                        struct machine *machine,
2448                                        struct thread *migrated)
2449{
2450        struct thread *thread;
2451        char tstr[64];
2452        u32 max_cpus = sched->max_cpu + 1;
2453        u32 ocpu, dcpu;
2454
2455        if (sched->summary_only)
2456                return;
2457
2458        max_cpus = sched->max_cpu + 1;
2459        ocpu = evsel__intval(evsel, sample, "orig_cpu");
2460        dcpu = evsel__intval(evsel, sample, "dest_cpu");
2461
2462        thread = machine__findnew_thread(machine, sample->pid, sample->tid);
2463        if (thread == NULL)
2464                return;
2465
2466        if (timehist_skip_sample(sched, thread, evsel, sample) &&
2467            timehist_skip_sample(sched, migrated, evsel, sample)) {
2468                return;
2469        }
2470
2471        timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
2472        printf("%15s [%04d] ", tstr, sample->cpu);
2473
2474        if (sched->show_cpu_visual) {
2475                u32 i;
2476                char c;
2477
2478                printf("  ");
2479                for (i = 0; i < max_cpus; ++i) {
2480                        c = (i == sample->cpu) ? 'm' : ' ';
2481                        printf("%c", c);
2482                }
2483                printf("  ");
2484        }
2485
2486        printf(" %-*s ", comm_width, timehist_get_commstr(thread));
2487
2488        /* dt spacer */
2489        printf("  %9s  %9s  %9s ", "", "", "");
2490
2491        printf("migrated: %s", timehist_get_commstr(migrated));
2492        printf(" cpu %d => %d", ocpu, dcpu);
2493
2494        printf("\n");
2495}
2496
2497static int timehist_migrate_task_event(struct perf_tool *tool,
2498                                       union perf_event *event __maybe_unused,
2499                                       struct evsel *evsel,
2500                                       struct perf_sample *sample,
2501                                       struct machine *machine)
2502{
2503        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
2504        struct thread *thread;
2505        struct thread_runtime *tr = NULL;
2506        /* want pid of migrated task not pid in sample */
2507        const u32 pid = evsel__intval(evsel, sample, "pid");
2508
2509        thread = machine__findnew_thread(machine, 0, pid);
2510        if (thread == NULL)
2511                return -1;
2512
2513        tr = thread__get_runtime(thread);
2514        if (tr == NULL)
2515                return -1;
2516
2517        tr->migrations++;
2518
2519        /* show migrations if requested */
2520        timehist_print_migration_event(sched, evsel, sample, machine, thread);
2521
2522        return 0;
2523}
2524
2525static int timehist_sched_change_event(struct perf_tool *tool,
2526                                       union perf_event *event,
2527                                       struct evsel *evsel,
2528                                       struct perf_sample *sample,
2529                                       struct machine *machine)
2530{
2531        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
2532        struct perf_time_interval *ptime = &sched->ptime;
2533        struct addr_location al;
2534        struct thread *thread;
2535        struct thread_runtime *tr = NULL;
2536        u64 tprev, t = sample->time;
2537        int rc = 0;
2538        int state = evsel__intval(evsel, sample, "prev_state");
2539
2540        if (machine__resolve(machine, &al, sample) < 0) {
2541                pr_err("problem processing %d event. skipping it\n",
2542                       event->header.type);
2543                rc = -1;
2544                goto out;
2545        }
2546
2547        thread = timehist_get_thread(sched, sample, machine, evsel);
2548        if (thread == NULL) {
2549                rc = -1;
2550                goto out;
2551        }
2552
2553        if (timehist_skip_sample(sched, thread, evsel, sample))
2554                goto out;
2555
2556        tr = thread__get_runtime(thread);
2557        if (tr == NULL) {
2558                rc = -1;
2559                goto out;
2560        }
2561
2562        tprev = evsel__get_time(evsel, sample->cpu);
2563
2564        /*
2565         * If start time given:
2566         * - sample time is under window user cares about - skip sample
2567         * - tprev is under window user cares about  - reset to start of window
2568         */
2569        if (ptime->start && ptime->start > t)
2570                goto out;
2571
2572        if (tprev && ptime->start > tprev)
2573                tprev = ptime->start;
2574
2575        /*
2576         * If end time given:
2577         * - previous sched event is out of window - we are done
2578         * - sample time is beyond window user cares about - reset it
2579         *   to close out stats for time window interest
2580         */
2581        if (ptime->end) {
2582                if (tprev > ptime->end)
2583                        goto out;
2584
2585                if (t > ptime->end)
2586                        t = ptime->end;
2587        }
2588
2589        if (!sched->idle_hist || thread->tid == 0) {
2590                if (!cpu_list || test_bit(sample->cpu, cpu_bitmap))
2591                        timehist_update_runtime_stats(tr, t, tprev);
2592
2593                if (sched->idle_hist) {
2594                        struct idle_thread_runtime *itr = (void *)tr;
2595                        struct thread_runtime *last_tr;
2596
2597                        BUG_ON(thread->tid != 0);
2598
2599                        if (itr->last_thread == NULL)
2600                                goto out;
2601
2602                        /* add current idle time as last thread's runtime */
2603                        last_tr = thread__get_runtime(itr->last_thread);
2604                        if (last_tr == NULL)
2605                                goto out;
2606
2607                        timehist_update_runtime_stats(last_tr, t, tprev);
2608                        /*
2609                         * remove delta time of last thread as it's not updated
2610                         * and otherwise it will show an invalid value next
2611                         * time.  we only care total run time and run stat.
2612                         */
2613                        last_tr->dt_run = 0;
2614                        last_tr->dt_delay = 0;
2615                        last_tr->dt_sleep = 0;
2616                        last_tr->dt_iowait = 0;
2617                        last_tr->dt_preempt = 0;
2618
2619                        if (itr->cursor.nr)
2620                                callchain_append(&itr->callchain, &itr->cursor, t - tprev);
2621
2622                        itr->last_thread = NULL;
2623                }
2624        }
2625
2626        if (!sched->summary_only)
2627                timehist_print_sample(sched, evsel, sample, &al, thread, t, state);
2628
2629out:
2630        if (sched->hist_time.start == 0 && t >= ptime->start)
2631                sched->hist_time.start = t;
2632        if (ptime->end == 0 || t <= ptime->end)
2633                sched->hist_time.end = t;
2634
2635        if (tr) {
2636                /* time of this sched_switch event becomes last time task seen */
2637                tr->last_time = sample->time;
2638
2639                /* last state is used to determine where to account wait time */
2640                tr->last_state = state;
2641
2642                /* sched out event for task so reset ready to run time */
2643                tr->ready_to_run = 0;
2644        }
2645
2646        evsel__save_time(evsel, sample->time, sample->cpu);
2647
2648        return rc;
2649}
2650
2651static int timehist_sched_switch_event(struct perf_tool *tool,
2652                             union perf_event *event,
2653                             struct evsel *evsel,
2654                             struct perf_sample *sample,
2655                             struct machine *machine __maybe_unused)
2656{
2657        return timehist_sched_change_event(tool, event, evsel, sample, machine);
2658}
2659
2660static int process_lost(struct perf_tool *tool __maybe_unused,
2661                        union perf_event *event,
2662                        struct perf_sample *sample,
2663                        struct machine *machine __maybe_unused)
2664{
2665        char tstr[64];
2666
2667        timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr));
2668        printf("%15s ", tstr);
2669        printf("lost %" PRI_lu64 " events on cpu %d\n", event->lost.lost, sample->cpu);
2670
2671        return 0;
2672}
2673
2674
2675static void print_thread_runtime(struct thread *t,
2676                                 struct thread_runtime *r)
2677{
2678        double mean = avg_stats(&r->run_stats);
2679        float stddev;
2680
2681        printf("%*s   %5d  %9" PRIu64 " ",
2682               comm_width, timehist_get_commstr(t), t->ppid,
2683               (u64) r->run_stats.n);
2684
2685        print_sched_time(r->total_run_time, 8);
2686        stddev = rel_stddev_stats(stddev_stats(&r->run_stats), mean);
2687        print_sched_time(r->run_stats.min, 6);
2688        printf(" ");
2689        print_sched_time((u64) mean, 6);
2690        printf(" ");
2691        print_sched_time(r->run_stats.max, 6);
2692        printf("  ");
2693        printf("%5.2f", stddev);
2694        printf("   %5" PRIu64, r->migrations);
2695        printf("\n");
2696}
2697
2698static void print_thread_waittime(struct thread *t,
2699                                  struct thread_runtime *r)
2700{
2701        printf("%*s   %5d  %9" PRIu64 " ",
2702               comm_width, timehist_get_commstr(t), t->ppid,
2703               (u64) r->run_stats.n);
2704
2705        print_sched_time(r->total_run_time, 8);
2706        print_sched_time(r->total_sleep_time, 6);
2707        printf(" ");
2708        print_sched_time(r->total_iowait_time, 6);
2709        printf(" ");
2710        print_sched_time(r->total_preempt_time, 6);
2711        printf(" ");
2712        print_sched_time(r->total_delay_time, 6);
2713        printf("\n");
2714}
2715
2716struct total_run_stats {
2717        struct perf_sched *sched;
2718        u64  sched_count;
2719        u64  task_count;
2720        u64  total_run_time;
2721};
2722
2723static int __show_thread_runtime(struct thread *t, void *priv)
2724{
2725        struct total_run_stats *stats = priv;
2726        struct thread_runtime *r;
2727
2728        if (thread__is_filtered(t))
2729                return 0;
2730
2731        r = thread__priv(t);
2732        if (r && r->run_stats.n) {
2733                stats->task_count++;
2734                stats->sched_count += r->run_stats.n;
2735                stats->total_run_time += r->total_run_time;
2736
2737                if (stats->sched->show_state)
2738                        print_thread_waittime(t, r);
2739                else
2740                        print_thread_runtime(t, r);
2741        }
2742
2743        return 0;
2744}
2745
2746static int show_thread_runtime(struct thread *t, void *priv)
2747{
2748        if (t->dead)
2749                return 0;
2750
2751        return __show_thread_runtime(t, priv);
2752}
2753
2754static int show_deadthread_runtime(struct thread *t, void *priv)
2755{
2756        if (!t->dead)
2757                return 0;
2758
2759        return __show_thread_runtime(t, priv);
2760}
2761
2762static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
2763{
2764        const char *sep = " <- ";
2765        struct callchain_list *chain;
2766        size_t ret = 0;
2767        char bf[1024];
2768        bool first;
2769
2770        if (node == NULL)
2771                return 0;
2772
2773        ret = callchain__fprintf_folded(fp, node->parent);
2774        first = (ret == 0);
2775
2776        list_for_each_entry(chain, &node->val, list) {
2777                if (chain->ip >= PERF_CONTEXT_MAX)
2778                        continue;
2779                if (chain->ms.sym && chain->ms.sym->ignore)
2780                        continue;
2781                ret += fprintf(fp, "%s%s", first ? "" : sep,
2782                               callchain_list__sym_name(chain, bf, sizeof(bf),
2783                                                        false));
2784                first = false;
2785        }
2786
2787        return ret;
2788}
2789
2790static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root)
2791{
2792        size_t ret = 0;
2793        FILE *fp = stdout;
2794        struct callchain_node *chain;
2795        struct rb_node *rb_node = rb_first_cached(root);
2796
2797        printf("  %16s  %8s  %s\n", "Idle time (msec)", "Count", "Callchains");
2798        printf("  %.16s  %.8s  %.50s\n", graph_dotted_line, graph_dotted_line,
2799               graph_dotted_line);
2800
2801        while (rb_node) {
2802                chain = rb_entry(rb_node, struct callchain_node, rb_node);
2803                rb_node = rb_next(rb_node);
2804
2805                ret += fprintf(fp, "  ");
2806                print_sched_time(chain->hit, 12);
2807                ret += 16;  /* print_sched_time returns 2nd arg + 4 */
2808                ret += fprintf(fp, " %8d  ", chain->count);
2809                ret += callchain__fprintf_folded(fp, chain);
2810                ret += fprintf(fp, "\n");
2811        }
2812
2813        return ret;
2814}
2815
2816static void timehist_print_summary(struct perf_sched *sched,
2817                                   struct perf_session *session)
2818{
2819        struct machine *m = &session->machines.host;
2820        struct total_run_stats totals;
2821        u64 task_count;
2822        struct thread *t;
2823        struct thread_runtime *r;
2824        int i;
2825        u64 hist_time = sched->hist_time.end - sched->hist_time.start;
2826
2827        memset(&totals, 0, sizeof(totals));
2828        totals.sched = sched;
2829
2830        if (sched->idle_hist) {
2831                printf("\nIdle-time summary\n");
2832                printf("%*s  parent  sched-out  ", comm_width, "comm");
2833                printf("  idle-time   min-idle    avg-idle    max-idle  stddev  migrations\n");
2834        } else if (sched->show_state) {
2835                printf("\nWait-time summary\n");
2836                printf("%*s  parent   sched-in  ", comm_width, "comm");
2837                printf("   run-time      sleep      iowait     preempt       delay\n");
2838        } else {
2839                printf("\nRuntime summary\n");
2840                printf("%*s  parent   sched-in  ", comm_width, "comm");
2841                printf("   run-time    min-run     avg-run     max-run  stddev  migrations\n");
2842        }
2843        printf("%*s            (count)  ", comm_width, "");
2844        printf("     (msec)     (msec)      (msec)      (msec)       %s\n",
2845               sched->show_state ? "(msec)" : "%");
2846        printf("%.117s\n", graph_dotted_line);
2847
2848        machine__for_each_thread(m, show_thread_runtime, &totals);
2849        task_count = totals.task_count;
2850        if (!task_count)
2851                printf("<no still running tasks>\n");
2852
2853        printf("\nTerminated tasks:\n");
2854        machine__for_each_thread(m, show_deadthread_runtime, &totals);
2855        if (task_count == totals.task_count)
2856                printf("<no terminated tasks>\n");
2857
2858        /* CPU idle stats not tracked when samples were skipped */
2859        if (sched->skipped_samples && !sched->idle_hist)
2860                return;
2861
2862        printf("\nIdle stats:\n");
2863        for (i = 0; i < idle_max_cpu; ++i) {
2864                if (cpu_list && !test_bit(i, cpu_bitmap))
2865                        continue;
2866
2867                t = idle_threads[i];
2868                if (!t)
2869                        continue;
2870
2871                r = thread__priv(t);
2872                if (r && r->run_stats.n) {
2873                        totals.sched_count += r->run_stats.n;
2874                        printf("    CPU %2d idle for ", i);
2875                        print_sched_time(r->total_run_time, 6);
2876                        printf(" msec  (%6.2f%%)\n", 100.0 * r->total_run_time / hist_time);
2877                } else
2878                        printf("    CPU %2d idle entire time window\n", i);
2879        }
2880
2881        if (sched->idle_hist && sched->show_callchain) {
2882                callchain_param.mode  = CHAIN_FOLDED;
2883                callchain_param.value = CCVAL_PERIOD;
2884
2885                callchain_register_param(&callchain_param);
2886
2887                printf("\nIdle stats by callchain:\n");
2888                for (i = 0; i < idle_max_cpu; ++i) {
2889                        struct idle_thread_runtime *itr;
2890
2891                        t = idle_threads[i];
2892                        if (!t)
2893                                continue;
2894
2895                        itr = thread__priv(t);
2896                        if (itr == NULL)
2897                                continue;
2898
2899                        callchain_param.sort(&itr->sorted_root.rb_root, &itr->callchain,
2900                                             0, &callchain_param);
2901
2902                        printf("  CPU %2d:", i);
2903                        print_sched_time(itr->tr.total_run_time, 6);
2904                        printf(" msec\n");
2905                        timehist_print_idlehist_callchain(&itr->sorted_root);
2906                        printf("\n");
2907                }
2908        }
2909
2910        printf("\n"
2911               "    Total number of unique tasks: %" PRIu64 "\n"
2912               "Total number of context switches: %" PRIu64 "\n",
2913               totals.task_count, totals.sched_count);
2914
2915        printf("           Total run time (msec): ");
2916        print_sched_time(totals.total_run_time, 2);
2917        printf("\n");
2918
2919        printf("    Total scheduling time (msec): ");
2920        print_sched_time(hist_time, 2);
2921        printf(" (x %d)\n", sched->max_cpu);
2922}
2923
2924typedef int (*sched_handler)(struct perf_tool *tool,
2925                          union perf_event *event,
2926                          struct evsel *evsel,
2927                          struct perf_sample *sample,
2928                          struct machine *machine);
2929
2930static int perf_timehist__process_sample(struct perf_tool *tool,
2931                                         union perf_event *event,
2932                                         struct perf_sample *sample,
2933                                         struct evsel *evsel,
2934                                         struct machine *machine)
2935{
2936        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
2937        int err = 0;
2938        int this_cpu = sample->cpu;
2939
2940        if (this_cpu > sched->max_cpu)
2941                sched->max_cpu = this_cpu;
2942
2943        if (evsel->handler != NULL) {
2944                sched_handler f = evsel->handler;
2945
2946                err = f(tool, event, evsel, sample, machine);
2947        }
2948
2949        return err;
2950}
2951
2952static int timehist_check_attr(struct perf_sched *sched,
2953                               struct evlist *evlist)
2954{
2955        struct evsel *evsel;
2956        struct evsel_runtime *er;
2957
2958        list_for_each_entry(evsel, &evlist->core.entries, core.node) {
2959                er = evsel__get_runtime(evsel);
2960                if (er == NULL) {
2961                        pr_err("Failed to allocate memory for evsel runtime data\n");
2962                        return -1;
2963                }
2964
2965                if (sched->show_callchain && !evsel__has_callchain(evsel)) {
2966                        pr_info("Samples do not have callchains.\n");
2967                        sched->show_callchain = 0;
2968                        symbol_conf.use_callchain = 0;
2969                }
2970        }
2971
2972        return 0;
2973}
2974
2975static int perf_sched__timehist(struct perf_sched *sched)
2976{
2977        struct evsel_str_handler handlers[] = {
2978                { "sched:sched_switch",       timehist_sched_switch_event, },
2979                { "sched:sched_wakeup",       timehist_sched_wakeup_event, },
2980                { "sched:sched_waking",       timehist_sched_wakeup_event, },
2981                { "sched:sched_wakeup_new",   timehist_sched_wakeup_event, },
2982        };
2983        const struct evsel_str_handler migrate_handlers[] = {
2984                { "sched:sched_migrate_task", timehist_migrate_task_event, },
2985        };
2986        struct perf_data data = {
2987                .path  = input_name,
2988                .mode  = PERF_DATA_MODE_READ,
2989                .force = sched->force,
2990        };
2991
2992        struct perf_session *session;
2993        struct evlist *evlist;
2994        int err = -1;
2995
2996        /*
2997         * event handlers for timehist option
2998         */
2999        sched->tool.sample       = perf_timehist__process_sample;
3000        sched->tool.mmap         = perf_event__process_mmap;
3001        sched->tool.comm         = perf_event__process_comm;
3002        sched->tool.exit         = perf_event__process_exit;
3003        sched->tool.fork         = perf_event__process_fork;
3004        sched->tool.lost         = process_lost;
3005        sched->tool.attr         = perf_event__process_attr;
3006        sched->tool.tracing_data = perf_event__process_tracing_data;
3007        sched->tool.build_id     = perf_event__process_build_id;
3008
3009        sched->tool.ordered_events = true;
3010        sched->tool.ordering_requires_timestamps = true;
3011
3012        symbol_conf.use_callchain = sched->show_callchain;
3013
3014        session = perf_session__new(&data, false, &sched->tool);
3015        if (IS_ERR(session))
3016                return PTR_ERR(session);
3017
3018        if (cpu_list) {
3019                err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
3020                if (err < 0)
3021                        goto out;
3022        }
3023
3024        evlist = session->evlist;
3025
3026        symbol__init(&session->header.env);
3027
3028        if (perf_time__parse_str(&sched->ptime, sched->time_str) != 0) {
3029                pr_err("Invalid time string\n");
3030                return -EINVAL;
3031        }
3032
3033        if (timehist_check_attr(sched, evlist) != 0)
3034                goto out;
3035
3036        setup_pager();
3037
3038        /* prefer sched_waking if it is captured */
3039        if (evlist__find_tracepoint_by_name(session->evlist, "sched:sched_waking"))
3040                handlers[1].handler = timehist_sched_wakeup_ignore;
3041
3042        /* setup per-evsel handlers */
3043        if (perf_session__set_tracepoints_handlers(session, handlers))
3044                goto out;
3045
3046        /* sched_switch event at a minimum needs to exist */
3047        if (!evlist__find_tracepoint_by_name(session->evlist, "sched:sched_switch")) {
3048                pr_err("No sched_switch events found. Have you run 'perf sched record'?\n");
3049                goto out;
3050        }
3051
3052        if (sched->show_migrations &&
3053            perf_session__set_tracepoints_handlers(session, migrate_handlers))
3054                goto out;
3055
3056        /* pre-allocate struct for per-CPU idle stats */
3057        sched->max_cpu = session->header.env.nr_cpus_online;
3058        if (sched->max_cpu == 0)
3059                sched->max_cpu = 4;
3060        if (init_idle_threads(sched->max_cpu))
3061                goto out;
3062
3063        /* summary_only implies summary option, but don't overwrite summary if set */
3064        if (sched->summary_only)
3065                sched->summary = sched->summary_only;
3066
3067        if (!sched->summary_only)
3068                timehist_header(sched);
3069
3070        err = perf_session__process_events(session);
3071        if (err) {
3072                pr_err("Failed to process events, error %d", err);
3073                goto out;
3074        }
3075
3076        sched->nr_events      = evlist->stats.nr_events[0];
3077        sched->nr_lost_events = evlist->stats.total_lost;
3078        sched->nr_lost_chunks = evlist->stats.nr_events[PERF_RECORD_LOST];
3079
3080        if (sched->summary)
3081                timehist_print_summary(sched, session);
3082
3083out:
3084        free_idle_threads();
3085        perf_session__delete(session);
3086
3087        return err;
3088}
3089
3090
3091static void print_bad_events(struct perf_sched *sched)
3092{
3093        if (sched->nr_unordered_timestamps && sched->nr_timestamps) {
3094                printf("  INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
3095                        (double)sched->nr_unordered_timestamps/(double)sched->nr_timestamps*100.0,
3096                        sched->nr_unordered_timestamps, sched->nr_timestamps);
3097        }
3098        if (sched->nr_lost_events && sched->nr_events) {
3099                printf("  INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
3100                        (double)sched->nr_lost_events/(double)sched->nr_events * 100.0,
3101                        sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks);
3102        }
3103        if (sched->nr_context_switch_bugs && sched->nr_timestamps) {
3104                printf("  INFO: %.3f%% context switch bugs (%ld out of %ld)",
3105                        (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0,
3106                        sched->nr_context_switch_bugs, sched->nr_timestamps);
3107                if (sched->nr_lost_events)
3108                        printf(" (due to lost events?)");
3109                printf("\n");
3110        }
3111}
3112
3113static void __merge_work_atoms(struct rb_root_cached *root, struct work_atoms *data)
3114{
3115        struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
3116        struct work_atoms *this;
3117        const char *comm = thread__comm_str(data->thread), *this_comm;
3118        bool leftmost = true;
3119
3120        while (*new) {
3121                int cmp;
3122
3123                this = container_of(*new, struct work_atoms, node);
3124                parent = *new;
3125
3126                this_comm = thread__comm_str(this->thread);
3127                cmp = strcmp(comm, this_comm);
3128                if (cmp > 0) {
3129                        new = &((*new)->rb_left);
3130                } else if (cmp < 0) {
3131                        new = &((*new)->rb_right);
3132                        leftmost = false;
3133                } else {
3134                        this->num_merged++;
3135                        this->total_runtime += data->total_runtime;
3136                        this->nb_atoms += data->nb_atoms;
3137                        this->total_lat += data->total_lat;
3138                        list_splice(&data->work_list, &this->work_list);
3139                        if (this->max_lat < data->max_lat) {
3140                                this->max_lat = data->max_lat;
3141                                this->max_lat_start = data->max_lat_start;
3142                                this->max_lat_end = data->max_lat_end;
3143                        }
3144                        zfree(&data);
3145                        return;
3146                }
3147        }
3148
3149        data->num_merged++;
3150        rb_link_node(&data->node, parent, new);
3151        rb_insert_color_cached(&data->node, root, leftmost);
3152}
3153
3154static void perf_sched__merge_lat(struct perf_sched *sched)
3155{
3156        struct work_atoms *data;
3157        struct rb_node *node;
3158
3159        if (sched->skip_merge)
3160                return;
3161
3162        while ((node = rb_first_cached(&sched->atom_root))) {
3163                rb_erase_cached(node, &sched->atom_root);
3164                data = rb_entry(node, struct work_atoms, node);
3165                __merge_work_atoms(&sched->merged_atom_root, data);
3166        }
3167}
3168
3169static int perf_sched__lat(struct perf_sched *sched)
3170{
3171        struct rb_node *next;
3172
3173        setup_pager();
3174
3175        if (perf_sched__read_events(sched))
3176                return -1;
3177
3178        perf_sched__merge_lat(sched);
3179        perf_sched__sort_lat(sched);
3180
3181        printf("\n -------------------------------------------------------------------------------------------------------------------------------------------\n");
3182        printf("  Task                  |   Runtime ms  | Switches | Avg delay ms    | Max delay ms    | Max delay start           | Max delay end          |\n");
3183        printf(" -------------------------------------------------------------------------------------------------------------------------------------------\n");
3184
3185        next = rb_first_cached(&sched->sorted_atom_root);
3186
3187        while (next) {
3188                struct work_atoms *work_list;
3189
3190                work_list = rb_entry(next, struct work_atoms, node);
3191                output_lat_thread(sched, work_list);
3192                next = rb_next(next);
3193                thread__zput(work_list->thread);
3194        }
3195
3196        printf(" -----------------------------------------------------------------------------------------------------------------\n");
3197        printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
3198                (double)sched->all_runtime / NSEC_PER_MSEC, sched->all_count);
3199
3200        printf(" ---------------------------------------------------\n");
3201
3202        print_bad_events(sched);
3203        printf("\n");
3204
3205        return 0;
3206}
3207
3208static int setup_map_cpus(struct perf_sched *sched)
3209{
3210        struct perf_cpu_map *map;
3211
3212        sched->max_cpu  = sysconf(_SC_NPROCESSORS_CONF);
3213
3214        if (sched->map.comp) {
3215                sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int));
3216                if (!sched->map.comp_cpus)
3217                        return -1;
3218        }
3219
3220        if (!sched->map.cpus_str)
3221                return 0;
3222
3223        map = perf_cpu_map__new(sched->map.cpus_str);
3224        if (!map) {
3225                pr_err("failed to get cpus map from %s\n", sched->map.cpus_str);
3226                return -1;
3227        }
3228
3229        sched->map.cpus = map;
3230        return 0;
3231}
3232
3233static int setup_color_pids(struct perf_sched *sched)
3234{
3235        struct perf_thread_map *map;
3236
3237        if (!sched->map.color_pids_str)
3238                return 0;
3239
3240        map = thread_map__new_by_tid_str(sched->map.color_pids_str);
3241        if (!map) {
3242                pr_err("failed to get thread map from %s\n", sched->map.color_pids_str);
3243                return -1;
3244        }
3245
3246        sched->map.color_pids = map;
3247        return 0;
3248}
3249
3250static int setup_color_cpus(struct perf_sched *sched)
3251{
3252        struct perf_cpu_map *map;
3253
3254        if (!sched->map.color_cpus_str)
3255                return 0;
3256
3257        map = perf_cpu_map__new(sched->map.color_cpus_str);
3258        if (!map) {
3259                pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str);
3260                return -1;
3261        }
3262
3263        sched->map.color_cpus = map;
3264        return 0;
3265}
3266
3267static int perf_sched__map(struct perf_sched *sched)
3268{
3269        if (setup_map_cpus(sched))
3270                return -1;
3271
3272        if (setup_color_pids(sched))
3273                return -1;
3274
3275        if (setup_color_cpus(sched))
3276                return -1;
3277
3278        setup_pager();
3279        if (perf_sched__read_events(sched))
3280                return -1;
3281        print_bad_events(sched);
3282        return 0;
3283}
3284
3285static int perf_sched__replay(struct perf_sched *sched)
3286{
3287        unsigned long i;
3288
3289        calibrate_run_measurement_overhead(sched);
3290        calibrate_sleep_measurement_overhead(sched);
3291
3292        test_calibrations(sched);
3293
3294        if (perf_sched__read_events(sched))
3295                return -1;
3296
3297        printf("nr_run_events:        %ld\n", sched->nr_run_events);
3298        printf("nr_sleep_events:      %ld\n", sched->nr_sleep_events);
3299        printf("nr_wakeup_events:     %ld\n", sched->nr_wakeup_events);
3300
3301        if (sched->targetless_wakeups)
3302                printf("target-less wakeups:  %ld\n", sched->targetless_wakeups);
3303        if (sched->multitarget_wakeups)
3304                printf("multi-target wakeups: %ld\n", sched->multitarget_wakeups);
3305        if (sched->nr_run_events_optimized)
3306                printf("run atoms optimized: %ld\n",
3307                        sched->nr_run_events_optimized);
3308
3309        print_task_traces(sched);
3310        add_cross_task_wakeups(sched);
3311
3312        create_tasks(sched);
3313        printf("------------------------------------------------------------\n");
3314        for (i = 0; i < sched->replay_repeat; i++)
3315                run_one_test(sched);
3316
3317        return 0;
3318}
3319
3320static void setup_sorting(struct perf_sched *sched, const struct option *options,
3321                          const char * const usage_msg[])
3322{
3323        char *tmp, *tok, *str = strdup(sched->sort_order);
3324
3325        for (tok = strtok_r(str, ", ", &tmp);
3326                        tok; tok = strtok_r(NULL, ", ", &tmp)) {
3327                if (sort_dimension__add(tok, &sched->sort_list) < 0) {
3328                        usage_with_options_msg(usage_msg, options,
3329                                        "Unknown --sort key: `%s'", tok);
3330                }
3331        }
3332
3333        free(str);
3334
3335        sort_dimension__add("pid", &sched->cmp_pid);
3336}
3337
3338static bool schedstat_events_exposed(void)
3339{
3340        /*
3341         * Select "sched:sched_stat_wait" event to check
3342         * whether schedstat tracepoints are exposed.
3343         */
3344        return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ?
3345                false : true;
3346}
3347
3348static int __cmd_record(int argc, const char **argv)
3349{
3350        unsigned int rec_argc, i, j;
3351        const char **rec_argv;
3352        const char * const record_args[] = {
3353                "record",
3354                "-a",
3355                "-R",
3356                "-m", "1024",
3357                "-c", "1",
3358                "-e", "sched:sched_switch",
3359                "-e", "sched:sched_stat_runtime",
3360                "-e", "sched:sched_process_fork",
3361                "-e", "sched:sched_wakeup_new",
3362                "-e", "sched:sched_migrate_task",
3363        };
3364
3365        /*
3366         * The tracepoints trace_sched_stat_{wait, sleep, iowait}
3367         * are not exposed to user if CONFIG_SCHEDSTATS is not set,
3368         * to prevent "perf sched record" execution failure, determine
3369         * whether to record schedstat events according to actual situation.
3370         */
3371        const char * const schedstat_args[] = {
3372                "-e", "sched:sched_stat_wait",
3373                "-e", "sched:sched_stat_sleep",
3374                "-e", "sched:sched_stat_iowait",
3375        };
3376        unsigned int schedstat_argc = schedstat_events_exposed() ?
3377                ARRAY_SIZE(schedstat_args) : 0;
3378
3379        struct tep_event *waking_event;
3380
3381        /*
3382         * +2 for either "-e", "sched:sched_wakeup" or
3383         * "-e", "sched:sched_waking"
3384         */
3385        rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1;
3386        rec_argv = calloc(rec_argc + 1, sizeof(char *));
3387
3388        if (rec_argv == NULL)
3389                return -ENOMEM;
3390
3391        for (i = 0; i < ARRAY_SIZE(record_args); i++)
3392                rec_argv[i] = strdup(record_args[i]);
3393
3394        rec_argv[i++] = "-e";
3395        waking_event = trace_event__tp_format("sched", "sched_waking");
3396        if (!IS_ERR(waking_event))
3397                rec_argv[i++] = strdup("sched:sched_waking");
3398        else
3399                rec_argv[i++] = strdup("sched:sched_wakeup");
3400
3401        for (j = 0; j < schedstat_argc; j++)
3402                rec_argv[i++] = strdup(schedstat_args[j]);
3403
3404        for (j = 1; j < (unsigned int)argc; j++, i++)
3405                rec_argv[i] = argv[j];
3406
3407        BUG_ON(i != rec_argc);
3408
3409        return cmd_record(i, rec_argv);
3410}
3411
3412int cmd_sched(int argc, const char **argv)
3413{
3414        static const char default_sort_order[] = "avg, max, switch, runtime";
3415        struct perf_sched sched = {
3416                .tool = {
3417                        .sample          = perf_sched__process_tracepoint_sample,
3418                        .comm            = perf_sched__process_comm,
3419                        .namespaces      = perf_event__process_namespaces,
3420                        .lost            = perf_event__process_lost,
3421                        .fork            = perf_sched__process_fork_event,
3422                        .ordered_events = true,
3423                },
3424                .cmp_pid              = LIST_HEAD_INIT(sched.cmp_pid),
3425                .sort_list            = LIST_HEAD_INIT(sched.sort_list),
3426                .start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
3427                .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
3428                .sort_order           = default_sort_order,
3429                .replay_repeat        = 10,
3430                .profile_cpu          = -1,
3431                .next_shortname1      = 'A',
3432                .next_shortname2      = '0',
3433                .skip_merge           = 0,
3434                .show_callchain       = 1,
3435                .max_stack            = 5,
3436        };
3437        const struct option sched_options[] = {
3438        OPT_STRING('i', "input", &input_name, "file",
3439                    "input file name"),
3440        OPT_INCR('v', "verbose", &verbose,
3441                    "be more verbose (show symbol address, etc)"),
3442        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
3443                    "dump raw trace in ASCII"),
3444        OPT_BOOLEAN('f', "force", &sched.force, "don't complain, do it"),
3445        OPT_END()
3446        };
3447        const struct option latency_options[] = {
3448        OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
3449                   "sort by key(s): runtime, switch, avg, max"),
3450        OPT_INTEGER('C', "CPU", &sched.profile_cpu,
3451                    "CPU to profile on"),
3452        OPT_BOOLEAN('p', "pids", &sched.skip_merge,
3453                    "latency stats per pid instead of per comm"),
3454        OPT_PARENT(sched_options)
3455        };
3456        const struct option replay_options[] = {
3457        OPT_UINTEGER('r', "repeat", &sched.replay_repeat,
3458                     "repeat the workload replay N times (-1: infinite)"),
3459        OPT_PARENT(sched_options)
3460        };
3461        const struct option map_options[] = {
3462        OPT_BOOLEAN(0, "compact", &sched.map.comp,
3463                    "map output in compact mode"),
3464        OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids",
3465                   "highlight given pids in map"),
3466        OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus",
3467                    "highlight given CPUs in map"),
3468        OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus",
3469                    "display given CPUs in map"),
3470        OPT_PARENT(sched_options)
3471        };
3472        const struct option timehist_options[] = {
3473        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
3474                   "file", "vmlinux pathname"),
3475        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
3476                   "file", "kallsyms pathname"),
3477        OPT_BOOLEAN('g', "call-graph", &sched.show_callchain,
3478                    "Display call chains if present (default on)"),
3479        OPT_UINTEGER(0, "max-stack", &sched.max_stack,
3480                   "Maximum number of functions to display backtrace."),
3481        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
3482                    "Look for files with symbols relative to this directory"),
3483        OPT_BOOLEAN('s', "summary", &sched.summary_only,
3484                    "Show only syscall summary with statistics"),
3485        OPT_BOOLEAN('S', "with-summary", &sched.summary,
3486                    "Show all syscalls and summary with statistics"),
3487        OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
3488        OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"),
3489        OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
3490        OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
3491        OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
3492        OPT_STRING(0, "time", &sched.time_str, "str",
3493                   "Time span for analysis (start,stop)"),
3494        OPT_BOOLEAN(0, "state", &sched.show_state, "Show task state when sched-out"),
3495        OPT_STRING('p', "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
3496                   "analyze events only for given process id(s)"),
3497        OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
3498                   "analyze events only for given thread id(s)"),
3499        OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
3500        OPT_PARENT(sched_options)
3501        };
3502
3503        const char * const latency_usage[] = {
3504                "perf sched latency [<options>]",
3505                NULL
3506        };
3507        const char * const replay_usage[] = {
3508                "perf sched replay [<options>]",
3509                NULL
3510        };
3511        const char * const map_usage[] = {
3512                "perf sched map [<options>]",
3513                NULL
3514        };
3515        const char * const timehist_usage[] = {
3516                "perf sched timehist [<options>]",
3517                NULL
3518        };
3519        const char *const sched_subcommands[] = { "record", "latency", "map",
3520                                                  "replay", "script",
3521                                                  "timehist", NULL };
3522        const char *sched_usage[] = {
3523                NULL,
3524                NULL
3525        };
3526        struct trace_sched_handler lat_ops  = {
3527                .wakeup_event       = latency_wakeup_event,
3528                .switch_event       = latency_switch_event,
3529                .runtime_event      = latency_runtime_event,
3530                .migrate_task_event = latency_migrate_task_event,
3531        };
3532        struct trace_sched_handler map_ops  = {
3533                .switch_event       = map_switch_event,
3534        };
3535        struct trace_sched_handler replay_ops  = {
3536                .wakeup_event       = replay_wakeup_event,
3537                .switch_event       = replay_switch_event,
3538                .fork_event         = replay_fork_event,
3539        };
3540        unsigned int i;
3541
3542        for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
3543                sched.curr_pid[i] = -1;
3544
3545        argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
3546                                        sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);
3547        if (!argc)
3548                usage_with_options(sched_usage, sched_options);
3549
3550        /*
3551         * Aliased to 'perf script' for now:
3552         */
3553        if (!strcmp(argv[0], "script"))
3554                return cmd_script(argc, argv);
3555
3556        if (!strncmp(argv[0], "rec", 3)) {
3557                return __cmd_record(argc, argv);
3558        } else if (!strncmp(argv[0], "lat", 3)) {
3559                sched.tp_handler = &lat_ops;
3560                if (argc > 1) {
3561                        argc = parse_options(argc, argv, latency_options, latency_usage, 0);
3562                        if (argc)
3563                                usage_with_options(latency_usage, latency_options);
3564                }
3565                setup_sorting(&sched, latency_options, latency_usage);
3566                return perf_sched__lat(&sched);
3567        } else if (!strcmp(argv[0], "map")) {
3568                if (argc) {
3569                        argc = parse_options(argc, argv, map_options, map_usage, 0);
3570                        if (argc)
3571                                usage_with_options(map_usage, map_options);
3572                }
3573                sched.tp_handler = &map_ops;
3574                setup_sorting(&sched, latency_options, latency_usage);
3575                return perf_sched__map(&sched);
3576        } else if (!strncmp(argv[0], "rep", 3)) {
3577                sched.tp_handler = &replay_ops;
3578                if (argc) {
3579                        argc = parse_options(argc, argv, replay_options, replay_usage, 0);
3580                        if (argc)
3581                                usage_with_options(replay_usage, replay_options);
3582                }
3583                return perf_sched__replay(&sched);
3584        } else if (!strcmp(argv[0], "timehist")) {
3585                if (argc) {
3586                        argc = parse_options(argc, argv, timehist_options,
3587                                             timehist_usage, 0);
3588                        if (argc)
3589                                usage_with_options(timehist_usage, timehist_options);
3590                }
3591                if ((sched.show_wakeups || sched.show_next) &&
3592                    sched.summary_only) {
3593                        pr_err(" Error: -s and -[n|w] are mutually exclusive.\n");
3594                        parse_options_usage(timehist_usage, timehist_options, "s", true);
3595                        if (sched.show_wakeups)
3596                                parse_options_usage(NULL, timehist_options, "w", true);
3597                        if (sched.show_next)
3598                                parse_options_usage(NULL, timehist_options, "n", true);
3599                        return -EINVAL;
3600                }
3601
3602                return perf_sched__timehist(&sched);
3603        } else {
3604                usage_with_options(sched_usage, sched_options);
3605        }
3606
3607        return 0;
3608}
3609