Re: [PATCH] OMAP CPUIDLE: CPU Idle latency measurement

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 ?

> +       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


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux