> -----Original Message----- > From: linux-omap-owner@xxxxxxxxxxxxxxx [mailto:linux-omap- > owner@xxxxxxxxxxxxxxx] On Behalf Of C V, Silesh > Sent: Friday, August 27, 2010 3:28 PM > To: vishwanath.sripathy@xxxxxxxxxx > Cc: linux-omap@xxxxxxxxxxxxxxx; linaro-dev@xxxxxxxxxxxxxxxx > Subject: Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement > > g 28, 2010 at 3:38 AM, <vishwanath.sripathy@xxxxxxxxxx> wrote: > > From: Vishwanath BS <vishwanath.sripathy@xxxxxxxxxx> > > > > 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@xxxxxxxxxx> > > Cc: linaro-dev@xxxxxxxxxxxxxxxx > > --- > > 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@xxxxxxxxxxxxxxx > > 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@xxxxxxxxxxxxxxx > 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html