diff options
Diffstat (limited to 'tools/perf/builtin-sched.c')
-rw-r--r-- | tools/perf/builtin-sched.c | 161 |
1 files changed, 75 insertions, 86 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index fed9ae432c16..d8c51b2f263f 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -109,8 +109,9 @@ struct trace_sched_handler { | |||
109 | int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, | 109 | int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, |
110 | struct perf_sample *sample, struct machine *machine); | 110 | struct perf_sample *sample, struct machine *machine); |
111 | 111 | ||
112 | int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel, | 112 | /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */ |
113 | struct perf_sample *sample); | 113 | int (*fork_event)(struct perf_sched *sched, union perf_event *event, |
114 | struct machine *machine); | ||
114 | 115 | ||
115 | int (*migrate_task_event)(struct perf_sched *sched, | 116 | int (*migrate_task_event)(struct perf_sched *sched, |
116 | struct perf_evsel *evsel, | 117 | struct perf_evsel *evsel, |
@@ -717,22 +718,31 @@ static int replay_switch_event(struct perf_sched *sched, | |||
717 | return 0; | 718 | return 0; |
718 | } | 719 | } |
719 | 720 | ||
720 | static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel, | 721 | static int replay_fork_event(struct perf_sched *sched, |
721 | struct perf_sample *sample) | 722 | union perf_event *event, |
723 | struct machine *machine) | ||
722 | { | 724 | { |
723 | const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"), | 725 | struct thread *child, *parent; |
724 | *child_comm = perf_evsel__strval(evsel, sample, "child_comm"); | 726 | |
725 | const u32 parent_pid = perf_evsel__intval(evsel, sample, "parent_pid"), | 727 | child = machine__findnew_thread(machine, event->fork.pid, |
726 | child_pid = perf_evsel__intval(evsel, sample, "child_pid"); | 728 | event->fork.tid); |
729 | parent = machine__findnew_thread(machine, event->fork.ppid, | ||
730 | event->fork.ptid); | ||
731 | |||
732 | if (child == NULL || parent == NULL) { | ||
733 | pr_debug("thread does not exist on fork event: child %p, parent %p\n", | ||
734 | child, parent); | ||
735 | return 0; | ||
736 | } | ||
727 | 737 | ||
728 | if (verbose) { | 738 | if (verbose) { |
729 | printf("sched_fork event %p\n", evsel); | 739 | printf("fork event\n"); |
730 | printf("... parent: %s/%d\n", parent_comm, parent_pid); | 740 | printf("... parent: %s/%d\n", parent->comm, parent->tid); |
731 | printf("... child: %s/%d\n", child_comm, child_pid); | 741 | printf("... child: %s/%d\n", child->comm, child->tid); |
732 | } | 742 | } |
733 | 743 | ||
734 | register_pid(sched, parent_pid, parent_comm); | 744 | register_pid(sched, parent->tid, parent->comm); |
735 | register_pid(sched, child_pid, child_comm); | 745 | register_pid(sched, child->tid, child->comm); |
736 | return 0; | 746 | return 0; |
737 | } | 747 | } |
738 | 748 | ||
@@ -824,14 +834,6 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) | |||
824 | return 0; | 834 | return 0; |
825 | } | 835 | } |
826 | 836 | ||
827 | static int latency_fork_event(struct perf_sched *sched __maybe_unused, | ||
828 | struct perf_evsel *evsel __maybe_unused, | ||
829 | struct perf_sample *sample __maybe_unused) | ||
830 | { | ||
831 | /* should insert the newcomer */ | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static char sched_out_state(u64 prev_state) | 837 | static char sched_out_state(u64 prev_state) |
836 | { | 838 | { |
837 | const char *str = TASK_STATE_TO_CHAR_STR; | 839 | const char *str = TASK_STATE_TO_CHAR_STR; |
@@ -934,8 +936,8 @@ static int latency_switch_event(struct perf_sched *sched, | |||
934 | return -1; | 936 | return -1; |
935 | } | 937 | } |
936 | 938 | ||
937 | sched_out = machine__findnew_thread(machine, prev_pid); | 939 | sched_out = machine__findnew_thread(machine, 0, prev_pid); |
938 | sched_in = machine__findnew_thread(machine, next_pid); | 940 | sched_in = machine__findnew_thread(machine, 0, next_pid); |
939 | 941 | ||
940 | out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); | 942 | out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); |
941 | if (!out_events) { | 943 | if (!out_events) { |
@@ -978,7 +980,7 @@ static int latency_runtime_event(struct perf_sched *sched, | |||
978 | { | 980 | { |
979 | const u32 pid = perf_evsel__intval(evsel, sample, "pid"); | 981 | const u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
980 | const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); | 982 | const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); |
981 | struct thread *thread = machine__findnew_thread(machine, pid); | 983 | struct thread *thread = machine__findnew_thread(machine, 0, pid); |
982 | struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); | 984 | struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); |
983 | u64 timestamp = sample->time; | 985 | u64 timestamp = sample->time; |
984 | int cpu = sample->cpu; | 986 | int cpu = sample->cpu; |
@@ -1016,7 +1018,7 @@ static int latency_wakeup_event(struct perf_sched *sched, | |||
1016 | if (!success) | 1018 | if (!success) |
1017 | return 0; | 1019 | return 0; |
1018 | 1020 | ||
1019 | wakee = machine__findnew_thread(machine, pid); | 1021 | wakee = machine__findnew_thread(machine, 0, pid); |
1020 | atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); | 1022 | atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); |
1021 | if (!atoms) { | 1023 | if (!atoms) { |
1022 | if (thread_atoms_insert(sched, wakee)) | 1024 | if (thread_atoms_insert(sched, wakee)) |
@@ -1070,12 +1072,12 @@ static int latency_migrate_task_event(struct perf_sched *sched, | |||
1070 | if (sched->profile_cpu == -1) | 1072 | if (sched->profile_cpu == -1) |
1071 | return 0; | 1073 | return 0; |
1072 | 1074 | ||
1073 | migrant = machine__findnew_thread(machine, pid); | 1075 | migrant = machine__findnew_thread(machine, 0, pid); |
1074 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); | 1076 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); |
1075 | if (!atoms) { | 1077 | if (!atoms) { |
1076 | if (thread_atoms_insert(sched, migrant)) | 1078 | if (thread_atoms_insert(sched, migrant)) |
1077 | return -1; | 1079 | return -1; |
1078 | register_pid(sched, migrant->pid, migrant->comm); | 1080 | register_pid(sched, migrant->tid, migrant->comm); |
1079 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); | 1081 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); |
1080 | if (!atoms) { | 1082 | if (!atoms) { |
1081 | pr_err("migration-event: Internal tree error"); | 1083 | pr_err("migration-event: Internal tree error"); |
@@ -1115,7 +1117,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1115 | sched->all_runtime += work_list->total_runtime; | 1117 | sched->all_runtime += work_list->total_runtime; |
1116 | sched->all_count += work_list->nb_atoms; | 1118 | sched->all_count += work_list->nb_atoms; |
1117 | 1119 | ||
1118 | ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); | 1120 | ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid); |
1119 | 1121 | ||
1120 | for (i = 0; i < 24 - ret; i++) | 1122 | for (i = 0; i < 24 - ret; i++) |
1121 | printf(" "); | 1123 | printf(" "); |
@@ -1131,9 +1133,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1131 | 1133 | ||
1132 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) | 1134 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
1133 | { | 1135 | { |
1134 | if (l->thread->pid < r->thread->pid) | 1136 | if (l->thread->tid < r->thread->tid) |
1135 | return -1; | 1137 | return -1; |
1136 | if (l->thread->pid > r->thread->pid) | 1138 | if (l->thread->tid > r->thread->tid) |
1137 | return 1; | 1139 | return 1; |
1138 | 1140 | ||
1139 | return 0; | 1141 | return 0; |
@@ -1289,8 +1291,8 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1289 | return -1; | 1291 | return -1; |
1290 | } | 1292 | } |
1291 | 1293 | ||
1292 | sched_out = machine__findnew_thread(machine, prev_pid); | 1294 | sched_out = machine__findnew_thread(machine, 0, prev_pid); |
1293 | sched_in = machine__findnew_thread(machine, next_pid); | 1295 | sched_in = machine__findnew_thread(machine, 0, next_pid); |
1294 | 1296 | ||
1295 | sched->curr_thread[this_cpu] = sched_in; | 1297 | sched->curr_thread[this_cpu] = sched_in; |
1296 | 1298 | ||
@@ -1321,7 +1323,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1321 | printf("*"); | 1323 | printf("*"); |
1322 | 1324 | ||
1323 | if (sched->curr_thread[cpu]) { | 1325 | if (sched->curr_thread[cpu]) { |
1324 | if (sched->curr_thread[cpu]->pid) | 1326 | if (sched->curr_thread[cpu]->tid) |
1325 | printf("%2s ", sched->curr_thread[cpu]->shortname); | 1327 | printf("%2s ", sched->curr_thread[cpu]->shortname); |
1326 | else | 1328 | else |
1327 | printf(". "); | 1329 | printf(". "); |
@@ -1332,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1332 | printf(" %12.6f secs ", (double)timestamp/1e9); | 1334 | printf(" %12.6f secs ", (double)timestamp/1e9); |
1333 | if (new_shortname) { | 1335 | if (new_shortname) { |
1334 | printf("%s => %s:%d\n", | 1336 | printf("%s => %s:%d\n", |
1335 | sched_in->shortname, sched_in->comm, sched_in->pid); | 1337 | sched_in->shortname, sched_in->comm, sched_in->tid); |
1336 | } else { | 1338 | } else { |
1337 | printf("\n"); | 1339 | printf("\n"); |
1338 | } | 1340 | } |
@@ -1379,25 +1381,20 @@ static int process_sched_runtime_event(struct perf_tool *tool, | |||
1379 | return 0; | 1381 | return 0; |
1380 | } | 1382 | } |
1381 | 1383 | ||
1382 | static int process_sched_fork_event(struct perf_tool *tool, | 1384 | static int perf_sched__process_fork_event(struct perf_tool *tool, |
1383 | struct perf_evsel *evsel, | 1385 | union perf_event *event, |
1384 | struct perf_sample *sample, | 1386 | struct perf_sample *sample, |
1385 | struct machine *machine __maybe_unused) | 1387 | struct machine *machine) |
1386 | { | 1388 | { |
1387 | struct perf_sched *sched = container_of(tool, struct perf_sched, tool); | 1389 | struct perf_sched *sched = container_of(tool, struct perf_sched, tool); |
1388 | 1390 | ||
1389 | if (sched->tp_handler->fork_event) | 1391 | /* run the fork event through the perf machineruy */ |
1390 | return sched->tp_handler->fork_event(sched, evsel, sample); | 1392 | perf_event__process_fork(tool, event, sample, machine); |
1391 | 1393 | ||
1392 | return 0; | 1394 | /* and then run additional processing needed for this command */ |
1393 | } | 1395 | if (sched->tp_handler->fork_event) |
1396 | return sched->tp_handler->fork_event(sched, event, machine); | ||
1394 | 1397 | ||
1395 | static int process_sched_exit_event(struct perf_tool *tool __maybe_unused, | ||
1396 | struct perf_evsel *evsel, | ||
1397 | struct perf_sample *sample __maybe_unused, | ||
1398 | struct machine *machine __maybe_unused) | ||
1399 | { | ||
1400 | pr_debug("sched_exit event %p\n", evsel); | ||
1401 | return 0; | 1398 | return 0; |
1402 | } | 1399 | } |
1403 | 1400 | ||
@@ -1425,15 +1422,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ | |||
1425 | struct perf_evsel *evsel, | 1422 | struct perf_evsel *evsel, |
1426 | struct machine *machine) | 1423 | struct machine *machine) |
1427 | { | 1424 | { |
1428 | struct thread *thread = machine__findnew_thread(machine, sample->tid); | ||
1429 | int err = 0; | 1425 | int err = 0; |
1430 | 1426 | ||
1431 | if (thread == NULL) { | ||
1432 | pr_debug("problem processing %s event, skipping it.\n", | ||
1433 | perf_evsel__name(evsel)); | ||
1434 | return -1; | ||
1435 | } | ||
1436 | |||
1437 | evsel->hists.stats.total_period += sample->period; | 1427 | evsel->hists.stats.total_period += sample->period; |
1438 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 1428 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
1439 | 1429 | ||
@@ -1445,7 +1435,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ | |||
1445 | return err; | 1435 | return err; |
1446 | } | 1436 | } |
1447 | 1437 | ||
1448 | static int perf_sched__read_events(struct perf_sched *sched, bool destroy, | 1438 | static int perf_sched__read_events(struct perf_sched *sched, |
1449 | struct perf_session **psession) | 1439 | struct perf_session **psession) |
1450 | { | 1440 | { |
1451 | const struct perf_evsel_str_handler handlers[] = { | 1441 | const struct perf_evsel_str_handler handlers[] = { |
@@ -1453,8 +1443,6 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, | |||
1453 | { "sched:sched_stat_runtime", process_sched_runtime_event, }, | 1443 | { "sched:sched_stat_runtime", process_sched_runtime_event, }, |
1454 | { "sched:sched_wakeup", process_sched_wakeup_event, }, | 1444 | { "sched:sched_wakeup", process_sched_wakeup_event, }, |
1455 | { "sched:sched_wakeup_new", process_sched_wakeup_event, }, | 1445 | { "sched:sched_wakeup_new", process_sched_wakeup_event, }, |
1456 | { "sched:sched_process_fork", process_sched_fork_event, }, | ||
1457 | { "sched:sched_process_exit", process_sched_exit_event, }, | ||
1458 | { "sched:sched_migrate_task", process_sched_migrate_task_event, }, | 1446 | { "sched:sched_migrate_task", process_sched_migrate_task_event, }, |
1459 | }; | 1447 | }; |
1460 | struct perf_session *session; | 1448 | struct perf_session *session; |
@@ -1480,11 +1468,10 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, | |||
1480 | sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; | 1468 | sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; |
1481 | } | 1469 | } |
1482 | 1470 | ||
1483 | if (destroy) | ||
1484 | perf_session__delete(session); | ||
1485 | |||
1486 | if (psession) | 1471 | if (psession) |
1487 | *psession = session; | 1472 | *psession = session; |
1473 | else | ||
1474 | perf_session__delete(session); | ||
1488 | 1475 | ||
1489 | return 0; | 1476 | return 0; |
1490 | 1477 | ||
@@ -1529,8 +1516,11 @@ static int perf_sched__lat(struct perf_sched *sched) | |||
1529 | struct perf_session *session; | 1516 | struct perf_session *session; |
1530 | 1517 | ||
1531 | setup_pager(); | 1518 | setup_pager(); |
1532 | if (perf_sched__read_events(sched, false, &session)) | 1519 | |
1520 | /* save session -- references to threads are held in work_list */ | ||
1521 | if (perf_sched__read_events(sched, &session)) | ||
1533 | return -1; | 1522 | return -1; |
1523 | |||
1534 | perf_sched__sort_lat(sched); | 1524 | perf_sched__sort_lat(sched); |
1535 | 1525 | ||
1536 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); | 1526 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); |
@@ -1565,7 +1555,7 @@ static int perf_sched__map(struct perf_sched *sched) | |||
1565 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1555 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); |
1566 | 1556 | ||
1567 | setup_pager(); | 1557 | setup_pager(); |
1568 | if (perf_sched__read_events(sched, true, NULL)) | 1558 | if (perf_sched__read_events(sched, NULL)) |
1569 | return -1; | 1559 | return -1; |
1570 | print_bad_events(sched); | 1560 | print_bad_events(sched); |
1571 | return 0; | 1561 | return 0; |
@@ -1580,7 +1570,7 @@ static int perf_sched__replay(struct perf_sched *sched) | |||
1580 | 1570 | ||
1581 | test_calibrations(sched); | 1571 | test_calibrations(sched); |
1582 | 1572 | ||
1583 | if (perf_sched__read_events(sched, true, NULL)) | 1573 | if (perf_sched__read_events(sched, NULL)) |
1584 | return -1; | 1574 | return -1; |
1585 | 1575 | ||
1586 | printf("nr_run_events: %ld\n", sched->nr_run_events); | 1576 | printf("nr_run_events: %ld\n", sched->nr_run_events); |
@@ -1639,7 +1629,6 @@ static int __cmd_record(int argc, const char **argv) | |||
1639 | "-e", "sched:sched_stat_sleep", | 1629 | "-e", "sched:sched_stat_sleep", |
1640 | "-e", "sched:sched_stat_iowait", | 1630 | "-e", "sched:sched_stat_iowait", |
1641 | "-e", "sched:sched_stat_runtime", | 1631 | "-e", "sched:sched_stat_runtime", |
1642 | "-e", "sched:sched_process_exit", | ||
1643 | "-e", "sched:sched_process_fork", | 1632 | "-e", "sched:sched_process_fork", |
1644 | "-e", "sched:sched_wakeup", | 1633 | "-e", "sched:sched_wakeup", |
1645 | "-e", "sched:sched_migrate_task", | 1634 | "-e", "sched:sched_migrate_task", |
@@ -1662,28 +1651,29 @@ static int __cmd_record(int argc, const char **argv) | |||
1662 | return cmd_record(i, rec_argv, NULL); | 1651 | return cmd_record(i, rec_argv, NULL); |
1663 | } | 1652 | } |
1664 | 1653 | ||
1654 | static const char default_sort_order[] = "avg, max, switch, runtime"; | ||
1655 | static struct perf_sched sched = { | ||
1656 | .tool = { | ||
1657 | .sample = perf_sched__process_tracepoint_sample, | ||
1658 | .comm = perf_event__process_comm, | ||
1659 | .lost = perf_event__process_lost, | ||
1660 | .fork = perf_sched__process_fork_event, | ||
1661 | .ordered_samples = true, | ||
1662 | }, | ||
1663 | .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), | ||
1664 | .sort_list = LIST_HEAD_INIT(sched.sort_list), | ||
1665 | .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1666 | .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1667 | .curr_pid = { [0 ... MAX_CPUS - 1] = -1 }, | ||
1668 | .sort_order = default_sort_order, | ||
1669 | .replay_repeat = 10, | ||
1670 | .profile_cpu = -1, | ||
1671 | .next_shortname1 = 'A', | ||
1672 | .next_shortname2 = '0', | ||
1673 | }; | ||
1674 | |||
1665 | int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | 1675 | int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) |
1666 | { | 1676 | { |
1667 | const char default_sort_order[] = "avg, max, switch, runtime"; | ||
1668 | struct perf_sched sched = { | ||
1669 | .tool = { | ||
1670 | .sample = perf_sched__process_tracepoint_sample, | ||
1671 | .comm = perf_event__process_comm, | ||
1672 | .lost = perf_event__process_lost, | ||
1673 | .fork = perf_event__process_fork, | ||
1674 | .ordered_samples = true, | ||
1675 | }, | ||
1676 | .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), | ||
1677 | .sort_list = LIST_HEAD_INIT(sched.sort_list), | ||
1678 | .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1679 | .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1680 | .curr_pid = { [0 ... MAX_CPUS - 1] = -1 }, | ||
1681 | .sort_order = default_sort_order, | ||
1682 | .replay_repeat = 10, | ||
1683 | .profile_cpu = -1, | ||
1684 | .next_shortname1 = 'A', | ||
1685 | .next_shortname2 = '0', | ||
1686 | }; | ||
1687 | const struct option latency_options[] = { | 1677 | const struct option latency_options[] = { |
1688 | OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", | 1678 | OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", |
1689 | "sort by key(s): runtime, switch, avg, max"), | 1679 | "sort by key(s): runtime, switch, avg, max"), |
@@ -1729,7 +1719,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1729 | .wakeup_event = latency_wakeup_event, | 1719 | .wakeup_event = latency_wakeup_event, |
1730 | .switch_event = latency_switch_event, | 1720 | .switch_event = latency_switch_event, |
1731 | .runtime_event = latency_runtime_event, | 1721 | .runtime_event = latency_runtime_event, |
1732 | .fork_event = latency_fork_event, | ||
1733 | .migrate_task_event = latency_migrate_task_event, | 1722 | .migrate_task_event = latency_migrate_task_event, |
1734 | }; | 1723 | }; |
1735 | struct trace_sched_handler map_ops = { | 1724 | struct trace_sched_handler map_ops = { |