PM: trace events for suspend/resume
Subsystems (7)
PATCH v3 1/1 PM: trace events for suspend/resume
Adds trace events that give finer resolution into suspend/resume. These events are graphed in the timelines generated by the analyze_suspend.py script. They represent large areas of time consumed that are typical to suspend and resume.
The event is triggered by calling the function "trace_suspend_resume" with three arguments: a string (the name of the event to be displayed in the timeline), an integer (case specific number, such as the power state or cpu number), and a boolean (where true is used to denote the start of the timeline event, and false to denote the end).
The suspend_resume trace event reproduces the data that the machine_suspend trace event did, so the latter has been removed.
----
drivers/acpi/sleep.c | 3 +++ drivers/base/power/main.c | 16 ++++++++++++++++ drivers/base/syscore.c | 5 +++++ include/trace/events/power.h | 42 +++++++++++++++++++++++++----------------- kernel/cpu.c | 5 +++++ kernel/power/hibernate.c | 3 +++ kernel/power/process.c | 3 +++ kernel/power/suspend.c | 14 ++++++++++++-- 8 files changed, 72 insertions(+), 19 deletions(-)
v3: June 6, 2014
- changed all string actions to use tracepoint_string so as to minimize the impact on the ring buffer
- removed the save/restore nvs memory events, using acpi_suspend/resume instead
- altered machine_suspend to encompass the lowest level call to kernel suspend for standby, freeze, mem, and disk
- updated the TP_PROTO for staic const char *s
v2: May 30, 2014
- changed the suspend_resume prototype to include an integer value, this is so that it can reproduce the machine_suspend calls as well as provide cpu number info without code modifications
- kernel/cpu.c calls no longer add sprintf's to the code, it's all contained in the tracepoint prototype
- removed the machine_suspend trace event prototype
- removed the suspend_resume/acpi_os_sleep trace event per Raphael's advice
- added trace points for all dpm calls in main.c
- this patch now provides all data for analyze_suspend except the initcalls
v1: May 19, 2014
- first submission
drivers/acpi/sleep.c +3 -0
@@ -19,6 +19,7 @@#include <linux/acpi.h> #include <linux/module.h> #include <asm/io.h> +#include <trace/events/power.h> #include "internal.h" #include "sleep.h"
@@ -500,6 +501,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)ACPI_FLUSH_CPU_CACHE (); +trace_suspend_resume (TPS ("acpi_suspend" ), acpi_state, true);switch (acpi_state) {case ACPI_STATE_S1 :barrier ();
@@ -515,6 +517,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)pr_info (PREFIX "Low-level resume complete\n" );break ; } +trace_suspend_resume (TPS ("acpi_suspend" ), acpi_state, false);/* This violates the spec but is required for bug compatibility. */ acpi_write_bit_register (ACPI_BITREG_SCI_ENABLE ,1 );
drivers/base/power/main.c +16 -0
@@ -545,6 +545,7 @@ static void dpm_resume_noirq(pm_message_t state)struct device *dev;ktime_t starttime =ktime_get (); +trace_suspend_resume (TPS ("dpm_resume_noirq" ), state.event, true);mutex_lock (&dpm_list_mtx); pm_transition = state;
@@ -587,6 +588,7 @@ static void dpm_resume_noirq(pm_message_t state)dpm_show_time (starttime, state,"noirq" );resume_device_irqs ();cpuidle_resume (); +trace_suspend_resume (TPS ("dpm_resume_noirq" ), state.event, false); }/**
@@ -664,6 +666,7 @@ static void dpm_resume_early(pm_message_t state)struct device *dev;ktime_t starttime =ktime_get (); +trace_suspend_resume (TPS ("dpm_resume_early" ), state.event, true);mutex_lock (&dpm_list_mtx); pm_transition = state;
@@ -703,6 +706,7 @@ static void dpm_resume_early(pm_message_t state)mutex_unlock (&dpm_list_mtx);async_synchronize_full ();dpm_show_time (starttime, state,"early" ); +trace_suspend_resume (TPS ("dpm_resume_early" ), state.event, false); }/**
@@ -828,6 +832,7 @@ void dpm_resume(pm_message_t state)struct device *dev;ktime_t starttime =ktime_get (); +trace_suspend_resume (TPS ("dpm_resume" ), state.event, true);might_sleep ();mutex_lock (&dpm_list_mtx);
@@ -869,6 +874,7 @@ void dpm_resume(pm_message_t state)dpm_show_time (starttime, state,NULL );cpufreq_resume (); +trace_suspend_resume (TPS ("dpm_resume" ), state.event, false); }/**
@@ -926,6 +932,7 @@ void dpm_complete(pm_message_t state) {struct list_head list; +trace_suspend_resume (TPS ("dpm_complete" ), state.event, true);might_sleep ();INIT_LIST_HEAD (&list);
@@ -945,6 +952,7 @@ void dpm_complete(pm_message_t state) }list_splice (&list, &dpm_list);mutex_unlock (&dpm_list_mtx); +trace_suspend_resume (TPS ("dpm_complete" ), state.event, false); }/**
@@ -1080,6 +1088,7 @@ static int dpm_suspend_noirq(pm_message_t state)ktime_t starttime =ktime_get ();int error =0 ; +trace_suspend_resume (TPS ("dpm_suspend_noirq" ), state.event, true);cpuidle_pause ();suspend_device_irqs ();mutex_lock (&dpm_list_mtx);
@@ -1120,6 +1129,7 @@ static int dpm_suspend_noirq(pm_message_t state) }else {dpm_show_time (starttime, state,"noirq" ); } +trace_suspend_resume (TPS ("dpm_suspend_noirq" ), state.event, false);return error; }
@@ -1216,6 +1226,7 @@ static int dpm_suspend_late(pm_message_t state)ktime_t starttime =ktime_get ();int error =0 ; +trace_suspend_resume (TPS ("dpm_suspend_late" ), state.event, true);mutex_lock (&dpm_list_mtx); pm_transition = state; async_error =0 ;
@@ -1251,6 +1262,7 @@ static int dpm_suspend_late(pm_message_t state) }else {dpm_show_time (starttime, state,"late" ); } +trace_suspend_resume (TPS ("dpm_suspend_late" ), state.event, false);return error; }
@@ -1435,6 +1447,7 @@ int dpm_suspend(pm_message_t state)ktime_t starttime =ktime_get ();int error =0 ; +trace_suspend_resume (TPS ("dpm_suspend" ), state.event, true);might_sleep ();cpufreq_suspend ();
@@ -1472,6 +1485,7 @@ int dpm_suspend(pm_message_t state)dpm_save_failed_step (SUSPEND_SUSPEND ); }else dpm_show_time (starttime, state,NULL ); +trace_suspend_resume (TPS ("dpm_suspend" ), state.event, false);return error; }
@@ -1546,6 +1560,7 @@ int dpm_prepare(pm_message_t state) {int error =0 ; +trace_suspend_resume (TPS ("dpm_prepare" ), state.event, true);might_sleep ();mutex_lock (&dpm_list_mtx);
@@ -1576,6 +1591,7 @@ int dpm_prepare(pm_message_t state)put_device (dev); }mutex_unlock (&dpm_list_mtx); +trace_suspend_resume (TPS ("dpm_prepare" ), state.event, false);return error; }
drivers/base/syscore.c +5 -0
@@ -10,6 +10,7 @@#include <linux/mutex.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <trace/events/power.h> static LIST_HEAD (syscore_ops_list);static DEFINE_MUTEX (syscore_ops_lock);
@@ -49,6 +50,7 @@ int syscore_suspend(void)struct syscore_ops *ops;int ret =0 ; +trace_suspend_resume (TPS ("syscore_suspend" ),0 , true);pr_debug ("Checking wakeup interrupts\n" );/* Return error code if there are any wakeup interrupts pending. */
@@ -70,6 +72,7 @@ int syscore_suspend(void) "Interrupts enabled after %pF\n", ops->suspend); } +trace_suspend_resume (TPS ("syscore_suspend" ),0 , false);return 0 ; err_out:
@@ -92,6 +95,7 @@ void syscore_resume(void) {struct syscore_ops *ops; +trace_suspend_resume (TPS ("syscore_resume" ),0 , true);WARN_ONCE (!irqs_disabled (),"Interrupts enabled before system core resume.\n" );
@@ -103,6 +107,7 @@ void syscore_resume(void)WARN_ONCE (!irqs_disabled (),"Interrupts enabled after %pF\n" , ops->resume); } +trace_suspend_resume (TPS ("syscore_resume" ),0 , false); }EXPORT_SYMBOL_GPL (syscore_resume);#endif /* CONFIG_PM_SLEEP */
include/trace/events/power.h +25 -17
60 lines not on this page · raw message
kernel/cpu.c +5 -0
@@ -20,6 +20,7 @@#include <linux/gfp.h> #include <linux/suspend.h> #include <linux/lockdep.h> +#include <trace/events/power.h> #include "smpboot.h"
@@ -522,7 +523,9 @@ int disable_nonboot_cpus(void)for_each_online_cpu (cpu) {if (cpu == first_cpu)continue ; +trace_suspend_resume (TPS ("CPU_OFF" ), cpu, true); error =_cpu_down (cpu,1 ); +trace_suspend_resume (TPS ("CPU_OFF" ), cpu, false);if (!error)cpumask_set_cpu (cpu, frozen_cpus);else {
@@ -566,7 +569,9 @@ void __ref enable_nonboot_cpus(void)arch_enable_nonboot_cpus_begin ();for_each_cpu (cpu, frozen_cpus) { +trace_suspend_resume (TPS ("CPU_ON" ), cpu, true); error =_cpu_up (cpu,1 ); +trace_suspend_resume (TPS ("CPU_ON" ), cpu, false);if (!error) {printk (KERN_INFO "CPU%d is up\n" , cpu);continue ;
kernel/power/hibernate.c +3 -0
@@ -28,6 +28,7 @@#include <linux/syscore_ops.h> #include <linux/ctype.h> #include <linux/genhd.h> +#include <trace/events/power.h> #include "power.h"
@@ -288,7 +289,9 @@ static int create_image(int platform_mode) in_suspend =1 ;save_processor_state (); +trace_suspend_resume (TPS ("machine_suspend" ),PM_EVENT_HIBERNATE , true); error =swsusp_arch_suspend (); +trace_suspend_resume (TPS ("machine_suspend" ),PM_EVENT_HIBERNATE , false);if (error)printk (KERN_ERR "PM: Error %d creating hibernation image\n" , error);
kernel/power/process.c +3 -0
@@ -17,6 +17,7 @@#include <linux/delay.h> #include <linux/workqueue.h> #include <linux/kmod.h> +#include <trace/events/power.h> /* * Timeout for stopping processes
@@ -175,6 +176,7 @@ void thaw_processes(void)struct task_struct *g, *p;struct task_struct *curr = current; +trace_suspend_resume (TPS ("thaw_processes" ),0 , true);if (pm_freezing)atomic_dec (&system_freezing_cnt); pm_freezing = false;
@@ -201,6 +203,7 @@ void thaw_processes(void)schedule ();printk ("done.\n" ); +trace_suspend_resume (TPS ("thaw_processes" ),0 , false); }void thaw_kernel_threads (void )
kernel/power/suspend.c +12 -2
@@ -147,7 +147,9 @@ static int suspend_prepare(suspend_state_t state)if (error) goto Finish; +trace_suspend_resume (TPS ("freeze_processes" ),0 , true); error =suspend_freeze_processes (); +trace_suspend_resume (TPS ("freeze_processes" ),0 , false);if (!error)return 0 ;
@@ -210,7 +212,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)* all the devices are suspended. */ if (state ==PM_SUSPEND_FREEZE ) { +trace_suspend_resume (TPS ("machine_suspend" ), state, true);freeze_enter (); +trace_suspend_resume (TPS ("machine_suspend" ), state, false); goto Platform_wake; }
@@ -226,7 +230,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)if (!error) { *wakeup =pm_wakeup_pending ();if (!(suspend_test (TEST_CORE ) || *wakeup)) { +trace_suspend_resume (TPS ("machine_suspend" ), + state, true); error = suspend_ops->enter (state); +trace_suspend_resume (TPS ("machine_suspend" ), + state, false); events_check_enabled = false; }syscore_resume ();
@@ -264,7 +272,6 @@ int suspend_devices_and_enter(suspend_state_t state)if (need_suspend_ops (state) && !suspend_ops)return -ENOSYS ; -trace_machine_suspend (state);if (need_suspend_ops (state) && suspend_ops->begin) { error = suspend_ops->begin (state);if (error)
@@ -294,7 +301,6 @@ int suspend_devices_and_enter(suspend_state_t state) Close:if (need_suspend_ops (state) && suspend_ops->end) suspend_ops->end (); -trace_machine_suspend (PWR_EVENT_EXIT );return error; Recover_platform:
@@ -328,6 +334,7 @@ static int enter_state(suspend_state_t state) {int error; +trace_suspend_resume (TPS ("suspend_enter" ), state, true);if (!valid_state (state))return -ENODEV ;
@@ -337,9 +344,11 @@ static int enter_state(suspend_state_t state)if (state ==PM_SUSPEND_FREEZE )freeze_begin (); +trace_suspend_resume (TPS ("sync_filesystems" ),0 , true);printk (KERN_INFO "PM: Syncing filesystems ... " );sys_sync ();printk ("done.\n" ); +trace_suspend_resume (TPS ("sync_filesystems" ),0 , false);pr_debug ("PM: Preparing system for %s sleep\n" , pm_states[state]); error =suspend_prepare (state);
@@ -349,6 +358,7 @@ static int enter_state(suspend_state_t state)if (suspend_test (TEST_FREEZER )) goto Finish; +trace_suspend_resume (TPS ("suspend_enter" ), state, false);pr_debug ("PM: Entering %s sleep\n" , pm_states[state]);pm_restrict_gfp_mask (); error =suspend_devices_and_enter (state);
Quoted 20 lines · On Fri, 6 Jun 2014 05:40:17 -0700 Todd E Brandt…
From: Todd E Brandt <[email protected]>
To: [email protected], [email protected]
Cc: [email protected], [email protected]
Subject: [PATCH v3] PM: trace events for suspend/resume
Date: Fri, 6 Jun 2014 05:40:17 -0700
Reply-To: [email protected]
User-Agent: Mutt/1.5.21 (2010-09-15)
Message-ID: <[email protected]>Adds trace events that give finer resolution into suspend/resume. These events are graphed in the timelines generated by the
analyze_suspend.pyscript. They represent large areas of time consumed that are typical to suspend and resume.The event is triggered by calling the function "
trace_suspend_resume" with three arguments: a string (the name of the event to be displayed in the timeline), an integer (case specific number, such as the power state or cpu number), and a boolean (where true is used to denote the start of the timeline event, and false to denote the end).
Quoted 4 lines
The
suspend_resumetrace event reproduces the data that themachine_suspendtrace event did, so the latter has been removed.Signed-off-by Todd Brandt <[email protected]>
Looks good to me.
-- Steve
Quoted 23 lines · Steven Rostedt
Quoted 20 lines · On Fri, 6 Jun 2014 05:40:17 -0700 Todd E Brandt…
From: Todd E Brandt <[email protected]>
To: [email protected], [email protected]
Cc: [email protected], [email protected]
Subject: [PATCH v3] PM: trace events for suspend/resume
Date: Fri, 6 Jun 2014 05:40:17 -0700
Reply-To: [email protected]
User-Agent: Mutt/1.5.21 (2010-09-15)
Message-ID: <[email protected]>Adds trace events that give finer resolution into suspend/resume. These events are graphed in the timelines generated by the
analyze_suspend.pyscript. They represent large areas of time consumed that are typical to suspend and resume.The event is triggered by calling the function "
trace_suspend_resume" with three arguments: a string (the name of the event to be displayed in the timeline), an integer (case specific number, such as the power state or cpu number), and a boolean (where true is used to denote the start of the timeline event, and false to denote the end).
Quoted 8 lines
Quoted 4 lines
The
suspend_resumetrace event reproduces the data that themachine_suspendtrace event did, so the latter has been removed.Signed-off-by Todd Brandt <[email protected]>Looks good to me.
Acked-by Steven Rostedt <[email protected]>
Applied after some rebasing.
Todd please check the bleeding-edge branch.
Thanks!
Signature · 2 lines
I speak only for myself. Rafael J. Wysocki, Intel Open Source Technology Center.