From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org --- arch/arm/mach-omap2/cpuidle34xx.c | 58 ++++++++++++++++-- arch/arm/mach-omap2/pm.h | 5 ++ arch/arm/mach-omap2/sleep34xx.S | 121 +++++++++++++++++++++++++++++++++++++ drivers/cpuidle/Kconfig | 5 ++ drivers/cpuidle/sysfs.c | 16 +++++- include/linux/cpuidle.h | 3 + 6 files changed, 202 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 3d3d035..398bef8 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -25,6 +25,7 @@ #include <linux/sched.h> #include <linux/cpuidle.h>
+#include <linux/clk.h> #include <plat/prcm.h> #include <plat/irqs.h> #include <plat/powerdomain.h> @@ -86,6 +87,11 @@ static struct cpuidle_params cpuidle_params_table[] = { {1, 10000, 30000, 300000}, };
+#ifdef CONFIG_CPU_IDLE_PROF +static struct clk *clk_32k; +#define CONVERT_32K_USEC(lat) (lat * (USEC_PER_SEC/clk_get_rate(clk_32k))) +#endif + static int omap3_idle_bm_check(void) { if (!omap3_can_sleep()) @@ -115,21 +121,28 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ + static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; +#ifdef CONFIG_CPU_IDLE_PROF + int idle_time, latency; + long sleep_time, wkup_time, total_sleep_time; + long preidle_time, postidle_time; +#endif
current_cx_state = *cx;
- /* Used to keep track of the total time in idle */ - getnstimeofday(&ts_preidle); - local_irq_disable(); local_fiq_disable(); - + /* Used to keep track of the total time in idle */ + getnstimeofday(&ts_preidle); +#ifdef CONFIG_CPU_IDLE_PROF + preidle_time = omap3_sram_get_32k_tick(); +#endif pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state);
@@ -153,9 +166,39 @@ return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF + postidle_time = omap3_sram_get_32k_tick(); +#endif local_irq_enable(); local_fiq_enable();
+#ifdef CONFIG_CPU_IDLE_PROF + sleep_time = omap3_sram_get_sleep_time(); + wkup_time = omap3_sram_get_wkup_time(); + + /* take care of overflow */ + if (postidle_time < preidle_time) + postidle_time += (u32) 0xffffffff; + if (wkup_time < sleep_time) + wkup_time += (u32) 0xffffffff; + + idle_time = postidle_time - preidle_time; + total_sleep_time = wkup_time - sleep_time; + latency = idle_time - total_sleep_time; + sleep_time = omap3_sram_get_sleep_time(); + wkup_time = omap3_sram_get_wkup_time(); + + /* calculate average latency after ignoring sprious ones */ + if ((total_sleep_time > 0) && (latency > state->actual_latency) + && (latency >= 0)) { + state->actual_latency = CONVERT_32K_USEC(latency); + latency = (sleep_time - preidle_time); + state->sleep_latency = CONVERT_32K_USEC(latency); + latency = postidle_time - wkup_time; + state->wkup_latency = CONVERT_32K_USEC(latency); + } +#endif + return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
@@ -423,7 +466,9 @@ int __init omap3_idle_init(void) struct omap3_processor_cx *cx; struct cpuidle_state *state; struct cpuidle_device *dev; - +#ifdef CONFIG_CPU_IDLE_PROF + static struct device dummy_device; +#endif mpu_pd = pwrdm_lookup("mpu_pwrdm"); core_pd = pwrdm_lookup("core_pwrdm");
@@ -456,6 +501,9 @@ int __init omap3_idle_init(void)
omap3_cpuidle_update_states();
+#ifdef CONFIG_CPU_IDLE_PROF + clk_32k = clk_get(&dummy_device, "wkup_32k_fck"); +#endif if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", __func__); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 3de6ece..e62e87d 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -82,4 +82,9 @@ extern unsigned int save_secure_ram_context_sz; extern unsigned int omap24xx_cpu_suspend_sz; extern unsigned int omap34xx_cpu_suspend_sz;
+#ifdef CONFIG_CPU_IDLE_PROF +extern u32 omap3_sram_get_wkup_time(); +extern u32 omap3_sram_get_sleep_time(); +extern u32 omap3_sram_get_32k_tick(); +#endif #endif diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index d522cd7..8dec5ef 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -59,6 +59,20 @@ #define SDRC_DLLA_STATUS_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) #define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+#define TIMER_32K_SYNC_P 0x48320010 +#define TIMER_32K_SYNC OMAP2_L4_IO_ADDRESS(TIMER_32K_SYNC_P) + +#define SCRATCHPAD_SLEEP_TIME_OFFSET 0x9f8 +#define SCRATCHPAD_WKUP_TIME_OFFSET 0x9fc +#define SCRATCHPAD_SLEEP_TIME OMAP343X_CTRL_REGADDR(SCRATCHPAD_SLEEP_TIME_OFFSET) +#define SCRATCHPAD_WKUP_TIME OMAP343X_CTRL_REGADDR(SCRATCHPAD_WKUP_TIME_OFFSET) +#define SCRATCHPAD_WKUP_TIME_P OMAP343X_CTRL_BASE + SCRATCHPAD_WKUP_TIME_OFFSET + +#define CM_ICLKEN_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_ICLKEN) +#define CM_ICLKEN_WKUP_P OMAP3430_CM_BASE + WKUP_MOD + CM_ICLKEN +#define CM_IDLEST_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_IDLEST) +#define CM_IDLEST_WKUP_P OMAP3430_CM_BASE + WKUP_MOD + CM_IDLEST + .text /* Function to aquire the semaphore in scratchpad */ ENTRY(lock_scratchpad_sem) @@ -183,7 +197,31 @@ api_params: .word 0x4, 0x0, 0x0, 0x1, 0x1 ENTRY(save_secure_ram_context_sz) .word . - save_secure_ram_context +#ifdef CONFIG_CPU_IDLE_PROF +ENTRY(omap3_sram_get_wkup_time) + stmfd sp!, {lr} @ save registers on stack + ldr r0, wkup_time + ldr r0, [r0] + ldmfd sp!, {pc} @ restore regs and return +ENTRY(omap3_sram_get_wkup_time_sz) + .word . - omap3_sram_get_wkup_time + +ENTRY(omap3_sram_get_sleep_time) + stmfd sp!, {lr} @ save registers on stack + ldr r0, sleep_time + ldr r0, [r0] + ldmfd sp!, {pc} @ restore regs and return +ENTRY(omap3_sram_get_sleep_time_sz) + .word . - omap3_sram_get_sleep_time
+ENTRY(omap3_sram_get_32k_tick) + stmfd sp!, {lr} @ save registers on stack + ldr r0, sync_32k_timer + ldr r0, [r0] + ldmfd sp!, {pc} @ restore regs and return +ENTRY(omap3_sram_get_32k_tick_sz) + .word . - omap3_sram_get_32k_tick +#endif /* * Forces OMAP into idle state * @@ -207,6 +245,13 @@ loop: cmp r1, #0x0 /* If context save is required, do that and execute wfi */ bne save_context_wfi + +#ifdef CONFIG_CPU_IDLE_PROF + ldr r4, sync_32k_timer + ldr r5, [r4] + ldr r6, sleep_time + str r5, [r6] +#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -224,8 +269,25 @@ loop: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF + ldr r4, iclken_wkup + ldr r5, [r4] + orr r5, r5, #0x4 + str r5, [r4] + ldr r4, idlest_wkup +wait_idlest: + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x0 + bne wait_idlest + ldr r4, sync_32k_timer + ldr r5, [r4] + ldr r6, wkup_time + str r5, [r6] +#endif bl wait_sdrc_ok
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return restore_es3: /*b restore_es3*/ @ Enable to debug restore code @@ -247,6 +309,23 @@ copy_to_sram: blx r1 restore: /* b restore*/ @ Enable to debug restore code +#ifdef CONFIG_CPU_IDLE_PROF + ldr r4, iclken_wkup_p + ldr r5, [r4] + orr r5, r5, #0x4 + str r5, [r4] + ldr r4, idlest_wkup_p +wait_idlest1: + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x0 + bne wait_idlest1 + ldr r4, sync_32k_timer_p + ldr r5, [r4] + ldr r6, wkup_time_p + str r5, [r6] +#endif + /* Check what was the reason for mpu reset and store the reason in r9*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost - In this case, we wont be here */ @@ -587,6 +666,12 @@ finished: mcr p15, 2, r10, c0, c0, 0 isb skip_l2_inval: +#ifdef CONFIG_CPU_IDLE_PROF + ldr r4, sync_32k_timer + ldr r5, [r4] + ldr r6, sleep_time + str r5, [r6] +#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -603,6 +688,22 @@ skip_l2_inval: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF + ldr r4, iclken_wkup + ldr r5, [r4] + orr r5, r5, #0x4 + str r5, [r4] + ldr r4, idlest_wkup +wait_idlest2: + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x0 + bne wait_idlest2 + ldr r4, sync_32k_timer + ldr r5, [r4] + ldr r6, wkup_time + str r5, [r6] +#endif bl wait_sdrc_ok /* restore regs and return */ ldmfd sp!, {r0-r12, pc} @@ -668,5 +769,25 @@ cache_pred_disable_mask: .word 0xFFFFE7FB control_stat: .word CONTROL_STAT +#ifdef CONFIG_CPU_IDLE_PROF +sync_32k_timer: + .word TIMER_32K_SYNC +sync_32k_timer_p: + .word TIMER_32K_SYNC_P +sleep_time: + .word SCRATCHPAD_SLEEP_TIME +wkup_time: + .word SCRATCHPAD_WKUP_TIME +wkup_time_p: + .word SCRATCHPAD_WKUP_TIME_P +iclken_wkup: + .word CM_ICLKEN_WKUP +iclken_wkup_p: + .word CM_ICLKEN_WKUP_P +idlest_wkup: + .word CM_IDLEST_WKUP +idlest_wkup_p: + .word CM_IDLEST_WKUP_P +#endif ENTRY(omap34xx_cpu_suspend_sz) .word . - omap34xx_cpu_suspend diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 7dbc4a8..147456d 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -18,3 +18,8 @@ config CPU_IDLE_GOV_MENU bool depends on CPU_IDLE && NO_HZ default y + +config CPU_IDLE_PROF + bool + depends on CPU_IDLE + default n diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0310ffa..a3e9db1 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -249,6 +249,11 @@ define_show_state_ull_function(usage) define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) +#ifdef CONFIG_CPU_IDLE_PROF +define_show_state_function(actual_latency) +define_show_state_function(sleep_latency) +define_show_state_function(wkup_latency) +#endif
define_one_state_ro(name, show_state_name); define_one_state_ro(desc, show_state_desc); @@ -256,7 +261,11 @@ define_one_state_ro(latency, show_state_exit_latency); define_one_state_ro(power, show_state_power_usage); define_one_state_ro(usage, show_state_usage); define_one_state_ro(time, show_state_time); - +#ifdef CONFIG_CPU_IDLE_PROF +define_one_state_ro(actual_latency, show_state_actual_latency); +define_one_state_ro(sleep_latency, show_state_sleep_latency); +define_one_state_ro(wkup_latency, show_state_wkup_latency); +#endif static struct attribute *cpuidle_state_default_attrs[] = { &attr_name.attr, &attr_desc.attr, @@ -264,6 +273,11 @@ static struct attribute *cpuidle_state_default_attrs[] = { &attr_power.attr, &attr_usage.attr, &attr_time.attr, +#ifdef CONFIG_CPU_IDLE_PROF + &attr_actual_latency.attr, + &attr_sleep_latency.attr, + &attr_wkup_latency.attr, +#endif NULL };
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 55215cc..6474f6a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -43,6 +43,9 @@ struct cpuidle_state {
int (*enter) (struct cpuidle_device *dev, struct cpuidle_state *state); +#ifdef CONFIG_CPU_IDLE_PROF + u32 actual_latency, sleep_latency, wkup_latency; +#endif };
/* Idle State Flags */
Hi,
On Sat, Aug 28, 2010 at 12:08 AM, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
...
+#ifdef CONFIG_CPU_IDLE_PROF
- sleep_time = omap3_sram_get_sleep_time();
- wkup_time = omap3_sram_get_wkup_time();
- /* take care of overflow */
- if (postidle_time < preidle_time)
- postidle_time += (u32) 0xffffffff;
- if (wkup_time < sleep_time)
- wkup_time += (u32) 0xffffffff;
- idle_time = postidle_time - preidle_time;
- total_sleep_time = wkup_time - sleep_time;
- latency = idle_time - total_sleep_time;
- sleep_time = omap3_sram_get_sleep_time();
- wkup_time = omap3_sram_get_wkup_time();
Is it needed to re-read the sleep_time and wkup_time values from the scratchpad? What about the 32k timer overflow? Could that cause the sleep_latency and/or wkup_latency to be <0?
- /* calculate average latency after ignoring sprious ones */
- if ((total_sleep_time > 0) && (latency > state->actual_latency)
- && (latency >= 0)) {
- state->actual_latency = CONVERT_32K_USEC(latency);
- latency = (sleep_time - preidle_time);
Risk of overflow?
- state->sleep_latency = CONVERT_32K_USEC(latency);
- latency = postidle_time - wkup_time;
Risk of overflow?
- state->wkup_latency = CONVERT_32K_USEC(latency);
- }
+#endif
return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
Jean
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Jean Pihet Sent: Friday, August 27, 2010 3:17 PM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi,
On Sat, Aug 28, 2010 at 12:08 AM, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
...
+#ifdef CONFIG_CPU_IDLE_PROF
- sleep_time = omap3_sram_get_sleep_time();
- wkup_time = omap3_sram_get_wkup_time();
- /* take care of overflow */
- if (postidle_time < preidle_time)
- postidle_time += (u32) 0xffffffff;
- if (wkup_time < sleep_time)
- wkup_time += (u32) 0xffffffff;
- idle_time = postidle_time - preidle_time;
- total_sleep_time = wkup_time - sleep_time;
- latency = idle_time - total_sleep_time;
- sleep_time = omap3_sram_get_sleep_time();
- wkup_time = omap3_sram_get_wkup_time();
Is it needed to re-read the sleep_time and wkup_time values from the scratchpad?
Sleep and wake up time stamps were taken just before and after executing wfi and stored in scratchpad wkup memory. These values are used while computing actual latency.
What about the 32k timer overflow? Could that cause the sleep_latency and/or wkup_latency to be <0?
Overflow issues are taken care while computing idle_time and total_sleep_time in code below. + if (postidle_time < preidle_time) + postidle_time += (u32) 0xffffffff; + if (wkup_time < sleep_time) + wkup_time += (u32) 0xffffffff;
- /* calculate average latency after ignoring sprious ones */
- if ((total_sleep_time > 0) && (latency > state->actual_latency)
- && (latency >= 0)) {
- state->actual_latency = CONVERT_32K_USEC(latency);
- latency = (sleep_time - preidle_time);
Risk of overflow?
Yes I just realized that overflow can cause sleep_latency and wkup_latency to turn negative. Thanks for pointing it. Will fix it in next version.
- state->sleep_latency = CONVERT_32K_USEC(latency);
- latency = postidle_time - wkup_time;
Risk of overflow?
Agreed. Will fix it.
Vishwa
- state->wkup_latency = CONVERT_32K_USEC(latency);
- }
+#endif
return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
Jean
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
g 28, 2010 at 3:38 AM, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
arch/arm/mach-omap2/cpuidle34xx.c | 58 ++++++++++++++++-- arch/arm/mach-omap2/pm.h | 5 ++ arch/arm/mach-omap2/sleep34xx.S | 121 +++++++++++++++++++++++++++++++++++++ drivers/cpuidle/Kconfig | 5 ++ drivers/cpuidle/sysfs.c | 16 +++++- include/linux/cpuidle.h | 3 + 6 files changed, 202 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 3d3d035..398bef8 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -25,6 +25,7 @@ #include <linux/sched.h> #include <linux/cpuidle.h>
+#include <linux/clk.h> #include <plat/prcm.h> #include <plat/irqs.h> #include <plat/powerdomain.h> @@ -86,6 +87,11 @@ static struct cpuidle_params cpuidle_params_table[] = { {1, 10000, 30000, 300000}, };
+#ifdef CONFIG_CPU_IDLE_PROF +static struct clk *clk_32k; +#define CONVERT_32K_USEC(lat) (lat * (USEC_PER_SEC/clk_get_rate(clk_32k))) +#endif
static int omap3_idle_bm_check(void) { if (!omap3_can_sleep()) @@ -115,21 +121,28 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */
static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; +#ifdef CONFIG_CPU_IDLE_PROF
- int idle_time, latency;
- long sleep_time, wkup_time, total_sleep_time;
- long preidle_time, postidle_time;
+#endif
current_cx_state = *cx;
- /* Used to keep track of the total time in idle */
- getnstimeofday(&ts_preidle);
local_irq_disable(); local_fiq_disable();
- /* Used to keep track of the total time in idle */
- getnstimeofday(&ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
- preidle_time = omap3_sram_get_32k_tick();
+#endif pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state);
@@ -153,9 +166,39 @@ return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
- postidle_time = omap3_sram_get_32k_tick();
+#endif local_irq_enable(); local_fiq_enable();
+#ifdef CONFIG_CPU_IDLE_PROF
- sleep_time = omap3_sram_get_sleep_time();
- wkup_time = omap3_sram_get_wkup_time();
- /* take care of overflow */
- if (postidle_time < preidle_time)
- postidle_time += (u32) 0xffffffff;
- if (wkup_time < sleep_time)
- wkup_time += (u32) 0xffffffff;
- idle_time = postidle_time - preidle_time;
- total_sleep_time = wkup_time - sleep_time;
- latency = idle_time - total_sleep_time;
- sleep_time = omap3_sram_get_sleep_time();
- wkup_time = omap3_sram_get_wkup_time();
- /* calculate average latency after ignoring sprious ones */
- if ((total_sleep_time > 0) && (latency > state->actual_latency)
- && (latency >= 0)) {
- state->actual_latency = CONVERT_32K_USEC(latency);
- latency = (sleep_time - preidle_time);
- state->sleep_latency = CONVERT_32K_USEC(latency);
- latency = postidle_time - wkup_time;
- state->wkup_latency = CONVERT_32K_USEC(latency);
- }
+#endif
return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
@@ -423,7 +466,9 @@ int __init omap3_idle_init(void) struct omap3_processor_cx *cx; struct cpuidle_state *state; struct cpuidle_device *dev;
+#ifdef CONFIG_CPU_IDLE_PROF
- static struct device dummy_device;
+#endif mpu_pd = pwrdm_lookup("mpu_pwrdm"); core_pd = pwrdm_lookup("core_pwrdm");
@@ -456,6 +501,9 @@ int __init omap3_idle_init(void)
omap3_cpuidle_update_states();
+#ifdef CONFIG_CPU_IDLE_PROF
- clk_32k = clk_get(&dummy_device, "wkup_32k_fck");
+#endif if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", __func__); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 3de6ece..e62e87d 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -82,4 +82,9 @@ extern unsigned int save_secure_ram_context_sz; extern unsigned int omap24xx_cpu_suspend_sz; extern unsigned int omap34xx_cpu_suspend_sz;
+#ifdef CONFIG_CPU_IDLE_PROF +extern u32 omap3_sram_get_wkup_time(); +extern u32 omap3_sram_get_sleep_time(); +extern u32 omap3_sram_get_32k_tick(); +#endif #endif diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index d522cd7..8dec5ef 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -59,6 +59,20 @@ #define SDRC_DLLA_STATUS_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) #define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+#define TIMER_32K_SYNC_P 0x48320010 +#define TIMER_32K_SYNC OMAP2_L4_IO_ADDRESS(TIMER_32K_SYNC_P)
+#define SCRATCHPAD_SLEEP_TIME_OFFSET 0x9f8 +#define SCRATCHPAD_WKUP_TIME_OFFSET 0x9fc +#define SCRATCHPAD_SLEEP_TIME OMAP343X_CTRL_REGADDR(SCRATCHPAD_SLEEP_TIME_OFFSET) +#define SCRATCHPAD_WKUP_TIME OMAP343X_CTRL_REGADDR(SCRATCHPAD_WKUP_TIME_OFFSET) +#define SCRATCHPAD_WKUP_TIME_P OMAP343X_CTRL_BASE + SCRATCHPAD_WKUP_TIME_OFFSET
+#define CM_ICLKEN_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_ICLKEN) +#define CM_ICLKEN_WKUP_P OMAP3430_CM_BASE + WKUP_MOD + CM_ICLKEN +#define CM_IDLEST_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_IDLEST) +#define CM_IDLEST_WKUP_P OMAP3430_CM_BASE + WKUP_MOD + CM_IDLEST
.text /* Function to aquire the semaphore in scratchpad */ ENTRY(lock_scratchpad_sem) @@ -183,7 +197,31 @@ api_params: .word 0x4, 0x0, 0x0, 0x1, 0x1 ENTRY(save_secure_ram_context_sz) .word . - save_secure_ram_context +#ifdef CONFIG_CPU_IDLE_PROF +ENTRY(omap3_sram_get_wkup_time)
- stmfd sp!, {lr} @ save registers on stack
- ldr r0, wkup_time
- ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
+ENTRY(omap3_sram_get_wkup_time_sz)
- .word . - omap3_sram_get_wkup_time
+ENTRY(omap3_sram_get_sleep_time)
- stmfd sp!, {lr} @ save registers on stack
- ldr r0, sleep_time
- ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
+ENTRY(omap3_sram_get_sleep_time_sz)
- .word . - omap3_sram_get_sleep_time
+ENTRY(omap3_sram_get_32k_tick)
- stmfd sp!, {lr} @ save registers on stack
- ldr r0, sync_32k_timer
- ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
+ENTRY(omap3_sram_get_32k_tick_sz)
- .word . - omap3_sram_get_32k_tick
+#endif /* * Forces OMAP into idle state * @@ -207,6 +245,13 @@ loop: cmp r1, #0x0 /* If context save is required, do that and execute wfi */ bne save_context_wfi
+#ifdef CONFIG_CPU_IDLE_PROF
- ldr r4, sync_32k_timer
- ldr r5, [r4]
- ldr r6, sleep_time
- str r5, [r6]
+#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -224,8 +269,25 @@ loop: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF
- ldr r4, iclken_wkup
- ldr r5, [r4]
- orr r5, r5, #0x4
- str r5, [r4]
- ldr r4, idlest_wkup
+wait_idlest:
- ldr r5, [r4]
- and r5, r5, #0x4
- cmp r5, #0x0
- bne wait_idlest
- ldr r4, sync_32k_timer
- ldr r5, [r4]
- ldr r6, wkup_time
- str r5, [r6]
+#endif bl wait_sdrc_ok
ldmfd sp!, {r0-r12, pc} @ restore regs and return restore_es3: /*b restore_es3*/ @ Enable to debug restore code @@ -247,6 +309,23 @@ copy_to_sram: blx r1 restore: /* b restore*/ @ Enable to debug restore code +#ifdef CONFIG_CPU_IDLE_PROF
- ldr r4, iclken_wkup_p
- ldr r5, [r4]
- orr r5, r5, #0x4
- str r5, [r4]
- ldr r4, idlest_wkup_p
+wait_idlest1:
- ldr r5, [r4]
- and r5, r5, #0x4
- cmp r5, #0x0
- bne wait_idlest1
- ldr r4, sync_32k_timer_p
- ldr r5, [r4]
- ldr r6, wkup_time_p
- str r5, [r6]
+#endif
/* Check what was the reason for mpu reset and store the reason in r9*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost - In this case, we wont be here */ @@ -587,6 +666,12 @@ finished: mcr p15, 2, r10, c0, c0, 0 isb skip_l2_inval: +#ifdef CONFIG_CPU_IDLE_PROF
- ldr r4, sync_32k_timer
- ldr r5, [r4]
- ldr r6, sleep_time
- str r5, [r6]
+#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -603,6 +688,22 @@ skip_l2_inval: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF
- ldr r4, iclken_wkup
- ldr r5, [r4]
- orr r5, r5, #0x4
- str r5, [r4]
- ldr r4, idlest_wkup
+wait_idlest2:
- ldr r5, [r4]
- and r5, r5, #0x4
- cmp r5, #0x0
- bne wait_idlest2
- ldr r4, sync_32k_timer
- ldr r5, [r4]
- ldr r6, wkup_time
- str r5, [r6]
+#endif bl wait_sdrc_ok /* restore regs and return */ ldmfd sp!, {r0-r12, pc} @@ -668,5 +769,25 @@ cache_pred_disable_mask: .word 0xFFFFE7FB control_stat: .word CONTROL_STAT +#ifdef CONFIG_CPU_IDLE_PROF +sync_32k_timer:
- .word TIMER_32K_SYNC
+sync_32k_timer_p:
- .word TIMER_32K_SYNC_P
+sleep_time:
- .word SCRATCHPAD_SLEEP_TIME
+wkup_time:
- .word SCRATCHPAD_WKUP_TIME
+wkup_time_p:
- .word SCRATCHPAD_WKUP_TIME_P
+iclken_wkup:
- .word CM_ICLKEN_WKUP
+iclken_wkup_p:
- .word CM_ICLKEN_WKUP_P
+idlest_wkup:
- .word CM_IDLEST_WKUP
+idlest_wkup_p:
- .word CM_IDLEST_WKUP_P
+#endif ENTRY(omap34xx_cpu_suspend_sz) .word . - omap34xx_cpu_suspend diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 7dbc4a8..147456d 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -18,3 +18,8 @@ config CPU_IDLE_GOV_MENU bool depends on CPU_IDLE && NO_HZ default y
+config CPU_IDLE_PROF
- bool
Should not this be something like bool "CPU idle profiling " so that this entry shows up in 'make menuconfig' ? and this should have dependency on ARCH_OMAP3 also ?
- depends on CPU_IDLE
- default n
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0310ffa..a3e9db1 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -249,6 +249,11 @@ define_show_state_ull_function(usage) define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) +#ifdef CONFIG_CPU_IDLE_PROF +define_show_state_function(actual_latency) +define_show_state_function(sleep_latency) +define_show_state_function(wkup_latency) +#endif
define_one_state_ro(name, show_state_name); define_one_state_ro(desc, show_state_desc); @@ -256,7 +261,11 @@ define_one_state_ro(latency, show_state_exit_latency); define_one_state_ro(power, show_state_power_usage); define_one_state_ro(usage, show_state_usage); define_one_state_ro(time, show_state_time);
+#ifdef CONFIG_CPU_IDLE_PROF +define_one_state_ro(actual_latency, show_state_actual_latency); +define_one_state_ro(sleep_latency, show_state_sleep_latency); +define_one_state_ro(wkup_latency, show_state_wkup_latency); +#endif static struct attribute *cpuidle_state_default_attrs[] = { &attr_name.attr, &attr_desc.attr, @@ -264,6 +273,11 @@ static struct attribute *cpuidle_state_default_attrs[] = { &attr_power.attr, &attr_usage.attr, &attr_time.attr, +#ifdef CONFIG_CPU_IDLE_PROF
- &attr_actual_latency.attr,
- &attr_sleep_latency.attr,
- &attr_wkup_latency.attr,
+#endif NULL };
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 55215cc..6474f6a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -43,6 +43,9 @@ struct cpuidle_state {
int (*enter) (struct cpuidle_device *dev, struct cpuidle_state *state); +#ifdef CONFIG_CPU_IDLE_PROF
- u32 actual_latency, sleep_latency, wkup_latency;
+#endif };
/* Idle State Flags */
1.7.0.4
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of C V, Silesh Sent: Friday, August 27, 2010 3:28 PM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
g 28, 2010 at 3:38 AM, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
arch/arm/mach-omap2/cpuidle34xx.c | 58 ++++++++++++++++-- arch/arm/mach-omap2/pm.h | 5 ++ arch/arm/mach-omap2/sleep34xx.S | 121
+++++++++++++++++++++++++++++++++++++
drivers/cpuidle/Kconfig | 5 ++ drivers/cpuidle/sysfs.c | 16 +++++- include/linux/cpuidle.h | 3 + 6 files changed, 202 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-
omap2/cpuidle34xx.c
index 3d3d035..398bef8 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -25,6 +25,7 @@ #include <linux/sched.h> #include <linux/cpuidle.h>
+#include <linux/clk.h> #include <plat/prcm.h> #include <plat/irqs.h> #include <plat/powerdomain.h> @@ -86,6 +87,11 @@ static struct cpuidle_params cpuidle_params_table[] = { {1, 10000, 30000, 300000}, };
+#ifdef CONFIG_CPU_IDLE_PROF +static struct clk *clk_32k; +#define CONVERT_32K_USEC(lat) (lat * (USEC_PER_SEC/clk_get_rate(clk_32k))) +#endif
static int omap3_idle_bm_check(void) { if (!omap3_can_sleep()) @@ -115,21 +121,28 @@ static int _cpuidle_deny_idle(struct powerdomain
*pwrdm,
- Called from the CPUidle framework to program the device to the
- specified target state selected by the governor.
*/
static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; +#ifdef CONFIG_CPU_IDLE_PROF
int idle_time, latency;
long sleep_time, wkup_time, total_sleep_time;
long preidle_time, postidle_time;
+#endif
current_cx_state = *cx;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
local_irq_disable(); local_fiq_disable();
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
preidle_time = omap3_sram_get_32k_tick();
+#endif pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state);
@@ -153,9 +166,39 @@ return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
postidle_time = omap3_sram_get_32k_tick();
+#endif local_irq_enable(); local_fiq_enable();
+#ifdef CONFIG_CPU_IDLE_PROF
sleep_time = omap3_sram_get_sleep_time();
wkup_time = omap3_sram_get_wkup_time();
/* take care of overflow */
if (postidle_time < preidle_time)
postidle_time += (u32) 0xffffffff;
if (wkup_time < sleep_time)
wkup_time += (u32) 0xffffffff;
idle_time = postidle_time - preidle_time;
total_sleep_time = wkup_time - sleep_time;
latency = idle_time - total_sleep_time;
sleep_time = omap3_sram_get_sleep_time();
wkup_time = omap3_sram_get_wkup_time();
/* calculate average latency after ignoring sprious ones */
if ((total_sleep_time > 0) && (latency > state->actual_latency)
&& (latency >= 0)) {
state->actual_latency = CONVERT_32K_USEC(latency);
latency = (sleep_time - preidle_time);
state->sleep_latency = CONVERT_32K_USEC(latency);
latency = postidle_time - wkup_time;
state->wkup_latency = CONVERT_32K_USEC(latency);
}
+#endif
return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
}
@@ -423,7 +466,9 @@ int __init omap3_idle_init(void) struct omap3_processor_cx *cx; struct cpuidle_state *state; struct cpuidle_device *dev;
+#ifdef CONFIG_CPU_IDLE_PROF
static struct device dummy_device;
+#endif mpu_pd = pwrdm_lookup("mpu_pwrdm"); core_pd = pwrdm_lookup("core_pwrdm");
@@ -456,6 +501,9 @@ int __init omap3_idle_init(void)
omap3_cpuidle_update_states();
+#ifdef CONFIG_CPU_IDLE_PROF
clk_32k = clk_get(&dummy_device, "wkup_32k_fck");
+#endif if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", __func__); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 3de6ece..e62e87d 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -82,4 +82,9 @@ extern unsigned int save_secure_ram_context_sz; extern unsigned int omap24xx_cpu_suspend_sz; extern unsigned int omap34xx_cpu_suspend_sz;
+#ifdef CONFIG_CPU_IDLE_PROF +extern u32 omap3_sram_get_wkup_time(); +extern u32 omap3_sram_get_sleep_time(); +extern u32 omap3_sram_get_32k_tick(); +#endif #endif diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-
omap2/sleep34xx.S
index d522cd7..8dec5ef 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -59,6 +59,20 @@ #define SDRC_DLLA_STATUS_V
OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
#define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+#define TIMER_32K_SYNC_P 0x48320010 +#define TIMER_32K_SYNC OMAP2_L4_IO_ADDRESS(TIMER_32K_SYNC_P)
+#define SCRATCHPAD_SLEEP_TIME_OFFSET 0x9f8 +#define SCRATCHPAD_WKUP_TIME_OFFSET 0x9fc +#define SCRATCHPAD_SLEEP_TIME
OMAP343X_CTRL_REGADDR(SCRATCHPAD_SLEEP_TIME_OFFSET)
+#define SCRATCHPAD_WKUP_TIME
OMAP343X_CTRL_REGADDR(SCRATCHPAD_WKUP_TIME_OFFSET)
+#define SCRATCHPAD_WKUP_TIME_P OMAP343X_CTRL_BASE +
SCRATCHPAD_WKUP_TIME_OFFSET
+#define CM_ICLKEN_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_ICLKEN) +#define CM_ICLKEN_WKUP_P OMAP3430_CM_BASE + WKUP_MOD +
CM_ICLKEN
+#define CM_IDLEST_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_IDLEST) +#define CM_IDLEST_WKUP_P OMAP3430_CM_BASE + WKUP_MOD +
CM_IDLEST
.text
/* Function to aquire the semaphore in scratchpad */ ENTRY(lock_scratchpad_sem) @@ -183,7 +197,31 @@ api_params: .word 0x4, 0x0, 0x0, 0x1, 0x1 ENTRY(save_secure_ram_context_sz) .word . - save_secure_ram_context +#ifdef CONFIG_CPU_IDLE_PROF +ENTRY(omap3_sram_get_wkup_time)
- stmfd sp!, {lr} @ save registers on stack
ldr r0, wkup_time
ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
+ENTRY(omap3_sram_get_wkup_time_sz)
.word . - omap3_sram_get_wkup_time
+ENTRY(omap3_sram_get_sleep_time)
- stmfd sp!, {lr} @ save registers on stack
ldr r0, sleep_time
ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
+ENTRY(omap3_sram_get_sleep_time_sz)
.word . - omap3_sram_get_sleep_time
+ENTRY(omap3_sram_get_32k_tick)
- stmfd sp!, {lr} @ save registers on stack
ldr r0, sync_32k_timer
ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
+ENTRY(omap3_sram_get_32k_tick_sz)
.word . - omap3_sram_get_32k_tick
+#endif /*
- Forces OMAP into idle state
@@ -207,6 +245,13 @@ loop: cmp r1, #0x0 /* If context save is required, do that and execute wfi */ bne save_context_wfi
+#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, sleep_time
str r5, [r6]
+#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -224,8 +269,25 @@ loop: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, iclken_wkup
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r4, idlest_wkup
+wait_idlest:
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
bne wait_idlest
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, wkup_time
str r5, [r6]
+#endif bl wait_sdrc_ok
ldmfd sp!, {r0-r12, pc} @ restore regs and return
restore_es3: /*b restore_es3*/ @ Enable to debug restore code @@ -247,6 +309,23 @@ copy_to_sram: blx r1 restore: /* b restore*/ @ Enable to debug restore code +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, iclken_wkup_p
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r4, idlest_wkup_p
+wait_idlest1:
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
bne wait_idlest1
ldr r4, sync_32k_timer_p
ldr r5, [r4]
ldr r6, wkup_time_p
str r5, [r6]
+#endif
/* Check what was the reason for mpu reset and store the reason in r9*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost - In this case, we wont be here */
@@ -587,6 +666,12 @@ finished: mcr p15, 2, r10, c0, c0, 0 isb skip_l2_inval: +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, sleep_time
str r5, [r6]
+#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -603,6 +688,22 @@ skip_l2_inval: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, iclken_wkup
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r4, idlest_wkup
+wait_idlest2:
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
bne wait_idlest2
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, wkup_time
str r5, [r6]
+#endif bl wait_sdrc_ok /* restore regs and return */ ldmfd sp!, {r0-r12, pc} @@ -668,5 +769,25 @@ cache_pred_disable_mask: .word 0xFFFFE7FB control_stat: .word CONTROL_STAT +#ifdef CONFIG_CPU_IDLE_PROF +sync_32k_timer:
.word TIMER_32K_SYNC
+sync_32k_timer_p:
.word TIMER_32K_SYNC_P
+sleep_time:
.word SCRATCHPAD_SLEEP_TIME
+wkup_time:
.word SCRATCHPAD_WKUP_TIME
+wkup_time_p:
.word SCRATCHPAD_WKUP_TIME_P
+iclken_wkup:
.word CM_ICLKEN_WKUP
+iclken_wkup_p:
.word CM_ICLKEN_WKUP_P
+idlest_wkup:
.word CM_IDLEST_WKUP
+idlest_wkup_p:
.word CM_IDLEST_WKUP_P
+#endif ENTRY(omap34xx_cpu_suspend_sz) .word . - omap34xx_cpu_suspend diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 7dbc4a8..147456d 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -18,3 +18,8 @@ config CPU_IDLE_GOV_MENU bool depends on CPU_IDLE && NO_HZ default y
+config CPU_IDLE_PROF
bool
Should not this be something like bool "CPU idle profiling " so that this entry shows up in 'make menuconfig' ? and this should have dependency on ARCH_OMAP3 also ?
Thanks. Will fix it in V2.
Vishwa
depends on CPU_IDLE
default n
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0310ffa..a3e9db1 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -249,6 +249,11 @@ define_show_state_ull_function(usage) define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) +#ifdef CONFIG_CPU_IDLE_PROF +define_show_state_function(actual_latency) +define_show_state_function(sleep_latency) +define_show_state_function(wkup_latency) +#endif
define_one_state_ro(name, show_state_name); define_one_state_ro(desc, show_state_desc); @@ -256,7 +261,11 @@ define_one_state_ro(latency, show_state_exit_latency); define_one_state_ro(power, show_state_power_usage); define_one_state_ro(usage, show_state_usage); define_one_state_ro(time, show_state_time);
+#ifdef CONFIG_CPU_IDLE_PROF +define_one_state_ro(actual_latency, show_state_actual_latency); +define_one_state_ro(sleep_latency, show_state_sleep_latency); +define_one_state_ro(wkup_latency, show_state_wkup_latency); +#endif static struct attribute *cpuidle_state_default_attrs[] = { &attr_name.attr, &attr_desc.attr, @@ -264,6 +273,11 @@ static struct attribute *cpuidle_state_default_attrs[] = { &attr_power.attr, &attr_usage.attr, &attr_time.attr, +#ifdef CONFIG_CPU_IDLE_PROF
&attr_actual_latency.attr,
&attr_sleep_latency.attr,
&attr_wkup_latency.attr,
+#endif NULL };
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 55215cc..6474f6a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -43,6 +43,9 @@ struct cpuidle_state {
int (*enter) (struct cpuidle_device *dev, struct cpuidle_state *state);
+#ifdef CONFIG_CPU_IDLE_PROF
u32 actual_latency, sleep_latency, wkup_latency;
+#endif };
/* Idle State Flags */
1.7.0.4
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- Silesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Vishwa,
On 8/28/2010 12:08 AM, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BSvishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
FYI, Jean is currently working on using standard Linux probes in order to instrument CPUIdle / CPUfreq. I'm not sure it is doable, but it might better to use standard method to do that instead of purely OMAP3 specific stuff. This code will not scale easily on OMAP4.
Do you have a dump of the latency you measured do far?
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BSvishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
arch/arm/mach-omap2/cpuidle34xx.c | 58 ++++++++++++++++-- arch/arm/mach-omap2/pm.h | 5 ++ arch/arm/mach-omap2/sleep34xx.S | 121 +++++++++++++++++++++++++++++++++++++ drivers/cpuidle/Kconfig | 5 ++ drivers/cpuidle/sysfs.c | 16 +++++- include/linux/cpuidle.h | 3 + 6 files changed, 202 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 3d3d035..398bef8 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -25,6 +25,7 @@ #include<linux/sched.h> #include<linux/cpuidle.h>
+#include<linux/clk.h> #include<plat/prcm.h> #include<plat/irqs.h> #include<plat/powerdomain.h> @@ -86,6 +87,11 @@ static struct cpuidle_params cpuidle_params_table[] = { {1, 10000, 30000, 300000}, };
+#ifdef CONFIG_CPU_IDLE_PROF
Cannot you use _PROFILING instead? _PROF does not sound very meaningful for my point of view.
+static struct clk *clk_32k; +#define CONVERT_32K_USEC(lat) (lat * (USEC_PER_SEC/clk_get_rate(clk_32k))) +#endif
- static int omap3_idle_bm_check(void) { if (!omap3_can_sleep())
@@ -115,21 +121,28 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
- Called from the CPUidle framework to program the device to the
- specified target state selected by the governor.
*/
- static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+#ifdef CONFIG_CPU_IDLE_PROF
int idle_time, latency;
long sleep_time, wkup_time, total_sleep_time;
long preidle_time, postidle_time;
+#endif
current_cx_state = *cx;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
local_irq_disable(); local_fiq_disable();
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
preidle_time = omap3_sram_get_32k_tick();
+#endif pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state);
@@ -153,9 +166,39 @@ return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
postidle_time = omap3_sram_get_32k_tick();
+#endif local_irq_enable(); local_fiq_enable();
+#ifdef CONFIG_CPU_IDLE_PROF
sleep_time = omap3_sram_get_sleep_time();
wkup_time = omap3_sram_get_wkup_time();
/* take care of overflow */
if (postidle_time< preidle_time)
postidle_time += (u32) 0xffffffff;
if (wkup_time< sleep_time)
wkup_time += (u32) 0xffffffff;
idle_time = postidle_time - preidle_time;
total_sleep_time = wkup_time - sleep_time;
latency = idle_time - total_sleep_time;
sleep_time = omap3_sram_get_sleep_time();
wkup_time = omap3_sram_get_wkup_time();
/* calculate average latency after ignoring sprious ones */
if ((total_sleep_time> 0)&& (latency> state->actual_latency)
+&& (latency>= 0)) {
state->actual_latency = CONVERT_32K_USEC(latency);
latency = (sleep_time - preidle_time);
state->sleep_latency = CONVERT_32K_USEC(latency);
latency = postidle_time - wkup_time;
state->wkup_latency = CONVERT_32K_USEC(latency);
}
+#endif
}return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
@@ -423,7 +466,9 @@ int __init omap3_idle_init(void) struct omap3_processor_cx *cx; struct cpuidle_state *state; struct cpuidle_device *dev;
+#ifdef CONFIG_CPU_IDLE_PROF
static struct device dummy_device;
+#endif mpu_pd = pwrdm_lookup("mpu_pwrdm"); core_pd = pwrdm_lookup("core_pwrdm");
@@ -456,6 +501,9 @@ int __init omap3_idle_init(void)
omap3_cpuidle_update_states();
+#ifdef CONFIG_CPU_IDLE_PROF
clk_32k = clk_get(&dummy_device, "wkup_32k_fck");
+#endif if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", __func__); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 3de6ece..e62e87d 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -82,4 +82,9 @@ extern unsigned int save_secure_ram_context_sz; extern unsigned int omap24xx_cpu_suspend_sz; extern unsigned int omap34xx_cpu_suspend_sz;
+#ifdef CONFIG_CPU_IDLE_PROF +extern u32 omap3_sram_get_wkup_time(); +extern u32 omap3_sram_get_sleep_time(); +extern u32 omap3_sram_get_32k_tick(); +#endif #endif diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index d522cd7..8dec5ef 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -59,6 +59,20 @@ #define SDRC_DLLA_STATUS_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) #define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+#define TIMER_32K_SYNC_P 0x48320010 +#define TIMER_32K_SYNC OMAP2_L4_IO_ADDRESS(TIMER_32K_SYNC_P)
We are trying to get rid of all the direct usage of physical address and hard coded virtual address translation in the code. So please do not access the timer like that.
+#define SCRATCHPAD_SLEEP_TIME_OFFSET 0x9f8 +#define SCRATCHPAD_WKUP_TIME_OFFSET 0x9fc +#define SCRATCHPAD_SLEEP_TIME OMAP343X_CTRL_REGADDR(SCRATCHPAD_SLEEP_TIME_OFFSET) +#define SCRATCHPAD_WKUP_TIME OMAP343X_CTRL_REGADDR(SCRATCHPAD_WKUP_TIME_OFFSET) +#define SCRATCHPAD_WKUP_TIME_P OMAP343X_CTRL_BASE + SCRATCHPAD_WKUP_TIME_OFFSET
+#define CM_ICLKEN_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_ICLKEN) +#define CM_ICLKEN_WKUP_P OMAP3430_CM_BASE + WKUP_MOD + CM_ICLKEN +#define CM_IDLEST_WKUP OMAP34XX_CM_REGADDR(WKUP_MOD, CM_IDLEST) +#define CM_IDLEST_WKUP_P OMAP3430_CM_BASE + WKUP_MOD + CM_IDLEST
Same issue, do not use any macros based on OMAP2_L4_IO_ADDRESS translation macros.
/* Function to aquire the semaphore in scratchpad */ ENTRY(lock_scratchpad_sem).text
@@ -183,7 +197,31 @@ api_params: .word 0x4, 0x0, 0x0, 0x1, 0x1 ENTRY(save_secure_ram_context_sz) .word . - save_secure_ram_context +#ifdef CONFIG_CPU_IDLE_PROF +ENTRY(omap3_sram_get_wkup_time)
- stmfd sp!, {lr} @ save registers on stack
Not needed in your case, you are not using lr in your code.
ldr r0, wkup_time
ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
Not needed either.
+ENTRY(omap3_sram_get_wkup_time_sz)
.word . - omap3_sram_get_wkup_time
+ENTRY(omap3_sram_get_sleep_time)
- stmfd sp!, {lr} @ save registers on stack
Ditto
ldr r0, sleep_time
ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
Ditto
+ENTRY(omap3_sram_get_sleep_time_sz)
.word . - omap3_sram_get_sleep_time
+ENTRY(omap3_sram_get_32k_tick)
- stmfd sp!, {lr} @ save registers on stack
Ditto
ldr r0, sync_32k_timer
ldr r0, [r0]
- ldmfd sp!, {pc} @ restore regs and return
Ditto
+ENTRY(omap3_sram_get_32k_tick_sz)
.word . - omap3_sram_get_32k_tick
+#endif
Why do you need assembly code to do that? Cannot you access directly these variable from the C code?
/*
- Forces OMAP into idle state
@@ -207,6 +245,13 @@ loop: cmp r1, #0x0 /* If context save is required, do that and execute wfi */ bne save_context_wfi
+#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, sleep_time
str r5, [r6]
+#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -224,8 +269,25 @@ loop: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, iclken_wkup
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r4, idlest_wkup
+wait_idlest:
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
bne wait_idlest
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, wkup_time
str r5, [r6]
+#endif
What are you trying to do exactly in that case? Could you describe that a little bit?
Regards, Benoit
bl wait_sdrc_ok
restore_es3: /*b restore_es3*/ @ Enable to debug restore codeldmfd sp!, {r0-r12, pc} @ restore regs and return
@@ -247,6 +309,23 @@ copy_to_sram: blx r1 restore: /* b restore*/ @ Enable to debug restore code +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, iclken_wkup_p
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r4, idlest_wkup_p
+wait_idlest1:
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
bne wait_idlest1
ldr r4, sync_32k_timer_p
ldr r5, [r4]
ldr r6, wkup_time_p
str r5, [r6]
+#endif
/* Check what was the reason for mpu reset and store the reason in r9*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost - In this case, we wont be here */
@@ -587,6 +666,12 @@ finished: mcr p15, 2, r10, c0, c0, 0 isb skip_l2_inval: +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, sleep_time
str r5, [r6]
+#endif /* Data memory barrier and Data sync barrier */ mov r1, #0 mcr p15, 0, r1, c7, c10, 4 @@ -603,6 +688,22 @@ skip_l2_inval: nop nop nop +#ifdef CONFIG_CPU_IDLE_PROF
ldr r4, iclken_wkup
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r4, idlest_wkup
+wait_idlest2:
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
bne wait_idlest2
ldr r4, sync_32k_timer
ldr r5, [r4]
ldr r6, wkup_time
str r5, [r6]
+#endif bl wait_sdrc_ok /* restore regs and return */ ldmfd sp!, {r0-r12, pc} @@ -668,5 +769,25 @@ cache_pred_disable_mask: .word 0xFFFFE7FB control_stat: .word CONTROL_STAT +#ifdef CONFIG_CPU_IDLE_PROF +sync_32k_timer:
.word TIMER_32K_SYNC
+sync_32k_timer_p:
.word TIMER_32K_SYNC_P
+sleep_time:
.word SCRATCHPAD_SLEEP_TIME
+wkup_time:
.word SCRATCHPAD_WKUP_TIME
+wkup_time_p:
.word SCRATCHPAD_WKUP_TIME_P
+iclken_wkup:
.word CM_ICLKEN_WKUP
+iclken_wkup_p:
.word CM_ICLKEN_WKUP_P
+idlest_wkup:
.word CM_IDLEST_WKUP
+idlest_wkup_p:
.word CM_IDLEST_WKUP_P
+#endif ENTRY(omap34xx_cpu_suspend_sz) .word . - omap34xx_cpu_suspend diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 7dbc4a8..147456d 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -18,3 +18,8 @@ config CPU_IDLE_GOV_MENU bool depends on CPU_IDLE&& NO_HZ default y
+config CPU_IDLE_PROF
bool
depends on CPU_IDLE
default n
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0310ffa..a3e9db1 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -249,6 +249,11 @@ define_show_state_ull_function(usage) define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) +#ifdef CONFIG_CPU_IDLE_PROF +define_show_state_function(actual_latency) +define_show_state_function(sleep_latency) +define_show_state_function(wkup_latency) +#endif
define_one_state_ro(name, show_state_name); define_one_state_ro(desc, show_state_desc); @@ -256,7 +261,11 @@ define_one_state_ro(latency, show_state_exit_latency); define_one_state_ro(power, show_state_power_usage); define_one_state_ro(usage, show_state_usage); define_one_state_ro(time, show_state_time);
+#ifdef CONFIG_CPU_IDLE_PROF +define_one_state_ro(actual_latency, show_state_actual_latency); +define_one_state_ro(sleep_latency, show_state_sleep_latency); +define_one_state_ro(wkup_latency, show_state_wkup_latency); +#endif static struct attribute *cpuidle_state_default_attrs[] = { &attr_name.attr, &attr_desc.attr, @@ -264,6 +273,11 @@ static struct attribute *cpuidle_state_default_attrs[] = { &attr_power.attr, &attr_usage.attr, &attr_time.attr, +#ifdef CONFIG_CPU_IDLE_PROF +&attr_actual_latency.attr, +&attr_sleep_latency.attr, +&attr_wkup_latency.attr, +#endif NULL };
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 55215cc..6474f6a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -43,6 +43,9 @@ struct cpuidle_state {
int (*enter) (struct cpuidle_device *dev, struct cpuidle_state *state);
+#ifdef CONFIG_CPU_IDLE_PROF
u32 actual_latency, sleep_latency, wkup_latency;
+#endif };
/* Idle State Flags */
1.7.0.4
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Benoit,
On Fri, Aug 27, 2010 at 12:25 PM, Cousson, Benoit b-cousson@ti.com wrote:
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
FYI, Jean is currently working on using standard Linux probes in order to instrument CPUIdle / CPUfreq. I'm not sure it is doable, but it might better to use standard method to do that instead of purely OMAP3 specific stuff. This code will not scale easily on OMAP4.
The proposed code looks OK to me since it is exporting the cpuidle latency figures through the generic cpuidle driver (in drivers/cpuidle/sysfs.c, via /sys/devices/system/cpu/cpu0/cpuidle/state<n>/). Once that code gets approved I can (and will) add some trace points in it, so that all PM related events can be traced vs time.
Do you have a dump of the latency you measured do far?
Jean
Benoit,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Cousson, Benoit Sent: Friday, August 27, 2010 3:56 PM To: vishwanath.sripathy@linaro.org; Sripathy, Vishwanath Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org; Jean Pihet; Chalhoub, Nicole; Bour, Vincent Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi Vishwa,
On 8/28/2010 12:08 AM, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BSvishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling
CONFIG_CPU_IDLE_PROF
in .config). This information can be used to correctly configure cpu
idle
latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
FYI, Jean is currently working on using standard Linux probes in order to instrument CPUIdle / CPUfreq. I'm not sure it is doable, but it might better to use standard method to do that instead of purely OMAP3 specific stuff. This code will not scale easily on OMAP4.
Just discussed how to scale this for all OMAPs. Firstly we need to get this code to common place instead of tying it to OMAP3/OMAP4 specific low level code. Since on OMAP3, we can push C-functions on SRAM and for OMAP4 we don't have any limitation, all this code can be converted to C.
Vishwa is planning to attempt that in next version.
Regards, santosh
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
Kevin
Kevin,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Kevin Hilman Sent: Saturday, August 28, 2010 12:45 AM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
The challenge here is that we need to take time stamp at the fag end of CPU Idle which means we have no access to DDR, MMU/Caches are disabled etc (on OMAP3). So I am not sure if we will be able to use ftrace/perf kind of tools here. If we choose to exclude assembly code part for measurement, then we will be omitting major contributor to CPU Idle latency namely ARM context save/restoration part.
Also these calculations are done only when we enable CPUIDLE profiling feature. In the normal production system, these will not come into picture at all. So I am not sure latencies involved in these calculations are still an issue when we are just doing profiling.
Regards Vishwa
Kevin
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Vishwa,
On Mon, Aug 30, 2010 at 6:29 PM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
Kevin,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Kevin Hilman Sent: Saturday, August 28, 2010 12:45 AM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
The challenge here is that we need to take time stamp at the fag end of CPU Idle which means we have no access to DDR, MMU/Caches are disabled etc (on OMAP3). So I am not sure if we will be able to use ftrace/perf kind of tools here. If we choose to exclude assembly code part for measurement, then we will be omitting major contributor to CPU Idle latency namely ARM context save/restoration part.
Also these calculations are done only when we enable CPUIDLE profiling feature. In the normal production system, these will not come into picture at all. So I am not sure latencies involved in these calculations are still an issue >when we are just doing profiling.
There are two other issues when we use 32k timer for latency measurement.
<snip> + + /* take care of overflow */ + if (postidle_time < preidle_time) + postidle_time += (u32) 0xffffffff; + if (wkup_time < sleep_time) + wkup_time += (u32) 0xffffffff; + <snip>
1.We are checking postidle_time < preidle_time to find out whether there had been an over flow or not. There can be situations in which the timer overflows and still we have a greater postidle_time.
2. We are doing the correction for one overflow. What happens if the timer overflows for a second or third time. Can we keep track of the number of overflows and then do the correction accordingly?
Regards, Silesh
Regards Vishwa
Kevin
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-----Original Message----- From: Silesh C V [mailto:saileshcv@gmail.com] Sent: Tuesday, August 31, 2010 9:53 AM To: Sripathy, Vishwanath Cc: Kevin Hilman; vishwanath.sripathy@linaro.org; linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi Vishwa,
On Mon, Aug 30, 2010 at 6:29 PM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
Kevin,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Kevin Hilman Sent: Saturday, August 28, 2010 12:45 AM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
The challenge here is that we need to take time stamp at the fag end of CPU Idle
which means we have no access to DDR, MMU/Caches are disabled etc (on OMAP3). So I am not sure if we will be able to use ftrace/perf kind of tools here. If we choose to exclude assembly code part for measurement, then we will be omitting major contributor to CPU Idle latency namely ARM context save/restoration part.
Also these calculations are done only when we enable CPUIDLE profiling feature. In the normal production system, these will not come into picture at all. So I am
not sure latencies involved in these calculations are still an issue >when we are just doing profiling.
There are two other issues when we use 32k timer for latency measurement.
<snip> + + /* take care of overflow */ + if (postidle_time < preidle_time) + postidle_time += (u32) 0xffffffff; + if (wkup_time < sleep_time) + wkup_time += (u32) 0xffffffff; + <snip>
1.We are checking postidle_time < preidle_time to find out whether there had been an over flow or not. There can be situations in which the timer overflows and still we have a greater postidle_time.
- We are doing the correction for one overflow. What happens if the
timer overflows for a second or third time. Can we keep track of the number of overflows and then do the correction accordingly?
Unfortunately, there is no way to check if overflow happens more than once in 32k timer and as you said, theoretically it's possible that if timer overflows more than once, these calculation will wrong. Having said that, do you really see any usecase where system will idle for more than 37 hours in single cpuidle execution to cause timer overflow?
Vishwa
Regards, Silesh
Regards Vishwa
Kevin
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Aug 31, 2010 at 10:28 AM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
-----Original Message----- From: Silesh C V [mailto:saileshcv@gmail.com] Sent: Tuesday, August 31, 2010 9:53 AM To: Sripathy, Vishwanath Cc: Kevin Hilman; vishwanath.sripathy@linaro.org; linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi Vishwa,
On Mon, Aug 30, 2010 at 6:29 PM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
Kevin,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Kevin Hilman Sent: Saturday, August 28, 2010 12:45 AM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
The challenge here is that we need to take time stamp at the fag end of CPU Idle
which means we have no access to DDR, MMU/Caches are disabled etc (on OMAP3). So I am not sure if we will be able to use ftrace/perf kind of tools here. If we choose to exclude assembly code part for measurement, then we will be omitting major contributor to CPU Idle latency namely ARM context save/restoration part.
Also these calculations are done only when we enable CPUIDLE profiling feature. In the normal production system, these will not come into picture at all. So I am
not sure latencies involved in these calculations are still an issue >when we are just doing profiling.
There are two other issues when we use 32k timer for latency measurement.
<snip> + + /* take care of overflow */ + if (postidle_time < preidle_time) + postidle_time += (u32) 0xffffffff; + if (wkup_time < sleep_time) + wkup_time += (u32) 0xffffffff; + <snip>
1.We are checking postidle_time < preidle_time to find out whether there had been an over flow or not. There can be situations in which the timer overflows and still we have a greater postidle_time.
- We are doing the correction for one overflow. What happens if the
timer overflows for a second or third time. Can we keep track of the number of overflows and then do the correction accordingly?
Unfortunately, there is no way to check if overflow happens more than once in 32k timer and as you said, theoretically it's possible >that if timer overflows more than once, these calculation will wrong. Having said that, do you really see any usecase where system >will idle for more than 37 hours in single cpuidle execution to cause timer overflow?
I am not sure. But can we completely write off such a possibility ?
Regards, Silesh
Vishwa
Regards, Silesh
Regards Vishwa
Kevin
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-----Original Message----- From: saileshcv@gmail.com [mailto:saileshcv@gmail.com] On Behalf Of C V, Silesh Sent: Tuesday, August 31, 2010 12:27 PM To: Sripathy, Vishwanath Cc: Kevin Hilman; vishwanath.sripathy@linaro.org; linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
On Tue, Aug 31, 2010 at 10:28 AM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
-----Original Message----- From: Silesh C V [mailto:saileshcv@gmail.com] Sent: Tuesday, August 31, 2010 9:53 AM To: Sripathy, Vishwanath Cc: Kevin Hilman; vishwanath.sripathy@linaro.org; linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi Vishwa,
On Mon, Aug 30, 2010 at 6:29 PM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
Kevin,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Kevin Hilman Sent: Saturday, August 28, 2010 12:45 AM To: vishwanath.sripathy@linaro.org Cc: linux-omap@vger.kernel.org; linaro-dev@lists.linaro.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
The challenge here is that we need to take time stamp at the fag end of CPU
Idle
which means we have no access to DDR, MMU/Caches are disabled etc (on
OMAP3).
So I am not sure if we will be able to use ftrace/perf kind of tools here. If we
choose
to exclude assembly code part for measurement, then we will be omitting major contributor to CPU Idle latency namely ARM context save/restoration part.
Also these calculations are done only when we enable CPUIDLE profiling feature. In the normal production system, these will not come into picture at all. So I
am
not sure latencies involved in these calculations are still an issue >when we are
just
doing profiling.
There are two other issues when we use 32k timer for latency measurement.
<snip> + + /* take care of overflow */ + if (postidle_time < preidle_time) + postidle_time += (u32) 0xffffffff; + if (wkup_time < sleep_time) + wkup_time += (u32) 0xffffffff; + <snip>
1.We are checking postidle_time < preidle_time to find out whether there had been an over flow or not. There can be situations in which the timer overflows and still we have a greater postidle_time.
- We are doing the correction for one overflow. What happens if the
timer overflows for a second or third time. Can we keep track of the number of overflows and then do the correction accordingly?
Unfortunately, there is no way to check if overflow happens more than once in 32k
timer and as you said, theoretically it's possible >that if timer overflows more than once, these calculation will wrong. Having said that, do you really see any usecase where system >will idle for more than 37 hours in single cpuidle execution to cause timer overflow?
I am not sure. But can we completely write off such a possibility ?
I do not think it's a possibility. Also I believe that this problem is applicable even for system time as it uses 32k clock for maintaining system time.
Vishwa
Regards, Silesh
Vishwa
Regards, Silesh
Regards Vishwa
Kevin
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 10 Aug 27, Kevin Hilman wrote:
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
Kevin,
I agree. We discussed this a little in our weekly meeting. Vishwa's main concern was the lack of ability to instrument the last bit of SRAM code.
I have a feeling that even with caches on when we enter this code, we won't see too much variance in the latency to execute this bit of code. Vishwa is going to confirm that now. If that hypothesis is true, we can indeed move to using tracepoints in the idle path and use external tools to track latency.
Even if it isn't true, the rest of the idle path could still contain tracepoints.
Regards, Amit
-----Original Message----- From: linaro-dev-bounces@lists.linaro.org [mailto:linaro-dev- bounces@lists.linaro.org] On Behalf Of Amit Kucheria Sent: Thursday, September 02, 2010 1:26 PM To: Kevin Hilman Cc: linaro-dev@lists.linaro.org; linux-omap@vger.kernel.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
On 10 Aug 27, Kevin Hilman wrote:
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the
multiplications
and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non
trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
Kevin,
I agree. We discussed this a little in our weekly meeting. Vishwa's main concern was the lack of ability to instrument the last bit of SRAM code.
I have a feeling that even with caches on when we enter this code, we won't see too much variance in the latency to execute this bit of code. Vishwa is going to confirm that now. If that hypothesis is true, we can indeed move to using tracepoints in the idle path and use external tools to track latency.
There will be difference with and without caches but the delta latency will be constant with caches and without caches. Another important point is he lowest level code should be just profiled once and for worst CPU/BUS clock speed.
Even if it isn't true, the rest of the idle path could still contain tracepoints.
I also think this would be better approach considering a generic solution.
Regards, Santosh
Hi Amit, Santosh,
On Thu, Sep 2, 2010 at 10:11 AM, Shilimkar, Santosh santosh.shilimkar@ti.com wrote: ...
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
Kevin,
I agree. We discussed this a little in our weekly meeting. Vishwa's main concern was the lack of ability to instrument the last bit of SRAM code.
I have a feeling that even with caches on when we enter this code, we won't see too much variance in the latency to execute this bit of code. Vishwa is going to confirm that now. If that hypothesis is true, we can indeed move to using tracepoints in the idle path and use external tools to track latency.
I agree. Can you confirm this asap? I am looking at the instrumentation tracepoints now. I think it would be ideal to provide multiple tracepoints in both sleep and wake-up paths.
There will be difference with and without caches but the delta latency will be constant with caches and without caches. Another important point is he lowest level code should be just profiled once and for worst CPU/BUS clock speed.
Ok.
Even if it isn't true, the rest of the idle path could still contain tracepoints.
I am looking at the best way to introduce tracepoints in the low level code, in case it is needed.
I also think this would be better approach considering a generic solution.
Good!
Regards, Santosh
Jean
Jean,
-----Original Message----- From: linux-omap-owner@vger.kernel.org [mailto:linux-omap- owner@vger.kernel.org] On Behalf Of Jean Pihet Sent: Thursday, September 02, 2010 2:39 PM To: Shilimkar, Santosh Cc: Amit Kucheria; Kevin Hilman; linaro-dev@lists.linaro.org; linux- omap@vger.kernel.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi Amit, Santosh,
On Thu, Sep 2, 2010 at 10:11 AM, Shilimkar, Santosh santosh.shilimkar@ti.com wrote: ...
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
Kevin,
I agree. We discussed this a little in our weekly meeting. Vishwa's main concern was the lack of ability to instrument the last bit of SRAM code.
I have a feeling that even with caches on when we enter this code, we won't see too much variance in the latency to execute this bit of code. Vishwa is going to confirm that now. If that hypothesis is true, we can indeed move to using tracepoints in the idle path and use external tools to track latency.
I agree. Can you confirm this asap?
I did some profiling of assembly code on OMAP3630 board (ZOOM3). In worst case it takes around 3.28ms and best case around 2.93ms for mpu off mode. For MPU INACTIVE/RET, it is less than 30us. However as Kevin mentioned in other email, it would be better to find out a way to trace inside assembly code as well.
Regards Vishwa
I am looking at the instrumentation tracepoints now. I think it would be ideal to provide multiple tracepoints in both sleep and wake-up paths.
There will be difference with and without caches but the delta latency will be
constant with caches and without caches. Another important point is
he lowest level code should be just profiled once and for worst CPU/BUS clock
speed. Ok.
Even if it isn't true, the rest of the idle path could still contain tracepoints.
I am looking at the best way to introduce tracepoints in the low level code, in case it is needed.
I also think this would be better approach considering a generic solution.
Good!
Regards, Santosh
Jean
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Vishwa,
On Mon, Sep 6, 2010 at 1:15 PM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
I did some profiling of assembly code on OMAP3630 board (ZOOM3). In worst case it takes around 3.28ms and best case around 2.93ms for mpu off mode.
Can you give a bit more details? Which measurement has been taken (ASM only, sleep, wake-up ...?) and what are the significant figures?
For MPU INACTIVE/RET, it is less than 30us.
Mmh that is the resolution of the 32kHz timer, so I guess you get either 0 or 1 timer cycle depending when you start the measurement. IMO the 32kHz timer is too slow to measure those fast events.
However as Kevin mentioned in other email, it would be better to find out a way to trace inside assembly code as well.
OK that could be done but first I would like to make sure such a complication is needed.
Regards Vishwa
Jean
Hi Jean,
-----Original Message----- From: Jean Pihet [mailto:jean.pihet@newoldbits.com] Sent: Monday, September 06, 2010 9:53 PM To: Sripathy, Vishwanath Cc: Shilimkar, Santosh; Amit Kucheria; Kevin Hilman; linaro-dev@lists.linaro.org; linux-omap@vger.kernel.org Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement
Hi Vishwa,
On Mon, Sep 6, 2010 at 1:15 PM, Sripathy, Vishwanath vishwanath.bs@ti.com wrote:
I did some profiling of assembly code on OMAP3630 board (ZOOM3). In worst case
it takes around 3.28ms and best case around 2.93ms for mpu off mode. Can you give a bit more details? Which measurement has been taken (ASM only, sleep, wake-up ...?) and what are the significant figures?
Measurement has been done for save (as part of sleep sequence) and restore routine (part of wake up sequence) in assembly code. The above number indicates total time spent in save and restore of ARM context.
For MPU INACTIVE/RET, it is less than 30us.
Mmh that is the resolution of the 32kHz timer, so I guess you get either 0 or 1 timer cycle depending when you start the measurement. IMO the 32kHz timer is too slow to measure those fast events.
Yes I agree. When we use trace events, I believe it would be more accurate as it is based on ARM perf counters.
Vishwa
However as Kevin mentioned in other email, it would be better to find out a way to
trace inside assembly code as well. OK that could be done but first I would like to make sure such a complication is needed.
Regards Vishwa
Jean
Amit Kucheria amit.kucheria@linaro.org writes:
On 10 Aug 27, Kevin Hilman wrote:
vishwanath.sripathy@linaro.org writes:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
While I have many problems with the implementation details, I won't go into them because in general this is the wrong direction for kernel instrumentation.
This approach adds quite a bit overhead to the idle path itself. With all the reads/writes from/to the scratchpad(?) and all the multiplications and divides in every idle path, as well as the wait-for-idlest in both the sleep and resume paths. The additional overhead added is non trivial.
Basically, I'd like get away from custom instrumentation and measurement coded inside the kernel itself. This kind of code never stops growing and morphing into ugliness, and rarely scales well when new SoCs are added.
With ftrace/perf, we can add tracepoints at specific points and use external tools to extract and analyze the delays, latencys etc.
The point is to keep the minimum possible in the kernel: just the tracepoints we're interested in. The rest (calculations, averages, analysis, etc.) does not need to be in the kernel and can be done easier and with more powerful tools outside the kernel.
Kevin,
I agree. We discussed this a little in our weekly meeting. Vishwa's main concern was the lack of ability to instrument the last bit of SRAM code.
I have a feeling that even with caches on when we enter this code, we won't see too much variance in the latency to execute this bit of code. Vishwa is going to confirm that now. If that hypothesis is true, we can indeed move to using tracepoints in the idle path and use external tools to track latency.
Even if it isn't true, the rest of the idle path could still contain tracepoints.
Yes.
As Santosh pointed out, that low-level code be a fixed latency and can likely be profiled once.
That being said, it should still be possible to trace the low-level code. Jean Pihet and I discussed implementing a "fake" tracepoint in SRAM during that part of the execution which could then be copied out later. This would minimize the custom tracing code and allow us to continue to use userspace tools to analyze the entire path.
Jean is investigating this now.
Kevin
On 10 Aug 28, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
arch/arm/mach-omap2/cpuidle34xx.c | 58 ++++++++++++++++-- arch/arm/mach-omap2/pm.h | 5 ++ arch/arm/mach-omap2/sleep34xx.S | 121 +++++++++++++++++++++++++++++++++++++ drivers/cpuidle/Kconfig | 5 ++ drivers/cpuidle/sysfs.c | 16 +++++- include/linux/cpuidle.h | 3 + 6 files changed, 202 insertions(+), 6 deletions(-)
Vishwa,
You should perhaps cc Len Brown and LKML for V2 to get acceptance for the new counters in cpuidle
Regards, Amit
Amit Kucheria amit.kucheria@linaro.org writes:
On 10 Aug 28, vishwanath.sripathy@linaro.org wrote:
From: Vishwanath BS vishwanath.sripathy@linaro.org
This patch has instrumentation code for measuring latencies for various CPUIdle C states for OMAP. Idea here is to capture the timestamp at various phases of CPU Idle and then compute the sw latency for various c states. For OMAP, 32k clock is chosen as reference clock this as is an always on clock. wkup domain memory (scratchpad memory) is used for storing timestamps. One can see the worstcase latencies in below sysfs entries (after enabling CONFIG_CPU_IDLE_PROF in .config). This information can be used to correctly configure cpu idle latencies for various C states after adding HW latencies for each of these sw latencies. /sys/devices/system/cpu/cpu0/cpuidle/state<n>/actual_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/sleep_latency /sys/devices/system/cpu/cpu0/cpuidle/state<n>/wkup_latency
THis patch is tested on OMAP ZOOM3 using kevin's pm branch.
Signed-off-by: Vishwanath BS vishwanath.sripathy@linaro.org Cc: linaro-dev@lists.linaro.org
arch/arm/mach-omap2/cpuidle34xx.c | 58 ++++++++++++++++-- arch/arm/mach-omap2/pm.h | 5 ++ arch/arm/mach-omap2/sleep34xx.S | 121 +++++++++++++++++++++++++++++++++++++ drivers/cpuidle/Kconfig | 5 ++ drivers/cpuidle/sysfs.c | 16 +++++- include/linux/cpuidle.h | 3 + 6 files changed, 202 insertions(+), 6 deletions(-)
You should perhaps cc Len Brown and LKML for V2 to get acceptance for the new counters in cpuidle
Before a v2, we need to have some discussions about the general direction of how to best do PM instrumentation. As I said in my review of this patch[1], I am not a fan of the current approach.
Kevin
[1] http://marc.info/?l=linux-omap&m=128293652216542&w=2
NOTE: This post may not have made it to linaro-dev since it's moderated, an I wasn't subscribed when I posted this, but am now.