diff options
| author | Dario Faggioli <raistlin@linux.it> | 2013-11-07 08:43:42 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2014-01-13 07:41:11 -0500 |
| commit | af6ace764d03900524e9b1ac621a1c520ee49fc6 (patch) | |
| tree | 4fd7117b730a77a77be2bcd24c53284f9568ed75 /kernel | |
| parent | 755378a47192a3d1f7c3a8ca6c15c1cf76de0af2 (diff) | |
sched/deadline: Add latency tracing for SCHED_DEADLINE tasks
It is very likely that systems that wants/needs to use the new
SCHED_DEADLINE policy also want to have the scheduling latency of
the -deadline tasks under control.
For this reason a new version of the scheduling wakeup latency,
called "wakeup_dl", is introduced.
As a consequence of applying this patch there will be three wakeup
latency tracer:
* "wakeup", that deals with all tasks in the system;
* "wakeup_rt", that deals with -rt and -deadline tasks only;
* "wakeup_dl", that deals with -deadline tasks only.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-9-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace_sched_wakeup.c | 64 | ||||
| -rw-r--r-- | kernel/trace/trace_selftest.c | 33 |
2 files changed, 79 insertions, 18 deletions
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index fee77e15d815..090c4d9dcf16 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c | |||
| @@ -27,6 +27,8 @@ static int wakeup_cpu; | |||
| 27 | static int wakeup_current_cpu; | 27 | static int wakeup_current_cpu; |
| 28 | static unsigned wakeup_prio = -1; | 28 | static unsigned wakeup_prio = -1; |
| 29 | static int wakeup_rt; | 29 | static int wakeup_rt; |
| 30 | static int wakeup_dl; | ||
| 31 | static int tracing_dl = 0; | ||
| 30 | 32 | ||
| 31 | static arch_spinlock_t wakeup_lock = | 33 | static arch_spinlock_t wakeup_lock = |
| 32 | (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; | 34 | (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; |
| @@ -437,6 +439,7 @@ static void __wakeup_reset(struct trace_array *tr) | |||
| 437 | { | 439 | { |
| 438 | wakeup_cpu = -1; | 440 | wakeup_cpu = -1; |
| 439 | wakeup_prio = -1; | 441 | wakeup_prio = -1; |
| 442 | tracing_dl = 0; | ||
| 440 | 443 | ||
| 441 | if (wakeup_task) | 444 | if (wakeup_task) |
| 442 | put_task_struct(wakeup_task); | 445 | put_task_struct(wakeup_task); |
| @@ -472,9 +475,17 @@ probe_wakeup(void *ignore, struct task_struct *p, int success) | |||
| 472 | tracing_record_cmdline(p); | 475 | tracing_record_cmdline(p); |
| 473 | tracing_record_cmdline(current); | 476 | tracing_record_cmdline(current); |
| 474 | 477 | ||
| 475 | if ((wakeup_rt && !rt_task(p)) || | 478 | /* |
| 476 | p->prio >= wakeup_prio || | 479 | * Semantic is like this: |
| 477 | p->prio >= current->prio) | 480 | * - wakeup tracer handles all tasks in the system, independently |
| 481 | * from their scheduling class; | ||
| 482 | * - wakeup_rt tracer handles tasks belonging to sched_dl and | ||
| 483 | * sched_rt class; | ||
| 484 | * - wakeup_dl handles tasks belonging to sched_dl class only. | ||
| 485 | */ | ||
| 486 | if (tracing_dl || (wakeup_dl && !dl_task(p)) || | ||
| 487 | (wakeup_rt && !dl_task(p) && !rt_task(p)) || | ||
| 488 | (!dl_task(p) && (p->prio >= wakeup_prio || p->prio >= current->prio))) | ||
| 478 | return; | 489 | return; |
| 479 | 490 | ||
| 480 | pc = preempt_count(); | 491 | pc = preempt_count(); |
| @@ -486,7 +497,8 @@ probe_wakeup(void *ignore, struct task_struct *p, int success) | |||
| 486 | arch_spin_lock(&wakeup_lock); | 497 | arch_spin_lock(&wakeup_lock); |
| 487 | 498 | ||
| 488 | /* check for races. */ | 499 | /* check for races. */ |
| 489 | if (!tracer_enabled || p->prio >= wakeup_prio) | 500 | if (!tracer_enabled || tracing_dl || |
| 501 | (!dl_task(p) && p->prio >= wakeup_prio)) | ||
| 490 | goto out_locked; | 502 | goto out_locked; |
| 491 | 503 | ||
| 492 | /* reset the trace */ | 504 | /* reset the trace */ |
| @@ -496,6 +508,15 @@ probe_wakeup(void *ignore, struct task_struct *p, int success) | |||
| 496 | wakeup_current_cpu = wakeup_cpu; | 508 | wakeup_current_cpu = wakeup_cpu; |
| 497 | wakeup_prio = p->prio; | 509 | wakeup_prio = p->prio; |
| 498 | 510 | ||
| 511 | /* | ||
| 512 | * Once you start tracing a -deadline task, don't bother tracing | ||
| 513 | * another task until the first one wakes up. | ||
| 514 | */ | ||
| 515 | if (dl_task(p)) | ||
| 516 | tracing_dl = 1; | ||
| 517 | else | ||
| 518 | tracing_dl = 0; | ||
| 519 | |||
| 499 | wakeup_task = p; | 520 | wakeup_task = p; |
| 500 | get_task_struct(wakeup_task); | 521 | get_task_struct(wakeup_task); |
| 501 | 522 | ||
| @@ -597,16 +618,25 @@ static int __wakeup_tracer_init(struct trace_array *tr) | |||
| 597 | 618 | ||
| 598 | static int wakeup_tracer_init(struct trace_array *tr) | 619 | static int wakeup_tracer_init(struct trace_array *tr) |
| 599 | { | 620 | { |
| 621 | wakeup_dl = 0; | ||
| 600 | wakeup_rt = 0; | 622 | wakeup_rt = 0; |
| 601 | return __wakeup_tracer_init(tr); | 623 | return __wakeup_tracer_init(tr); |
| 602 | } | 624 | } |
| 603 | 625 | ||
| 604 | static int wakeup_rt_tracer_init(struct trace_array *tr) | 626 | static int wakeup_rt_tracer_init(struct trace_array *tr) |
| 605 | { | 627 | { |
| 628 | wakeup_dl = 0; | ||
| 606 | wakeup_rt = 1; | 629 | wakeup_rt = 1; |
| 607 | return __wakeup_tracer_init(tr); | 630 | return __wakeup_tracer_init(tr); |
| 608 | } | 631 | } |
| 609 | 632 | ||
| 633 | static int wakeup_dl_tracer_init(struct trace_array *tr) | ||
| 634 | { | ||
| 635 | wakeup_dl = 1; | ||
| 636 | wakeup_rt = 0; | ||
| 637 | return __wakeup_tracer_init(tr); | ||
| 638 | } | ||
| 639 | |||
| 610 | static void wakeup_tracer_reset(struct trace_array *tr) | 640 | static void wakeup_tracer_reset(struct trace_array *tr) |
| 611 | { | 641 | { |
| 612 | int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT; | 642 | int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT; |
| @@ -674,6 +704,28 @@ static struct tracer wakeup_rt_tracer __read_mostly = | |||
| 674 | .use_max_tr = true, | 704 | .use_max_tr = true, |
| 675 | }; | 705 | }; |
| 676 | 706 | ||
| 707 | static struct tracer wakeup_dl_tracer __read_mostly = | ||
| 708 | { | ||
| 709 | .name = "wakeup_dl", | ||
| 710 | .init = wakeup_dl_tracer_init, | ||
| 711 | .reset = wakeup_tracer_reset, | ||
| 712 | .start = wakeup_tracer_start, | ||
| 713 | .stop = wakeup_tracer_stop, | ||
| 714 | .wait_pipe = poll_wait_pipe, | ||
| 715 | .print_max = true, | ||
| 716 | .print_header = wakeup_print_header, | ||
| 717 | .print_line = wakeup_print_line, | ||
| 718 | .flags = &tracer_flags, | ||
| 719 | .set_flag = wakeup_set_flag, | ||
| 720 | .flag_changed = wakeup_flag_changed, | ||
| 721 | #ifdef CONFIG_FTRACE_SELFTEST | ||
| 722 | .selftest = trace_selftest_startup_wakeup, | ||
| 723 | #endif | ||
| 724 | .open = wakeup_trace_open, | ||
| 725 | .close = wakeup_trace_close, | ||
| 726 | .use_max_tr = true, | ||
| 727 | }; | ||
| 728 | |||
| 677 | __init static int init_wakeup_tracer(void) | 729 | __init static int init_wakeup_tracer(void) |
| 678 | { | 730 | { |
| 679 | int ret; | 731 | int ret; |
| @@ -686,6 +738,10 @@ __init static int init_wakeup_tracer(void) | |||
| 686 | if (ret) | 738 | if (ret) |
| 687 | return ret; | 739 | return ret; |
| 688 | 740 | ||
| 741 | ret = register_tracer(&wakeup_dl_tracer); | ||
| 742 | if (ret) | ||
| 743 | return ret; | ||
| 744 | |||
| 689 | return 0; | 745 | return 0; |
| 690 | } | 746 | } |
| 691 | core_initcall(init_wakeup_tracer); | 747 | core_initcall(init_wakeup_tracer); |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index a7329b7902f8..e98fca60974f 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
| @@ -1022,11 +1022,16 @@ trace_selftest_startup_nop(struct tracer *trace, struct trace_array *tr) | |||
| 1022 | #ifdef CONFIG_SCHED_TRACER | 1022 | #ifdef CONFIG_SCHED_TRACER |
| 1023 | static int trace_wakeup_test_thread(void *data) | 1023 | static int trace_wakeup_test_thread(void *data) |
| 1024 | { | 1024 | { |
| 1025 | /* Make this a RT thread, doesn't need to be too high */ | 1025 | /* Make this a -deadline thread */ |
| 1026 | static const struct sched_param param = { .sched_priority = 5 }; | 1026 | static const struct sched_attr attr = { |
| 1027 | .sched_policy = SCHED_DEADLINE, | ||
| 1028 | .sched_runtime = 100000ULL, | ||
| 1029 | .sched_deadline = 10000000ULL, | ||
| 1030 | .sched_period = 10000000ULL | ||
| 1031 | }; | ||
| 1027 | struct completion *x = data; | 1032 | struct completion *x = data; |
| 1028 | 1033 | ||
| 1029 | sched_setscheduler(current, SCHED_FIFO, ¶m); | 1034 | sched_setattr(current, &attr); |
| 1030 | 1035 | ||
| 1031 | /* Make it know we have a new prio */ | 1036 | /* Make it know we have a new prio */ |
| 1032 | complete(x); | 1037 | complete(x); |
| @@ -1040,8 +1045,8 @@ static int trace_wakeup_test_thread(void *data) | |||
| 1040 | /* we are awake, now wait to disappear */ | 1045 | /* we are awake, now wait to disappear */ |
| 1041 | while (!kthread_should_stop()) { | 1046 | while (!kthread_should_stop()) { |
| 1042 | /* | 1047 | /* |
| 1043 | * This is an RT task, do short sleeps to let | 1048 | * This will likely be the system top priority |
| 1044 | * others run. | 1049 | * task, do short sleeps to let others run. |
| 1045 | */ | 1050 | */ |
| 1046 | msleep(100); | 1051 | msleep(100); |
| 1047 | } | 1052 | } |
| @@ -1054,21 +1059,21 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) | |||
| 1054 | { | 1059 | { |
| 1055 | unsigned long save_max = tracing_max_latency; | 1060 | unsigned long save_max = tracing_max_latency; |
| 1056 | struct task_struct *p; | 1061 | struct task_struct *p; |
| 1057 | struct completion isrt; | 1062 | struct completion is_ready; |
| 1058 | unsigned long count; | 1063 | unsigned long count; |
| 1059 | int ret; | 1064 | int ret; |
| 1060 | 1065 | ||
| 1061 | init_completion(&isrt); | 1066 | init_completion(&is_ready); |
| 1062 | 1067 | ||
| 1063 | /* create a high prio thread */ | 1068 | /* create a -deadline thread */ |
| 1064 | p = kthread_run(trace_wakeup_test_thread, &isrt, "ftrace-test"); | 1069 | p = kthread_run(trace_wakeup_test_thread, &is_ready, "ftrace-test"); |
| 1065 | if (IS_ERR(p)) { | 1070 | if (IS_ERR(p)) { |
| 1066 | printk(KERN_CONT "Failed to create ftrace wakeup test thread "); | 1071 | printk(KERN_CONT "Failed to create ftrace wakeup test thread "); |
| 1067 | return -1; | 1072 | return -1; |
| 1068 | } | 1073 | } |
| 1069 | 1074 | ||
| 1070 | /* make sure the thread is running at an RT prio */ | 1075 | /* make sure the thread is running at -deadline policy */ |
| 1071 | wait_for_completion(&isrt); | 1076 | wait_for_completion(&is_ready); |
| 1072 | 1077 | ||
| 1073 | /* start the tracing */ | 1078 | /* start the tracing */ |
| 1074 | ret = tracer_init(trace, tr); | 1079 | ret = tracer_init(trace, tr); |
| @@ -1082,19 +1087,19 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) | |||
| 1082 | 1087 | ||
| 1083 | while (p->on_rq) { | 1088 | while (p->on_rq) { |
| 1084 | /* | 1089 | /* |
| 1085 | * Sleep to make sure the RT thread is asleep too. | 1090 | * Sleep to make sure the -deadline thread is asleep too. |
| 1086 | * On virtual machines we can't rely on timings, | 1091 | * On virtual machines we can't rely on timings, |
| 1087 | * but we want to make sure this test still works. | 1092 | * but we want to make sure this test still works. |
| 1088 | */ | 1093 | */ |
| 1089 | msleep(100); | 1094 | msleep(100); |
| 1090 | } | 1095 | } |
| 1091 | 1096 | ||
| 1092 | init_completion(&isrt); | 1097 | init_completion(&is_ready); |
| 1093 | 1098 | ||
| 1094 | wake_up_process(p); | 1099 | wake_up_process(p); |
| 1095 | 1100 | ||
| 1096 | /* Wait for the task to wake up */ | 1101 | /* Wait for the task to wake up */ |
| 1097 | wait_for_completion(&isrt); | 1102 | wait_for_completion(&is_ready); |
| 1098 | 1103 | ||
| 1099 | /* stop the tracing. */ | 1104 | /* stop the tracing. */ |
| 1100 | tracing_stop(); | 1105 | tracing_stop(); |
