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

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

 




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


[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