| From 4031ea4537276ecfd1a4ca63fa75df7086b5c725 Mon Sep 17 00:00:00 2001 |
| From: Paul Gortmaker <paul.gortmaker@windriver.com> |
| Date: Sat, 22 Jan 2011 17:07:07 -0500 |
| Subject: [PATCH] trace bundle uprev parts from merges. |
| |
| This is one of several extractions from the merge up to 33-rc8. |
| |
| See portions of it in a git tip repo with: |
| |
| git diff 5f854cfc024622e4aae14d7cf422f6ff86278688^ \ |
| 5f854cfc024622e4aae14d7cf422f6ff86278688 |
| |
| You can find the origin of this change in the tip merge commit: |
| |
| commit 5f854cfc024622e4aae14d7cf422f6ff86278688 |
| Merge: cc24da0 4ec62b2 |
| Author: Thomas Gleixner <tglx@linutronix.de> |
| Date: Sun Feb 21 20:17:22 2010 +0100 |
| |
| Forward to 2.6.33-rc8 |
| |
| Merge branch 'linus' into rt/head with a pile of conflicts. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| |
| Normally there are not significant changes/additions in a merge commit that |
| are not from any other "normal" commit. But in this case there are, so |
| break them out into separate explicit commits. |
| |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt |
| index 14cc034..03485bf 100644 |
| --- a/Documentation/trace/ftrace.txt |
| +++ b/Documentation/trace/ftrace.txt |
| @@ -117,14 +117,9 @@ of ftrace. Here is a list of some of the key files: |
| For example, the time interrupts are disabled. |
| This time is saved in this file. The max trace |
| will also be stored, and displayed by "trace". |
| - A new max trace will only be recorded, if the |
| + A new max trace will only be recorded if the |
| latency is greater than the value in this |
| - file (in microseconds). Note that the max latency |
| - recorded by the wakeup and the wakeup_rt tracer |
| - do not necessarily reflect the worst-case latency |
| - of the system, but may be erroneously high in |
| - case two or more processes share the maximum |
| - priority of the system. |
| + file. (in microseconds) |
| |
| buffer_size_kb: |
| |
| diff --git a/Documentation/trace/histograms.txt b/Documentation/trace/histograms.txt |
| index 2f17967..6645057 100644 |
| --- a/Documentation/trace/histograms.txt |
| +++ b/Documentation/trace/histograms.txt |
| @@ -24,43 +24,26 @@ histograms of potential sources of latency, the kernel stores the time |
| stamp at the start of a critical section, determines the time elapsed |
| when the end of the section is reached, and increments the frequency |
| counter of that latency value - irrespective of whether any concurrently |
| -running process is affected by this latency or not. |
| +running process is affected by latency or not. |
| - Configuration items (in the Kernel hacking/Tracers submenu) |
| - CONFIG_INTERRUPT_OFF_HIST |
| - CONFIG_PREEMPT_OFF_HIST |
| + CONFIG_INTERRUPT_OFF_LATENCY |
| + CONFIG_PREEMPT_OFF_LATENCY |
| |
| |
| * Effective latencies |
| -There are two types of effective latencies, wakeup latencies and missed |
| -timer latencies |
| - |
| -* Wakeup latencies |
| -Wakeup latencies may occur during wakeup of a process. To determine |
| -wakeup latencies, the kernel stores the time stamp when a process is |
| -scheduled to be woken up, and determines the duration of the wakeup time |
| -shortly before control is passed over to this process. Note that the |
| -apparent latency in user space may be considerably longer, since |
| -i) interrupts may be disabled preventing the timer from waking up a process |
| -in time |
| + |
| +Effective latencies are actually occuring during wakeup of a process. To |
| +determine effective latencies, the kernel stores the time stamp when a |
| +process is scheduled to be woken up, and determines the duration of the |
| +wakeup time shortly before control is passed over to this process. Note |
| +that the apparent latency in user space may be considerably longer, |
| +since |
| +i) interrupts may be disabled preventing the scheduler from initiating |
| +the wakeup mechanism, and |
| ii) the process may be interrupted after control is passed over to it |
| but before user space execution takes place. |
| -If a particular wakeup latency is highest so far, details of the task |
| -that is suffering from this latency are stored as well (see below). |
| -- Configuration item (in the Kernel hacking/Tracers submenu) |
| - CONFIG_WAKEUP_LATENCY_HIST |
| - |
| -* Missed timer latencies |
| - |
| -Missed timer latencies occur when a timer interrupt is serviced later |
| -than it should. This is mainly due to disabled interrupts. To determine |
| -the missed timer latency, the expected and the real execution time of a |
| -timer are compared. If the former precedes the latter, the difference is |
| -entered into the missed timer offsets histogram. If the timer is |
| -responsible to wakeup a sleeping process and the latency is highest so |
| -far among previous wakeup timers, details of the related task are stored |
| -as well (see below). |
| - Configuration item (in the Kernel hacking/Tracers submenu) |
| - CONFIG_MISSED_TIMER_OFFSETS_HIST |
| + CONFIG_WAKEUP_LATENCY |
| |
| |
| * Usage |
| @@ -76,36 +59,30 @@ from shell command line level, or add |
| nodev /sys sysfs defaults 0 0 |
| nodev /sys/kernel/debug debugfs defaults 0 0 |
| |
| -to the file /etc/fstab in order to implicitly mount the debug file |
| -system at every reboot. All latency histogram related files are |
| +to the file /etc/fstab. All latency histogram related files are |
| available in the directory /sys/kernel/debug/tracing/latency_hist. A |
| particular histogram type is enabled by writing non-zero to the related |
| variable in the /sys/kernel/debug/tracing/latency_hist/enable directory. |
| -Select "preemptirqsoff" for histograms of potential sources of |
| -latencies, "wakeup" for histograms of wakeup latencies and |
| -"missed_timer_offsets" for histograms of missed timer offsets, |
| -respectively. |
| +Select "preemptirqsoff" for the histograms of potential sources of |
| +latencies and "wakeup" for histograms of effective latencies. The |
| +histogram data - one per CPU - are available in the files |
| |
| -The histogram data - one per CPU - are available in the files |
| /sys/kernel/debug/tracing/latency_hist/preemptoff/CPUx |
| /sys/kernel/debug/tracing/latency_hist/irqsoff/CPUx |
| /sys/kernel/debug/tracing/latency_hist/preemptirqsoff/CPUx |
| /sys/kernel/debug/tracing/latency_hist/wakeup/CPUx. |
| -/sys/kernel/debug/tracing/latency_hist/wakeup/sharedprio/CPUx. |
| -/sys/kernel/debug/tracing/latency_hist/missed_timer_offsets/CPUx. |
| |
| The histograms are reset by writing non-zero to the file "reset" in a |
| particular latency directory. To reset all latency data, use |
| |
| -#!/bin/bash |
| +#!/bin/sh |
| |
| -TRACINGDIR=/sys/kernel/debug/tracing |
| -HISTDIR=$TRACINGDIR/latency_hist |
| +HISTDIR=/sys/kernel/debug/tracing/latency_hist |
| |
| if test -d $HISTDIR |
| then |
| cd $HISTDIR |
| - for i in `find . | grep /reset$` |
| + for i in */reset |
| do |
| echo 1 >$i |
| done |
| @@ -115,19 +92,19 @@ fi |
| * Data format |
| |
| Latency data are stored with a resolution of one microsecond. The |
| -maximum latency is 10,240 microseconds. Every output line contains the |
| -latency in microseconds in the first row and the number of samples in |
| -the second row. To display only lines with a positive latency count, |
| -use, for example, |
| +maximum latency is 10,240 microseconds. The data are only valid, if the |
| +overflow register is empty. Every output line contains the latency in |
| +microseconds in the first row and the number of samples in the second |
| +row. To display only lines with a positive latency count, use, for |
| +example, |
| |
| grep -v " 0$" /sys/kernel/debug/tracing/latency_hist/preemptoff/CPU0 |
| |
| -#Minimum latency: 0 microseconds |
| -#Average latency: 0 microseconds |
| -#Maximum latency: 25 microseconds |
| +#Minimum latency: 0 microseconds. |
| +#Average latency: 0 microseconds. |
| +#Maximum latency: 25 microseconds. |
| #Total samples: 3104770694 |
| -#There are 0 samples lower than 0 microseconds. |
| -#There are 0 samples greater or equal than 10240 microseconds. |
| +#There are 0 samples greater or equal than 10240 microseconds |
| #usecs samples |
| 0 2984486876 |
| 1 49843506 |
| @@ -156,23 +133,6 @@ grep -v " 0$" /sys/kernel/debug/tracing/latency_hist/preemptoff/CPU0 |
| 25 1 |
| |
| |
| -* Two types of wakeup latency histograms |
| - |
| -Two different algorithms are used to determine the wakeup latency of a |
| -process. One of them only considers processes that exclusively use the |
| -highest priority of the system, the other one records the wakeup latency |
| -of a process even if it shares the highest system latency with other |
| -processes. The former is used to determine the worst-case latency of a |
| -system; if higher than expected, the hardware and or system software |
| -(e.g. the Linux kernel) may need to be debugged and fixed. The latter |
| -reflects the priority design of a given system; if higher than expected, |
| -the system design may need to be re-evaluated - the hardware |
| -manufacturer or the kernel developers must not be blamed for such |
| -latencies. The exclusive-priority wakeup latency histograms are located |
| -in the "wakeup" subdirectory, the shared-priority histograms are located |
| -in the "wakeup/sharedprio" subdirectory. |
| - |
| - |
| * Wakeup latency of a selected process |
| |
| To only collect wakeup latency data of a particular process, write the |
| @@ -183,18 +143,14 @@ PID of the requested process to |
| PIDs are not considered, if this variable is set to 0. |
| |
| |
| -* Details of processes with the highest wakeup or missed timer |
| -latency so far |
| +* Details of the process with the highest wakeup latency so far |
| |
| -Selected data of processes that suffered from the highest wakeup or |
| -missed timer latency that occurred on a particular CPU are available in |
| -the files |
| +Selected data of the process that suffered from the highest wakeup |
| +latency that occurred in a particular CPU are available in the file |
| |
| -/sys/kernel/debug/tracing/latency_hist/wakeup/max_latency-CPUx |
| -/sys/kernel/debug/tracing/latency_hist/wakeup/sharedprio/max_latency-CPUx |
| -/sys/kernel/debug/tracing/latency_hist/missed_timer_offsets/max_latency-CPUx |
| +/sys/kernel/debug/tracing/latency_hist/wakeup/max_latency-CPUx. |
| |
| The format of the data is |
| <PID> <Priority> <Latency> <Command> |
| |
| -These data are also reset when the related histograms are reset. |
| +These data are also reset when the wakeup histogram ist reset. |
| diff --git a/include/trace/events/hist.h b/include/trace/events/hist.h |
| index 2dc4c70..28646db 100644 |
| --- a/include/trace/events/hist.h |
| +++ b/include/trace/events/hist.h |
| @@ -32,27 +32,34 @@ TRACE_EVENT(preemptirqsoff_hist, |
| #endif |
| |
| #ifndef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| -#define trace_hrtimer_interrupt(a,b,c) |
| +#define trace_hrtimer_interrupt(a,b,c,d) |
| #else |
| TRACE_EVENT(hrtimer_interrupt, |
| |
| - TP_PROTO(int cpu, long long offset, struct task_struct *task), |
| + TP_PROTO(int cpu, long long offset, struct task_struct *curr, struct task_struct *task), |
| |
| - TP_ARGS(cpu, offset, task), |
| + TP_ARGS(cpu, offset, curr, task), |
| |
| TP_STRUCT__entry( |
| - __array(char, comm, TASK_COMM_LEN) |
| __field(int, cpu ) |
| __field(long long, offset ) |
| + __array(char, ccomm, TASK_COMM_LEN) |
| + __field(int, cprio ) |
| + __array(char, tcomm, TASK_COMM_LEN) |
| + __field(int, tprio ) |
| ), |
| |
| TP_fast_assign( |
| - strncpy(__entry->comm, task != NULL ? task->comm : "", TASK_COMM_LEN); |
| __entry->cpu = cpu; |
| __entry->offset = offset; |
| + memcpy(__entry->ccomm, curr->comm, TASK_COMM_LEN); |
| + __entry->cprio = curr->prio; |
| + memcpy(__entry->tcomm, task != NULL ? task->comm : "<none>", task != NULL ? TASK_COMM_LEN : 7); |
| + __entry->tprio = task != NULL ? task->prio : -1; |
| ), |
| |
| - TP_printk("cpu=%d offset=%lld thread=%s", __entry->cpu, __entry->offset, __entry->comm) |
| + TP_printk("cpu=%d offset=%lld curr=%s[%d] thread=%s[%d]", |
| + __entry->cpu, __entry->offset, __entry->ccomm, __entry->cprio, __entry->tcomm, __entry->tprio) |
| ); |
| #endif |
| |
| diff --git a/kernel/trace/latency_hist.c b/kernel/trace/latency_hist.c |
| index 83d8d2f..8300929 100644 |
| --- a/kernel/trace/latency_hist.c |
| +++ b/kernel/trace/latency_hist.c |
| @@ -93,9 +93,9 @@ static struct enable_data preemptirqsoff_enabled_data = { |
| defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| struct maxlatproc_data { |
| char comm[FIELD_SIZEOF(struct task_struct, comm)]; |
| - unsigned int pid; |
| - unsigned int prio; |
| - unsigned long latency; |
| + int pid; |
| + int prio; |
| + long latency; |
| }; |
| #endif |
| |
| @@ -108,28 +108,30 @@ static notrace void probe_wakeup_latency_hist_start(struct rq *rq, |
| struct task_struct *p, int success); |
| static notrace void probe_wakeup_latency_hist_stop(struct rq *rq, |
| struct task_struct *prev, struct task_struct *next); |
| +static notrace void probe_sched_migrate_task(struct task_struct *task, |
| + int cpu); |
| static struct enable_data wakeup_latency_enabled_data = { |
| .latency_type = WAKEUP_LATENCY, |
| .enabled = 0, |
| }; |
| static DEFINE_PER_CPU(struct maxlatproc_data, wakeup_maxlatproc); |
| static DEFINE_PER_CPU(struct maxlatproc_data, wakeup_maxlatproc_sharedprio); |
| -static struct task_struct *wakeup_task; |
| -static int wakeup_sharedprio; |
| -static int wakeup_pid; |
| +static DEFINE_PER_CPU(struct task_struct *, wakeup_task); |
| +static DEFINE_PER_CPU(int, wakeup_sharedprio); |
| +static unsigned long wakeup_pid; |
| #endif |
| |
| #ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| static DEFINE_PER_CPU(struct hist_data, missed_timer_offsets); |
| static char *missed_timer_offsets_dir = "missed_timer_offsets"; |
| static notrace void probe_hrtimer_interrupt(int cpu, |
| - long long offset, struct task_struct *task); |
| + long long offset, struct task_struct *curr, struct task_struct *task); |
| static struct enable_data missed_timer_offsets_enabled_data = { |
| .latency_type = MISSED_TIMER_OFFSETS, |
| .enabled = 0, |
| }; |
| -static DEFINE_PER_CPU(struct maxlatproc_data, |
| - missed_timer_offsets_maxlatproc); |
| +static DEFINE_PER_CPU(struct maxlatproc_data, missed_timer_offsets_maxlatproc); |
| +static unsigned long missed_timer_offsets_pid; |
| #endif |
| |
| void notrace latency_hist(int latency_type, int cpu, unsigned long latency, |
| @@ -196,11 +198,12 @@ void notrace latency_hist(int latency_type, int cpu, unsigned long latency, |
| |
| if (latency < my_hist->min_lat) |
| my_hist->min_lat = latency; |
| - else if (latency > my_hist->max_lat) { |
| -#if defined (CONFIG_WAKEUP_LATENCY_HIST) || \ |
| + if (latency > my_hist->max_lat) { |
| +#if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| if (latency_type == WAKEUP_LATENCY || |
| - latency_type == WAKEUP_LATENCY_SHAREDPRIO) { |
| + latency_type == WAKEUP_LATENCY_SHAREDPRIO || |
| + latency_type == MISSED_TIMER_OFFSETS) { |
| strncpy(mp->comm, p->comm, sizeof(mp->comm)); |
| mp->pid = task_pid_nr(p); |
| mp->prio = p->prio; |
| @@ -209,18 +212,8 @@ void notrace latency_hist(int latency_type, int cpu, unsigned long latency, |
| #endif |
| my_hist->max_lat = latency; |
| } |
| -#ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| - if (latency_type == MISSED_TIMER_OFFSETS && p != NULL && |
| - latency > mp->latency) { |
| - strncpy(mp->comm, p->comm, sizeof(mp->comm)); |
| - mp->pid = task_pid_nr(p); |
| - mp->prio = p->prio; |
| - mp->latency = latency; |
| - } |
| -#endif |
| my_hist->total_samples++; |
| my_hist->accumulate_lat += latency; |
| - return; |
| } |
| |
| static void *l_start(struct seq_file *m, loff_t *pos) |
| @@ -245,7 +238,7 @@ static void *l_start(struct seq_file *m, loff_t *pos) |
| (long) my_hist->min_lat - my_hist->offset); |
| snprintf(avgstr, sizeof(avgstr), "%ld", |
| (long) avg - my_hist->offset); |
| - snprintf(maxstr, sizeof(minstr), "%ld", |
| + snprintf(maxstr, sizeof(maxstr), "%ld", |
| (long) my_hist->max_lat - my_hist->offset); |
| } else { |
| strcpy(minstr, "<undef>"); |
| @@ -299,14 +292,8 @@ static int l_show(struct seq_file *m, void *p) |
| { |
| int index = *(loff_t *) p; |
| struct hist_data *my_hist = m->private; |
| - char *fmt; |
| - |
| - if (my_hist->offset) |
| - fmt = "%6d\t%16llu\n"; |
| - else |
| - fmt = "%5d\t%16llu\n"; |
| |
| - seq_printf(m, fmt, index - my_hist->offset, |
| + seq_printf(m, "%6ld\t%16llu\n", index - my_hist->offset, |
| my_hist->hist_array[index]); |
| return 0; |
| } |
| @@ -354,71 +341,61 @@ static void hist_reset(struct hist_data *hist) |
| |
| static ssize_t |
| latency_hist_reset(struct file *file, const char __user *a, |
| - size_t size, loff_t *off) |
| + size_t size, loff_t *off) |
| { |
| int cpu; |
| - struct hist_data *hist; |
| + struct hist_data *hist = NULL; |
| #if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| struct maxlatproc_data *mp = NULL; |
| #endif |
| - int latency_type = (int) file->private_data; |
| + off_t latency_type = (off_t) file->private_data; |
| |
| - switch (latency_type) { |
| + for_each_online_cpu(cpu) { |
| + |
| + switch (latency_type) { |
| #ifdef CONFIG_PREEMPT_OFF_HIST |
| - case PREEMPTOFF_LATENCY: |
| - for_each_online_cpu(cpu) { |
| + case PREEMPTOFF_LATENCY: |
| hist = &per_cpu(preemptoff_hist, cpu); |
| - hist_reset(hist); |
| - } |
| - break; |
| + break; |
| #endif |
| #ifdef CONFIG_INTERRUPT_OFF_HIST |
| - case IRQSOFF_LATENCY: |
| - for_each_online_cpu(cpu) { |
| + case IRQSOFF_LATENCY: |
| hist = &per_cpu(irqsoff_hist, cpu); |
| - hist_reset(hist); |
| - } |
| - break; |
| + break; |
| #endif |
| #if defined(CONFIG_INTERRUPT_OFF_HIST) && defined(CONFIG_PREEMPT_OFF_HIST) |
| - case PREEMPTIRQSOFF_LATENCY: |
| - for_each_online_cpu(cpu) { |
| + case PREEMPTIRQSOFF_LATENCY: |
| hist = &per_cpu(preemptirqsoff_hist, cpu); |
| - hist_reset(hist); |
| - } |
| - break; |
| + break; |
| #endif |
| #ifdef CONFIG_WAKEUP_LATENCY_HIST |
| - case WAKEUP_LATENCY: |
| - for_each_online_cpu(cpu) { |
| + case WAKEUP_LATENCY: |
| hist = &per_cpu(wakeup_latency_hist, cpu); |
| - hist_reset(hist); |
| mp = &per_cpu(wakeup_maxlatproc, cpu); |
| - mp->comm[0] = '\0'; |
| - mp->prio = mp->pid = mp->latency = 0; |
| - } |
| - break; |
| - case WAKEUP_LATENCY_SHAREDPRIO: |
| - for_each_online_cpu(cpu) { |
| + break; |
| + case WAKEUP_LATENCY_SHAREDPRIO: |
| hist = &per_cpu(wakeup_latency_hist_sharedprio, cpu); |
| - hist_reset(hist); |
| mp = &per_cpu(wakeup_maxlatproc_sharedprio, cpu); |
| - mp->comm[0] = '\0'; |
| - mp->prio = mp->pid = mp->latency = 0; |
| - } |
| - break; |
| + break; |
| #endif |
| #ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| - case MISSED_TIMER_OFFSETS: |
| - for_each_online_cpu(cpu) { |
| + case MISSED_TIMER_OFFSETS: |
| hist = &per_cpu(missed_timer_offsets, cpu); |
| - hist_reset(hist); |
| mp = &per_cpu(missed_timer_offsets_maxlatproc, cpu); |
| + break; |
| +#endif |
| + } |
| + |
| + hist_reset(hist); |
| +#if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| + defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| + if (latency_type == WAKEUP_LATENCY || |
| + latency_type == WAKEUP_LATENCY_SHAREDPRIO || |
| + latency_type == MISSED_TIMER_OFFSETS) { |
| mp->comm[0] = '\0'; |
| - mp->prio = mp->pid = mp->latency = 0; |
| + mp->prio = mp->pid = mp->latency = -1; |
| } |
| - break; |
| #endif |
| } |
| |
| @@ -427,22 +404,22 @@ latency_hist_reset(struct file *file, const char __user *a, |
| |
| #ifdef CONFIG_WAKEUP_LATENCY_HIST |
| static ssize_t |
| -latency_hist_show_pid(struct file *filp, char __user *ubuf, |
| - size_t cnt, loff_t *ppos) |
| +show_pid(struct file *file, char __user *ubuf, size_t cnt, loff_t *ppos) |
| { |
| char buf[64]; |
| int r; |
| + unsigned long *this_pid = file->private_data; |
| |
| - r = snprintf(buf, sizeof(buf), "%u\n", wakeup_pid); |
| + r = snprintf(buf, sizeof(buf), "%lu\n", *this_pid); |
| return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
| } |
| |
| -static ssize_t |
| -latency_hist_pid(struct file *filp, const char __user *ubuf, |
| - size_t cnt, loff_t *ppos) |
| +static ssize_t do_pid(struct file *file, const char __user *ubuf, |
| + size_t cnt, loff_t *ppos) |
| { |
| char buf[64]; |
| unsigned long pid; |
| + unsigned long *this_pid = file->private_data; |
| |
| if (cnt >= sizeof(buf)) |
| return -EINVAL; |
| @@ -455,7 +432,8 @@ latency_hist_pid(struct file *filp, const char __user *ubuf, |
| if (strict_strtoul(buf, 10, &pid)) |
| return(-EINVAL); |
| |
| - wakeup_pid = pid; |
| + *this_pid = pid; |
| + |
| return cnt; |
| } |
| #endif |
| @@ -463,27 +441,23 @@ latency_hist_pid(struct file *filp, const char __user *ubuf, |
| #if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| static ssize_t |
| -latency_hist_show_maxlatproc(struct file *filp, char __user *ubuf, |
| - size_t cnt, loff_t *ppos) |
| +show_maxlatproc(struct file *file, char __user *ubuf, size_t cnt, loff_t *ppos) |
| { |
| char buf[1024]; |
| int r; |
| - struct maxlatproc_data *mp = (struct maxlatproc_data *) |
| - filp->private_data; |
| + struct maxlatproc_data *mp = file->private_data; |
| |
| - r = snprintf(buf, sizeof(buf), "%5d %3d %ld %s\n", |
| - mp->pid, mp->prio, mp->latency, mp->comm); |
| + r = snprintf(buf, sizeof(buf), "%d %d %ld %s\n", |
| + mp->pid, MAX_RT_PRIO-1 - mp->prio, mp->latency, mp->comm); |
| return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
| } |
| - |
| #endif |
| |
| static ssize_t |
| -latency_hist_show_enable(struct file *filp, char __user *ubuf, |
| - size_t cnt, loff_t *ppos) |
| +show_enable(struct file *file, char __user *ubuf, size_t cnt, loff_t *ppos) |
| { |
| char buf[64]; |
| - struct enable_data *ed = (struct enable_data *) filp->private_data; |
| + struct enable_data *ed = file->private_data; |
| int r; |
| |
| r = snprintf(buf, sizeof(buf), "%d\n", ed->enabled); |
| @@ -491,12 +465,11 @@ latency_hist_show_enable(struct file *filp, char __user *ubuf, |
| } |
| |
| static ssize_t |
| -latency_hist_enable(struct file *filp, const char __user *ubuf, |
| - size_t cnt, loff_t *ppos) |
| +do_enable(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) |
| { |
| char buf[64]; |
| long enable; |
| - struct enable_data *ed = (struct enable_data *) filp->private_data; |
| + struct enable_data *ed = file->private_data; |
| |
| if (cnt >= sizeof(buf)) |
| return -EINVAL; |
| @@ -556,6 +529,20 @@ latency_hist_enable(struct file *filp, const char __user *ubuf, |
| "to trace_sched_switch\n"); |
| unregister_trace_sched_wakeup( |
| probe_wakeup_latency_hist_start); |
| + unregister_trace_sched_wakeup_new( |
| + probe_wakeup_latency_hist_start); |
| + return ret; |
| + } |
| + ret = register_trace_sched_migrate_task( |
| + probe_sched_migrate_task); |
| + if (ret) { |
| + pr_info("wakeup trace: Couldn't assign " |
| + "probe_sched_migrate_task " |
| + "to trace_sched_migrate_task\n"); |
| + unregister_trace_sched_wakeup( |
| + probe_wakeup_latency_hist_start); |
| + unregister_trace_sched_wakeup_new( |
| + probe_wakeup_latency_hist_start); |
| unregister_trace_sched_switch( |
| probe_wakeup_latency_hist_stop); |
| return ret; |
| @@ -603,16 +590,25 @@ latency_hist_enable(struct file *filp, const char __user *ubuf, |
| } |
| break; |
| #endif |
| -#ifdef CONFIG_WAKEUP_LATEHCY_HIST |
| +#ifdef CONFIG_WAKEUP_LATENCY_HIST |
| case WAKEUP_LATENCY: |
| - unregister_trace_sched_wakeup( |
| - probe_wakeup_latency_hist_start); |
| - unregister_trace_sched_wakeup_new( |
| - probe_wakeup_latency_hist_start); |
| - unregister_trace_sched_switch( |
| - probe_wakeup_latency_hist_stop); |
| - wakeup_task = NULL; |
| - wakeup_sharedprio = 0; |
| + { |
| + int cpu; |
| + |
| + unregister_trace_sched_wakeup( |
| + probe_wakeup_latency_hist_start); |
| + unregister_trace_sched_wakeup_new( |
| + probe_wakeup_latency_hist_start); |
| + unregister_trace_sched_switch( |
| + probe_wakeup_latency_hist_stop); |
| + unregister_trace_sched_migrate_task( |
| + probe_sched_migrate_task); |
| + |
| + for_each_online_cpu(cpu) { |
| + per_cpu(wakeup_task, cpu) = NULL; |
| + per_cpu(wakeup_sharedprio, cpu) = 0; |
| + } |
| + } |
| break; |
| #endif |
| #ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| @@ -634,30 +630,28 @@ static const struct file_operations latency_hist_reset_fops = { |
| .write = latency_hist_reset, |
| }; |
| |
| -static const struct file_operations latency_hist_enable_fops = { |
| +static const struct file_operations enable_fops = { |
| .open = tracing_open_generic, |
| - .read = latency_hist_show_enable, |
| - .write = latency_hist_enable, |
| + .read = show_enable, |
| + .write = do_enable, |
| }; |
| |
| -#ifdef CONFIG_WAKEUP_LATENCY_HIST |
| -static const struct file_operations latency_hist_pid_fops = { |
| +#if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| + defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| +static const struct file_operations pid_fops = { |
| .open = tracing_open_generic, |
| - .read = latency_hist_show_pid, |
| - .write = latency_hist_pid, |
| + .read = show_pid, |
| + .write = do_pid, |
| }; |
| -#endif |
| |
| -#if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| - defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| -static const struct file_operations latency_hist_maxlatproc_fops = { |
| +static const struct file_operations maxlatproc_fops = { |
| .open = tracing_open_generic, |
| - .read = latency_hist_show_maxlatproc, |
| + .read = show_maxlatproc, |
| }; |
| #endif |
| |
| #if defined(CONFIG_INTERRUPT_OFF_HIST) || defined(CONFIG_PREEMPT_OFF_HIST) |
| -notrace void probe_preemptirqsoff_hist(int reason, int starthist) |
| +static notrace void probe_preemptirqsoff_hist(int reason, int starthist) |
| { |
| int cpu = raw_smp_processor_id(); |
| int time_set = 0; |
| @@ -760,85 +754,133 @@ notrace void probe_preemptirqsoff_hist(int reason, int starthist) |
| |
| #ifdef CONFIG_WAKEUP_LATENCY_HIST |
| static DEFINE_RAW_SPINLOCK(wakeup_lock); |
| +static notrace void probe_sched_migrate_task(struct task_struct *task, int cpu) |
| +{ |
| + int old_cpu = task_cpu(task); |
| + |
| + if (cpu != old_cpu) { |
| + unsigned long flags; |
| + struct task_struct *cpu_wakeup_task; |
| |
| -notrace void probe_wakeup_latency_hist_start(struct rq *rq, |
| + raw_spin_lock_irqsave(&wakeup_lock, flags); |
| + |
| + cpu_wakeup_task = per_cpu(wakeup_task, old_cpu); |
| + if (task == cpu_wakeup_task) { |
| + put_task_struct(cpu_wakeup_task); |
| + per_cpu(wakeup_task, old_cpu) = NULL; |
| + cpu_wakeup_task = per_cpu(wakeup_task, cpu) = task; |
| + get_task_struct(cpu_wakeup_task); |
| + } |
| + |
| + raw_spin_unlock_irqrestore(&wakeup_lock, flags); |
| + } |
| +} |
| + |
| +static notrace void probe_wakeup_latency_hist_start(struct rq *rq, |
| struct task_struct *p, int success) |
| { |
| unsigned long flags; |
| struct task_struct *curr = rq_curr(rq); |
| + int cpu = task_cpu(p); |
| + struct task_struct *cpu_wakeup_task; |
| + |
| + raw_spin_lock_irqsave(&wakeup_lock, flags); |
| + |
| + cpu_wakeup_task = per_cpu(wakeup_task, cpu); |
| |
| if (wakeup_pid) { |
| - if ((wakeup_task && p->prio == wakeup_task->prio) || |
| + if ((cpu_wakeup_task && p->prio == cpu_wakeup_task->prio) || |
| p->prio == curr->prio) |
| - wakeup_sharedprio = 1; |
| + per_cpu(wakeup_sharedprio, cpu) = 1; |
| if (likely(wakeup_pid != task_pid_nr(p))) |
| - return; |
| + goto out; |
| } else { |
| if (likely(!rt_task(p)) || |
| - (wakeup_task && p->prio > wakeup_task->prio) || |
| + (cpu_wakeup_task && p->prio > cpu_wakeup_task->prio) || |
| p->prio > curr->prio) |
| - return; |
| - if ((wakeup_task && p->prio == wakeup_task->prio) || |
| + goto out; |
| + if ((cpu_wakeup_task && p->prio == cpu_wakeup_task->prio) || |
| p->prio == curr->prio) |
| - wakeup_sharedprio = 1; |
| + per_cpu(wakeup_sharedprio, cpu) = 1; |
| } |
| |
| - raw_spin_lock_irqsave(&wakeup_lock, flags); |
| - if (wakeup_task) |
| - put_task_struct(wakeup_task); |
| - get_task_struct(p); |
| - wakeup_task = p; |
| - wakeup_task->preempt_timestamp_hist = |
| - ftrace_now(raw_smp_processor_id()); |
| + if (cpu_wakeup_task) |
| + put_task_struct(cpu_wakeup_task); |
| + cpu_wakeup_task = per_cpu(wakeup_task, cpu) = p; |
| + get_task_struct(cpu_wakeup_task); |
| + cpu_wakeup_task->preempt_timestamp_hist = |
| + ftrace_now(raw_smp_processor_id()); |
| +out: |
| raw_spin_unlock_irqrestore(&wakeup_lock, flags); |
| } |
| |
| -notrace void probe_wakeup_latency_hist_stop(struct rq *rq, |
| +static notrace void probe_wakeup_latency_hist_stop(struct rq *rq, |
| struct task_struct *prev, struct task_struct *next) |
| { |
| unsigned long flags; |
| - int cpu; |
| + int cpu = task_cpu(next); |
| unsigned long latency; |
| cycle_t stop; |
| + struct task_struct *cpu_wakeup_task; |
| |
| - if (next != wakeup_task) |
| - return; |
| + raw_spin_lock_irqsave(&wakeup_lock, flags); |
| |
| - cpu = raw_smp_processor_id(); |
| - stop = ftrace_now(cpu); |
| + cpu_wakeup_task = per_cpu(wakeup_task, cpu); |
| |
| - raw_spin_lock_irqsave(&wakeup_lock, flags); |
| + if (cpu_wakeup_task == NULL) |
| + goto out; |
| + |
| + /* Already running? */ |
| + if (unlikely(current == cpu_wakeup_task)) |
| + goto out_reset; |
| + |
| + if (next != cpu_wakeup_task) { |
| + if (next->prio < cpu_wakeup_task->prio) |
| + goto out_reset; |
| + |
| + if (next->prio == cpu_wakeup_task->prio) |
| + per_cpu(wakeup_sharedprio, cpu) = 1; |
| |
| - latency = nsecs_to_usecs(stop - next->preempt_timestamp_hist); |
| - if (next != wakeup_task) { |
| - if (wakeup_task && next->prio == wakeup_task->prio) |
| - latency_hist(WAKEUP_LATENCY_SHAREDPRIO, cpu, latency, |
| - next); |
| goto out; |
| } |
| |
| - if (wakeup_sharedprio) { |
| + /* |
| + * The task we are waiting for is about to be switched to. |
| + * Calculate latency and store it in histogram. |
| + */ |
| + stop = ftrace_now(raw_smp_processor_id()); |
| + |
| + latency = nsecs_to_usecs(stop - next->preempt_timestamp_hist); |
| + |
| + if (per_cpu(wakeup_sharedprio, cpu)) { |
| latency_hist(WAKEUP_LATENCY_SHAREDPRIO, cpu, latency, next); |
| - wakeup_sharedprio = 0; |
| + per_cpu(wakeup_sharedprio, cpu) = 0; |
| } else |
| latency_hist(WAKEUP_LATENCY, cpu, latency, next); |
| |
| - put_task_struct(wakeup_task); |
| - wakeup_task = NULL; |
| +out_reset: |
| + put_task_struct(cpu_wakeup_task); |
| + per_cpu(wakeup_task, cpu) = NULL; |
| out: |
| raw_spin_unlock_irqrestore(&wakeup_lock, flags); |
| } |
| #endif |
| |
| #ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| -notrace void probe_hrtimer_interrupt(int cpu, long long latency_ns, |
| - struct task_struct *task) |
| +static notrace void probe_hrtimer_interrupt(int cpu, long long latency_ns, |
| + struct task_struct *curr, struct task_struct *task) |
| { |
| - if (latency_ns <= 0) { |
| + if (latency_ns <= 0 && task != NULL && rt_task(task) && |
| + task->prio < curr->prio) { |
| unsigned long latency; |
| |
| - latency = (unsigned long) div_s64(-latency_ns, 1000); |
| + if (missed_timer_offsets_pid) { |
| + if (likely(missed_timer_offsets_pid != |
| + task_pid_nr(task))) |
| + return; |
| + } |
| |
| + latency = (unsigned long) div_s64(-latency_ns, 1000); |
| latency_hist(MISSED_TIMER_OFFSETS, cpu, latency, task); |
| } |
| } |
| @@ -852,7 +894,7 @@ static __init int latency_hist_init(void) |
| struct dentry *dentry_sharedprio; |
| #endif |
| struct dentry *entry; |
| - struct dentry *latency_hist_enable_root; |
| + struct dentry *enable_root; |
| int i = 0; |
| struct hist_data *my_hist; |
| char name[64]; |
| @@ -860,15 +902,12 @@ static __init int latency_hist_init(void) |
| #if defined(CONFIG_WAKEUP_LATENCY_HIST) || \ |
| defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) |
| char *cpufmt_maxlatproc = "max_latency-CPU%d"; |
| + struct maxlatproc_data *mp = NULL; |
| #endif |
| |
| dentry = tracing_init_dentry(); |
| - |
| - latency_hist_root = |
| - debugfs_create_dir(latency_hist_dir_root, dentry); |
| - |
| - latency_hist_enable_root = |
| - debugfs_create_dir("enable", latency_hist_root); |
| + latency_hist_root = debugfs_create_dir(latency_hist_dir_root, dentry); |
| + enable_root = debugfs_create_dir("enable", latency_hist_root); |
| |
| #ifdef CONFIG_INTERRUPT_OFF_HIST |
| dentry = debugfs_create_dir(irqsoff_hist_dir, latency_hist_root); |
| @@ -916,8 +955,8 @@ static __init int latency_hist_init(void) |
| |
| #if defined(CONFIG_INTERRUPT_OFF_HIST) || defined(CONFIG_PREEMPT_OFF_HIST) |
| entry = debugfs_create_file("preemptirqsoff", 0644, |
| - latency_hist_enable_root, (void *)&preemptirqsoff_enabled_data, |
| - &latency_hist_enable_fops); |
| + enable_root, (void *)&preemptirqsoff_enabled_data, |
| + &enable_fops); |
| #endif |
| |
| #ifdef CONFIG_WAKEUP_LATENCY_HIST |
| @@ -927,6 +966,7 @@ static __init int latency_hist_init(void) |
| wakeup_latency_hist_dir_sharedprio, dentry); |
| for_each_possible_cpu(i) { |
| sprintf(name, cpufmt, i); |
| + |
| entry = debugfs_create_file(name, 0444, dentry, |
| &per_cpu(wakeup_latency_hist, i), |
| &latency_hist_fops); |
| @@ -934,7 +974,6 @@ static __init int latency_hist_init(void) |
| atomic_set(&my_hist->hist_mode, 1); |
| my_hist->min_lat = 0xFFFFFFFFUL; |
| |
| - sprintf(name, cpufmt, i); |
| entry = debugfs_create_file(name, 0444, dentry_sharedprio, |
| &per_cpu(wakeup_latency_hist_sharedprio, i), |
| &latency_hist_fops); |
| @@ -943,24 +982,26 @@ static __init int latency_hist_init(void) |
| my_hist->min_lat = 0xFFFFFFFFUL; |
| |
| sprintf(name, cpufmt_maxlatproc, i); |
| - entry = debugfs_create_file(name, 0444, dentry, |
| - &per_cpu(wakeup_maxlatproc, i), |
| - &latency_hist_maxlatproc_fops); |
| |
| - sprintf(name, cpufmt_maxlatproc, i); |
| - entry = debugfs_create_file(name, 0444, dentry_sharedprio, |
| - &per_cpu(wakeup_maxlatproc_sharedprio, i), |
| - &latency_hist_maxlatproc_fops); |
| + mp = &per_cpu(wakeup_maxlatproc, i); |
| + entry = debugfs_create_file(name, 0444, dentry, mp, |
| + &maxlatproc_fops); |
| + mp->prio = mp->pid = mp->latency = -1; |
| + |
| + mp = &per_cpu(wakeup_maxlatproc_sharedprio, i); |
| + entry = debugfs_create_file(name, 0444, dentry_sharedprio, mp, |
| + &maxlatproc_fops); |
| + mp->prio = mp->pid = mp->latency = -1; |
| } |
| entry = debugfs_create_file("pid", 0644, dentry, |
| - (void *)&wakeup_pid, &latency_hist_pid_fops); |
| + (void *)&wakeup_pid, &pid_fops); |
| entry = debugfs_create_file("reset", 0644, dentry, |
| (void *)WAKEUP_LATENCY, &latency_hist_reset_fops); |
| entry = debugfs_create_file("reset", 0644, dentry_sharedprio, |
| (void *)WAKEUP_LATENCY_SHAREDPRIO, &latency_hist_reset_fops); |
| entry = debugfs_create_file("wakeup", 0644, |
| - latency_hist_enable_root, (void *)&wakeup_latency_enabled_data, |
| - &latency_hist_enable_fops); |
| + enable_root, (void *)&wakeup_latency_enabled_data, |
| + &enable_fops); |
| #endif |
| |
| #ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST |
| @@ -975,16 +1016,18 @@ static __init int latency_hist_init(void) |
| my_hist->min_lat = 0xFFFFFFFFUL; |
| |
| sprintf(name, cpufmt_maxlatproc, i); |
| - entry = debugfs_create_file(name, 0444, dentry, |
| - &per_cpu(missed_timer_offsets_maxlatproc, i), |
| - &latency_hist_maxlatproc_fops); |
| + mp = &per_cpu(missed_timer_offsets_maxlatproc, i); |
| + entry = debugfs_create_file(name, 0444, dentry, mp, |
| + &maxlatproc_fops); |
| + mp->prio = mp->pid = mp->latency = -1; |
| } |
| + entry = debugfs_create_file("pid", 0644, dentry, |
| + (void *)&missed_timer_offsets_pid, &pid_fops); |
| entry = debugfs_create_file("reset", 0644, dentry, |
| (void *)MISSED_TIMER_OFFSETS, &latency_hist_reset_fops); |
| entry = debugfs_create_file("missed_timer_offsets", 0644, |
| - latency_hist_enable_root, |
| - (void *)&missed_timer_offsets_enabled_data, |
| - &latency_hist_enable_fops); |
| + enable_root, (void *)&missed_timer_offsets_enabled_data, |
| + &enable_fops); |
| #endif |
| return 0; |
| } |
| diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c |
| index 855c81c..12dff6c 100644 |
| --- a/kernel/trace/ring_buffer.c |
| +++ b/kernel/trace/ring_buffer.c |
| @@ -1200,11 +1200,12 @@ static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer); |
| static void |
| rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) |
| { |
| - struct buffer_page *bpage; |
| + struct buffer_page *bpage, *tmp; |
| struct list_head *p; |
| + LIST_HEAD(tofree); |
| unsigned i; |
| |
| - spin_lock_irq(&cpu_buffer->reader_lock); |
| + raw_spin_lock_irq(&cpu_buffer->reader_lock); |
| rb_head_page_deactivate(cpu_buffer); |
| |
| for (i = 0; i < nr_pages; i++) { |
| @@ -1212,8 +1213,8 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) |
| goto out; |
| p = cpu_buffer->pages->next; |
| bpage = list_entry(p, struct buffer_page, list); |
| - list_del_init(&bpage->list); |
| - free_buffer_page(bpage); |
| + list_del(&bpage->list); |
| + list_add(&bpage->list, &tofree); |
| } |
| if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages))) |
| goto out; |
| @@ -1222,7 +1223,13 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) |
| rb_check_pages(cpu_buffer); |
| |
| out: |
| - spin_unlock_irq(&cpu_buffer->reader_lock); |
| + raw_spin_unlock_irq(&cpu_buffer->reader_lock); |
| + |
| + list_for_each_entry_safe(bpage, tmp, &tofree, list) { |
| + list_del_init(&bpage->list); |
| + free_buffer_page(bpage); |
| + } |
| + |
| } |
| |
| static void |
| @@ -1233,7 +1240,7 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer, |
| struct list_head *p; |
| unsigned i; |
| |
| - spin_lock_irq(&cpu_buffer->reader_lock); |
| + raw_spin_lock_irq(&cpu_buffer->reader_lock); |
| rb_head_page_deactivate(cpu_buffer); |
| |
| for (i = 0; i < nr_pages; i++) { |
| @@ -1248,7 +1255,7 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer, |
| rb_check_pages(cpu_buffer); |
| |
| out: |
| - spin_unlock_irq(&cpu_buffer->reader_lock); |
| + raw_spin_unlock_irq(&cpu_buffer->reader_lock); |
| } |
| |
| /** |
| -- |
| 1.7.1.1 |
| |