diff options
Diffstat (limited to 'tools/perf/builtin-sched.c')
-rw-r--r-- | tools/perf/builtin-sched.c | 189 |
1 files changed, 149 insertions, 40 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 5977c49ae2c7..8750b5f2d49b 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -156,6 +156,9 @@ struct perf_sched_map { const char *color_pids_str; struct perf_cpu_map *color_cpus; const char *color_cpus_str; + const char *task_name; + struct strlist *task_names; + bool fuzzy; struct perf_cpu_map *cpus; const char *cpus_str; }; @@ -177,6 +180,7 @@ struct perf_sched { struct perf_cpu max_cpu; u32 *curr_pid; struct thread **curr_thread; + struct thread **curr_out_thread; char next_shortname1; char next_shortname2; unsigned int replay_repeat; @@ -1538,23 +1542,91 @@ map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid return thread; } +static bool sched_match_task(struct perf_sched *sched, const char *comm_str) +{ + bool fuzzy_match = sched->map.fuzzy; + struct strlist *task_names = sched->map.task_names; + struct str_node *node; + + strlist__for_each_entry(node, task_names) { + bool match_found = fuzzy_match ? !!strstr(comm_str, node->s) : + !strcmp(comm_str, node->s); + if (match_found) + return true; + } + + return false; +} + +static void print_sched_map(struct perf_sched *sched, struct perf_cpu this_cpu, int cpus_nr, + const char *color, bool sched_out) +{ + for (int i = 0; i < cpus_nr; i++) { + struct perf_cpu cpu = { + .cpu = sched->map.comp ? sched->map.comp_cpus[i].cpu : i, + }; + struct thread *curr_thread = sched->curr_thread[cpu.cpu]; + struct thread *curr_out_thread = sched->curr_out_thread[cpu.cpu]; + struct thread_runtime *curr_tr; + const char *pid_color = color; + const char *cpu_color = color; + char symbol = ' '; + struct thread *thread_to_check = sched_out ? curr_out_thread : curr_thread; + + if (thread_to_check && thread__has_color(thread_to_check)) + pid_color = COLOR_PIDS; + + if (sched->map.color_cpus && perf_cpu_map__has(sched->map.color_cpus, cpu)) + cpu_color = COLOR_CPUS; + + if (cpu.cpu == this_cpu.cpu) + symbol = '*'; + + color_fprintf(stdout, cpu.cpu != this_cpu.cpu ? color : cpu_color, "%c", symbol); + + thread_to_check = sched_out ? sched->curr_out_thread[cpu.cpu] : + sched->curr_thread[cpu.cpu]; + + if (thread_to_check) { + curr_tr = thread__get_runtime(thread_to_check); + if (curr_tr == NULL) + return; + + if (sched_out) { + if (cpu.cpu == this_cpu.cpu) + color_fprintf(stdout, color, "- "); + else { + curr_tr = thread__get_runtime(sched->curr_thread[cpu.cpu]); + if (curr_tr != NULL) + color_fprintf(stdout, pid_color, "%2s ", + curr_tr->shortname); + } + } else + color_fprintf(stdout, pid_color, "%2s ", curr_tr->shortname); + } else + color_fprintf(stdout, color, " "); + } +} + static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, struct perf_sample *sample, struct machine *machine) { const u32 next_pid = evsel__intval(evsel, sample, "next_pid"); - struct thread *sched_in; + const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"); + struct thread *sched_in, *sched_out; struct thread_runtime *tr; int new_shortname; u64 timestamp0, timestamp = sample->time; s64 delta; - int i; struct perf_cpu this_cpu = { .cpu = sample->cpu, }; int cpus_nr; + int proceed; bool new_cpu = false; const char *color = PERF_COLOR_NORMAL; char stimestamp[32]; + const char *str; BUG_ON(this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0); @@ -1583,7 +1655,8 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, } sched_in = map__findnew_thread(sched, machine, -1, next_pid); - if (sched_in == NULL) + sched_out = map__findnew_thread(sched, machine, -1, prev_pid); + if (sched_in == NULL || sched_out == NULL) return -1; tr = thread__get_runtime(sched_in); @@ -1593,9 +1666,9 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, } sched->curr_thread[this_cpu.cpu] = thread__get(sched_in); + sched->curr_out_thread[this_cpu.cpu] = thread__get(sched_out); - printf(" "); - + str = thread__comm_str(sched_in); new_shortname = 0; if (!tr->shortname[0]) { if (!strcmp(thread__comm_str(sched_in), "swapper")) { @@ -1605,7 +1678,7 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, */ tr->shortname[0] = '.'; tr->shortname[1] = ' '; - } else { + } else if (!sched->map.task_name || sched_match_task(sched, str)) { tr->shortname[0] = sched->next_shortname1; tr->shortname[1] = sched->next_shortname2; @@ -1618,46 +1691,37 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, else sched->next_shortname2 = '0'; } + } else { + tr->shortname[0] = '-'; + tr->shortname[1] = ' '; } new_shortname = 1; } - for (i = 0; i < cpus_nr; i++) { - struct perf_cpu cpu = { - .cpu = sched->map.comp ? sched->map.comp_cpus[i].cpu : i, - }; - struct thread *curr_thread = sched->curr_thread[cpu.cpu]; - struct thread_runtime *curr_tr; - const char *pid_color = color; - const char *cpu_color = color; - - if (curr_thread && thread__has_color(curr_thread)) - pid_color = COLOR_PIDS; - - if (sched->map.cpus && !perf_cpu_map__has(sched->map.cpus, cpu)) - continue; - - if (sched->map.color_cpus && perf_cpu_map__has(sched->map.color_cpus, cpu)) - cpu_color = COLOR_CPUS; + if (sched->map.cpus && !perf_cpu_map__has(sched->map.cpus, this_cpu)) + goto out; - if (cpu.cpu != this_cpu.cpu) - color_fprintf(stdout, color, " "); + proceed = 0; + str = thread__comm_str(sched_in); + /* + * Check which of sched_in and sched_out matches the passed --task-name + * arguments and call the corresponding print_sched_map. + */ + if (sched->map.task_name && !sched_match_task(sched, str)) { + if (!sched_match_task(sched, thread__comm_str(sched_out))) + goto out; else - color_fprintf(stdout, cpu_color, "*"); + goto sched_out; - if (sched->curr_thread[cpu.cpu]) { - curr_tr = thread__get_runtime(sched->curr_thread[cpu.cpu]); - if (curr_tr == NULL) { - thread__put(sched_in); - return -1; - } - color_fprintf(stdout, pid_color, "%2s ", curr_tr->shortname); - } else - color_fprintf(stdout, color, " "); + } else { + str = thread__comm_str(sched_out); + if (!(sched->map.task_name && !sched_match_task(sched, str))) + proceed = 1; } - if (sched->map.cpus && !perf_cpu_map__has(sched->map.cpus, this_cpu)) - goto out; + printf(" "); + + print_sched_map(sched, this_cpu, cpus_nr, color, false); timestamp__scnprintf_usec(timestamp, stimestamp, sizeof(stimestamp)); color_fprintf(stdout, color, " %12s secs ", stimestamp); @@ -1675,9 +1739,32 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, if (sched->map.comp && new_cpu) color_fprintf(stdout, color, " (CPU %d)", this_cpu); -out: + if (proceed != 1) { + color_fprintf(stdout, color, "\n"); + goto out; + } + +sched_out: + if (sched->map.task_name) { + tr = thread__get_runtime(sched->curr_out_thread[this_cpu.cpu]); + if (strcmp(tr->shortname, "") == 0) + goto out; + + if (proceed == 1) + color_fprintf(stdout, color, "\n"); + + printf(" "); + print_sched_map(sched, this_cpu, cpus_nr, color, true); + timestamp__scnprintf_usec(timestamp, stimestamp, sizeof(stimestamp)); + color_fprintf(stdout, color, " %12s secs ", stimestamp); + } + color_fprintf(stdout, color, "\n"); +out: + if (sched->map.task_name) + thread__put(sched_out); + thread__put(sched_in); return 0; @@ -2659,7 +2746,10 @@ out: tr->last_state = state; /* sched out event for task so reset ready to run time */ - tr->ready_to_run = 0; + if (state == 'R') + tr->ready_to_run = t; + else + tr->ready_to_run = 0; } evsel__save_time(evsel, sample->time, sample->cpu); @@ -3307,6 +3397,10 @@ static int perf_sched__map(struct perf_sched *sched) if (!sched->curr_thread) return rc; + sched->curr_out_thread = calloc(MAX_CPUS, sizeof(*(sched->curr_out_thread))); + if (!sched->curr_out_thread) + return rc; + if (setup_cpus_switch_event(sched)) goto out_free_curr_thread; @@ -3383,6 +3477,9 @@ static int perf_sched__replay(struct perf_sched *sched) sched->thread_funcs_exit = false; create_tasks(sched); printf("------------------------------------------------------------\n"); + if (sched->replay_repeat == 0) + sched->replay_repeat = UINT_MAX; + for (i = 0; i < sched->replay_repeat; i++) run_one_test(sched); @@ -3548,7 +3645,7 @@ int cmd_sched(int argc, const char **argv) }; const struct option replay_options[] = { OPT_UINTEGER('r', "repeat", &sched.replay_repeat, - "repeat the workload replay N times (-1: infinite)"), + "repeat the workload replay N times (0: infinite)"), OPT_PARENT(sched_options) }; const struct option map_options[] = { @@ -3560,6 +3657,10 @@ int cmd_sched(int argc, const char **argv) "highlight given CPUs in map"), OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus", "display given CPUs in map"), + OPT_STRING(0, "task-name", &sched.map.task_name, "task", + "map output only for the given task name(s)."), + OPT_BOOLEAN(0, "fuzzy-name", &sched.map.fuzzy, + "given command name can be partially matched (fuzzy matching)"), OPT_PARENT(sched_options) }; const struct option timehist_options[] = { @@ -3658,6 +3759,14 @@ int cmd_sched(int argc, const char **argv) argc = parse_options(argc, argv, map_options, map_usage, 0); if (argc) usage_with_options(map_usage, map_options); + + if (sched.map.task_name) { + sched.map.task_names = strlist__new(sched.map.task_name, NULL); + if (sched.map.task_names == NULL) { + fprintf(stderr, "Failed to parse task names\n"); + return -1; + } + } } sched.tp_handler = &map_ops; setup_sorting(&sched, latency_options, latency_usage); |