Linux内核suspend状态

Linux内核支持多种类型的睡眠状态,通过设置不同的模块进入低功耗模式来达到省电功能。目前存在四种模式:suspend to idle、power-on standby(Standby)、suspend to ram(STR)和sudpend to disk(Hibernate),分别对应ACPI状态的S0、S1、S3和S4。

Suspend to idle完全是软件相关的并且尽量将CPU维持在深度idle状态。

Power-on standby设置设备进入低功耗模式并且关闭所有non-boot CPU。

Suspend to ram就更进一步,关闭所有CPU并且设置RAM进入自刷新模式。(在HiKey的实际测试中,boot CPU是没有关闭的!实际上这里也没有standby,mem和standby基本上没有区别。)

Suspend to disk是最省功耗的模式,通过尽可能的关闭设备,包括RAM。RAM的数据会被写入磁盘中,在resume的时候读回到RAM。

下面用STR表示Suspend to RAM,STI表示Suspend to Idle。

详情请参考:http://www.linaro.org/blog/suspend-to-idle/

STR 和STI区别

写入/sys/power/state不同字符串,可以让系统进入不同睡眠状态。

#define PM_SUSPEND_ON        ((__force suspend_state_t) 0)  正常工作状态
#define PM_SUSPEND_FREEZE    ((__force suspend_state_t) 1) 对应suspend to idle
#define PM_SUSPEND_STANDBY    ((__force suspend_state_t) 2)  对应power-on standby
#define PM_SUSPEND_MEM        ((__force suspend_state_t) 3)  对应suspend to idle
#define PM_SUSPEND_MIN        PM_SUSPEND_FREEZE
#define PM_SUSPEND_MAX        ((__force suspend_state_t) 4)  对应suspend to disk,即hibernate

针对state sysfs节点的写入,最终会进入到state_store这个函数,将字符串转换成上表中不同状态。

state_store(kernel/power/main.c)
    -->pm_suspend (kernel/power/suspend.c) 处理除freeze、standby、mem三种类型suspend
        -->enter_state  在进入睡眠之前,做一些准备工作
            -->suspend_devices_and_enter 
                -->suspend_enter  这里才是freeze与standby/mem区别所在。
    -->hibernate  进入suspend to disk流程

STR和STI的最主要区别就是下面一段代码:

static int suspend_enter(suspend_state_t state, bool *wakeup)
{

/*
     * PM_SUSPEND_FREEZE equals
     * frozen processes + suspended devices + idle processors.
     * Thus we should invoke freeze_enter() soon after
     * all the devices are suspended.
     */
    if (state == PM_SUSPEND_FREEZE) {  如果要进入freeze状态,就会执行此段代码。
        trace_suspend_resume(TPS("machine_suspend"), state, true);
        freeze_enter();
        trace_suspend_resume(TPS("machine_suspend"), state, false);
        goto Platform_wake;  在执行结束跳转到Platform_wake,中间一段绿色代码将会被跳过。所以说freeze和standby、mem相比,多了freeze_enter,少了对non-boot CPUs、arch、syscore的操作。
    }

error = disable_nonboot_cpus();
    if (error || suspend_test(TEST_CPUS)) {
        log_suspend_abort_reason("Disabling non-boot cpus failed");
        goto Enable_cpus;
    }

arch_suspend_disable_irqs();
    BUG_ON(!irqs_disabled());

error = syscore_suspend();
    if (!error) {
        *wakeup = pm_wakeup_pending();
        if (!(suspend_test(TEST_CORE) || *wakeup)) {
            trace_suspend_resume(TPS("machine_suspend"),
                state, true);
            error = suspend_ops->enter(state);
            trace_suspend_resume(TPS("machine_suspend"),
                state, false);
            events_check_enabled = false;
        } else if (*wakeup) {
            pm_get_active_wakeup_sources(suspend_abort,
                MAX_SUSPEND_ABORT_LEN);
            log_suspend_abort_reason(suspend_abort);
            error = -EBUSY;
        }
        syscore_resume();
    }

arch_suspend_enable_irqs();
    BUG_ON(irqs_disabled());

Enable_cpus:
    enable_nonboot_cpus();

Platform_wake:
    platform_resume_noirq(state);
    dpm_resume_noirq(PMSG_RESUME);

}

下面分析一些每个子系统的suspend/resume。

整个suspend可以分为若干阶段,每个阶段函数—>关键节点Trace—>analyze_suspend.py解析Trace—>根据Trace时间画出Timeline图表

这样就可以分析出总的时间差异,每个阶段差异,甚至一个设备suspend/resume、一个子系统suspend/resume的时间差异。

freeze_enter

platform_suspend_begin/patform_resume_end

suspend_console/resume_console

dpm_suspend_start/dpm_resume_end

dpm_suspend_noirq/dpm_resume_noirq

disable_nonboot_cpus/enable_nonboot_cpus

arch_suspend_disable_irqs/arch_suspend_enable_irqs

syscore_suspend/syscore_resume

如何让HiKey进入STR/STI并唤醒?

可以通过配置GPIO作为唤醒源,或者通过RTC作为唤醒源,延时一定时间来唤醒。

检查是否存在/sys/class/rtc/rtc0/wakealarm,入不存在则需要打开CONFIG_RTC_DRV_PL031。

写入wakealarm的参数,表示在多少秒之后resume唤醒,退出suspend。

写mem进入state,是系统进入suspend流程。

adb root && adb remount
adb shell "echo +10 > /sys/class/rtc/rtc0/wakealarm && echo mem > /sys/power/state"

suspend/resume的latency分析手段

analyze_suspend.py v3.0

在kernel的scripts中,这个工具可以帮助内核和OS开发者优化suspend/resume时间。

在打开一系列内核选项之后,此工具就可以执行suspend操作,然后抓取dmesg和ftrace数据知道resume结束。

这些数据会按照时间线显示每个设备,并且显示占用最多suspend/resume时间的设备或者子系统的调用关系详图。

执行工具后,会根据时间生成一个子目录,里面包含:html、dmesg和原始ftrace文件。

下面简单看一下工具选项:

Options:
  [general]
    -h          Print this help text
    -v          Print the current tool version
    -verbose    Print extra information during execution and analysis
    -status     Test to see if the system is enabled to run this tool
    -modes      List available suspend modes  显示当前支持的suspend模式
    -m mode     Mode to initiate for suspend ['freeze', 'mem', 'disk'] (default: mem)  设置进入何种模式的suspend
    -rtcwake t  Use rtcwake to autoresume after <t> seconds (default: disabled)  使用rtc来唤醒,参数是间隔时间
  [advanced]
    -f          Use ftrace to create device callgraphs (default: disabled)  基于ftrace生成调用关系图
    -filter "d1 d2 ..." Filter out all but this list of dev names
    -x2         Run two suspend/resumes back to back (default: disabled)
    -x2delay t  Minimum millisecond delay <t> between the two test runs (default: 0 ms)
    -postres t  Time after resume completion to wait for post-resume events (default: 0 S)
    -multi n d  Execute <n> consecutive tests at <d> seconds intervals. The outputs will
                be created in a new subdirectory with a summary page.
  [utilities]
    -fpdt       Print out the contents of the ACPI Firmware Performance Data Table
    -usbtopo    Print out the current USB topology with power info
    -usbauto    Enable autosuspend for all connected USB devices
  [android testing]
    -adb binary Use the given adb binary to run the test on an android device.  参数需要给出adb路径,工具就会对Android设备进行测试,并将结果pull出来。有一点需要注意,在此之前确保adb具有root权限。
                The device should already be connected and with root access.
                Commands will be executed on the device using "adb shell"
  [re-analyze data from previous runs] 针对之前测试数据重新分析
    -ftrace ftracefile  Create HTML output using ftrace input
    -dmesg dmesgfile    Create HTML output using dmesg (not needed for kernel >= 3.15)
    -summary directory  Create a summary of all test in this dir

在了解了工具使用方法之后,就可以进行相关测试了。

Android

./analysze_suspend.py –modes –adb /usr/bin/adb获取当前系统支持的suspend状态。

['freeze', 'mem']

1.Android上测试STR,suspend/resume共5次,每次间隔20秒。

./analyze_suspend.py -adb  /usr/bin/adb -rtcwake 10 -multi 5 20 -f -m mem

2.Android上测试STI,suspend/resume共10次,每次间隔5秒。

./analyze_suspend.py -adb  /usr/bin/adb -rtcwake 10 -multi 5 20 -f -m freeze

测试结果可以在如下获得:

https://github.com/arnoldlu/common-use/tree/master/tools/analyze_suspend/hikey_test

存在的问题:analyze_suspend.py不支持Android的rtcwakeup和callgraph。已经在如下fix:

https://github.com/arnoldlu/common-use/blob/master/tools/analyze_suspend/analyze_suspend.py

总体对比

下面是HiKey上测试结果,可以看出两个数据都不够稳定。mem的suspend和resume平均值都比较高。

freeze相比mem的suspend/resume平均值提高了304.3ms/613.5ms。

是否suspend CPU

对比如下两幅图,明显看出mem类型的suspend关闭了除CPU0之外的所有CPU;而freeze则没有关闭任何CPU。

non-boot CPUs的suspend/resume时间就达到300ms/200ms。

同时从log中也可以看出mem和freeze的主要区别就在于是否disabling/enabling non-boot CPU。其他设备和子系统的suspend/resume时间基本一致。

[ 3385.642962] PM: suspend entry 1970-01-01 00:57:30.580909763 UTC
[ 3385.649165] PM: Syncing filesystems ... done.
[ 3385.661349] Freezing user space processes ...
[ 3385.671207] dwc2 f72c0000.usb: dwc2_hsotg_ep_stop_xfr: timeout DOEPCTL.EPDisable
[ 3385.678933] dwc2 f72c0000.usb: GINNakEff triggered
[ 3385.685718] (elapsed 0.019 seconds) done.
[ 3385.689860] Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done.
[ 3385.700092] Suspending console(s) (use no_console_suspend to debug)
[ 3385.736020] PM: suspend of devices complete after 27.195 msecs
[ 3385.740811] PM: late suspend of devices complete after 4.765 msecs
[ 3385.743919] PM: noirq suspend of devices complete after 3.090 msecs
Disabling and Enabling non-boot CPUs
[ 3386.209126] PM: noirq resume of devices complete after 1.865 msecs
[ 3386.212066] PM: early resume of devices complete after 2.460 msecs
[ 3386.234729] mmc_host mmc0: Bus speed (slot 0) = 24800000Hz (slot req 400000Hz, actual 400000HZ div = 31)
[ 3386.311480] mmc_host mmc0: Bus speed (slot 0) = 51756522Hz (slot req 52000000Hz, actual 51756522HZ div = 0)
[ 3386.410411] mmc_host mmc2: Bus speed (slot 0) = 24800000Hz (slot req 400000Hz, actual 400000HZ div = 31)
[ 3386.458232] mmc_host mmc2: Bus speed (slot 0) = 24800000Hz (slot req 25000000Hz, actual 24800000HZ div = 0)
[ 3386.458729] PM: resume of devices complete after 246.646 msecs
[ 3386.818770] Restarting tasks ...
[ 3386.827026] done.
[ 3386.844139] PM: suspend exit 1970-01-01 00:57:40.624589167 UTC

[ 3471.760265] PM: Syncing filesystems ... done.
[ 3471.771897] Freezing user space processes ...
[ 3471.780407] dwc2 f72c0000.usb: dwc2_hsotg_ep_stop_xfr: timeout DOEPCTL.EPDisable
[ 3471.788105] dwc2 f72c0000.usb: GINNakEff triggered
[ 3471.794916] (elapsed 0.018 seconds) done.
[ 3471.799078] Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done.
[ 3471.809320] Suspending console(s) (use no_console_suspend to debug)
[ 3471.847947] PM: suspend of devices complete after 29.905 msecs
[ 3471.852473] PM: late suspend of devices complete after 4.497 msecs
[ 3471.855611] PM: noirq suspend of devices complete after 3.120 msecs

[ 3481.034722] PM: noirq resume of devices complete after 1.945 msecs
[ 3481.037992] PM: early resume of devices complete after 2.694 msecs
[ 3481.062803] mmc_host mmc0: Bus speed (slot 0) = 24800000Hz (slot req 400000Hz, actual 400000HZ div = 31)
[ 3481.137795] mmc_host mmc0: Bus speed (slot 0) = 51756522Hz (slot req 52000000Hz, actual 51756522HZ div = 0)
[ 3481.234796] mmc_host mmc2: Bus speed (slot 0) = 24800000Hz (slot req 400000Hz, actual 400000HZ div = 31)
[ 3481.278601] mmc_host mmc2: Bus speed (slot 0) = 24800000Hz (slot req 25000000Hz, actual 24800000HZ div = 0)
[ 3481.279396] PM: resume of devices complete after 241.388 msecs
[ 3481.358513] Restarting tasks ... done.
[ 3481.377766] PM: suspend exit 1970-01-01 00:59:15.332218333 UTC

resume_console节省时间

对比resume_console可以发现,mem要比freeze多210ms。

Ubuntu

此工具在Ubuntu上显示了更强大的功能。

支持了callgraph功能之后,更能清晰地分析每个设备或者子系统的suspend/resume占用的时间。

sudo ./analyze_suspend.py -rtcwake 10 -multi 5 20 -f -m mem
sudo ./analyze_suspend.py -rtcwake 10 -multi 5 20 -f -m freeze

在对比两种不同suspend模式后,发现freeze花费的时间要比mem少。这也符合预期,但是没有功耗数据?_?。

下面着重分析一下如何基于此工具分析。

工具界面总体分析

最上面显示Kernel Suspend Time和Kernel Resume Time,可以从总体上查看是否有回退或者进步。

再下面是一些缩放按钮。

然后就是基于timeline的图表,比对颜色示意图,可以清晰看出suspend prepare、suspend、suspend late、suspend irq、suspend machine、resume machine、resume irq、resume early、resume和resume complete的分布。

最下面是每个模块、子系统的详细函数调用图以及开始时间、消耗时间。

子系统、模块详细分析

选中一个模块,会在最下面显示详细的模块在suspend/resume各个阶段消费的时间,以及函数调用关系图。

缩放查看细节

ZOOM IN放大,ZOOMOUT缩小,ZOOM 1:1恢复原始尺寸。

通过在timeline图表,放大可以查看到更小的模块消耗的时间。从宏观到模块,再到函数消耗时间,逐步细化,很有利于分析。

如果发现某个函数占用时间较大,可以逐级展开。知道发现最终占用较大的函数,发现问题所在。

参考文档

Power Management Support in Hikey (suspend-resume):http://www.96boards.org/forums/topic/power-management-support-in-hikey-suspend-resume/#gsc.tab=0

Suspend to Idle:http://www.linaro.org/blog/suspend-to-idle/

Suspend and Resume:https://01.org/zh/suspendresume

SuspendAndResume github:https://github.com/arnoldlu/suspendresume

Linux电源管理(6)_Generic PM之Suspend功能:http://www.wowotech.net/pm_subsystem/suspend_and_resume.html

Suspend to RAM和Suspend to Idle分析,以及在HiKey上性能对比的更多相关文章

  1. Suspend to RAM和Suspend to Idle分析,以及在HiKey上性能对比【转】

    转自:https://www.cnblogs.com/arnoldlu/p/6253665.html 测试环境:AOSP 7.1.1+Kernel 4.4.17 HW:HiKey Ubuntu 14. ...

  2. Jconsole与Jmx 分析JVM状况(上) 转

    出处:Jconsole与Jmx 分析JVM状况(上) JVM 平台提供 Mbeans 说明 在 Java 2 平台 5.0 以上版本,有一组 API 可以让 Java 应用程序和允许的工具监视和管理  ...

  3. 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)

    如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...

  4. ArrayList和LinkedList的几种循环遍历方式及性能对比分析(转)

    主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论. 通过本文你可以 ...

  5. ArrayList和LinkedList的几种循环遍历方式及性能对比分析

    最新最准确内容建议直接访问原文:ArrayList和LinkedList的几种循环遍历方式及性能对比分析 主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性 ...

  6. HBase在单Column和多Column情况下批量Put的性能对比分析

    作者: 大圆那些事 | 文章可以转载,请以超链接形式标明文章原始出处和作者信息 网址: http://www.cnblogs.com/panfeng412/archive/2013/11/28/hba ...

  7. 使用 Web Tracing Framework 分析富 JS 应用的性能

    来自谷歌的 Web Tracing Framework 包含一组工具和脚本,用于 JavaScript 相关代码的性能分析.它是重 JavaScript 应用程序的理想选择,而 JavaScript ...

  8. ArrayList和LinkedList的几种循环遍历方式及性能对比分析(转载)

    原文地址: http://www.trinea.cn/android/arraylist-linkedlist-loop-performance/ 原文地址: http://www.trinea.cn ...

  9. ArrayList和LinkedList遍历方式及性能对比分析

    ArrayList和LinkedList的几种循环遍历方式及性能对比分析 主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayLis ...

随机推荐

  1. React-Native学习系列(二) Image和ScrollView

    接下来,我们接着(一)继续讲,今天我们学习的是Image组件和ScrollView组件. Image组件 Image:一个用于显示多种不同类型图片的React组件.那么要如何使用呢? 引入本地图片: ...

  2. 学习笔记--C#深复制和浅复制

    参考博客:http://www.cnblogs.com/nliao/archive/2012/11/18/2776114.html 例子网上都有很多,我也就不列了. 其实很久以前就明白了这两者的区别, ...

  3. 【译】Asp.net mvc 使用ITextSharp PDF to HTML (解决img标签问题)

    前言:因项目需求,需要将HTML代码转成PDF.大致上已经实现了,可以是发现使用ITextSharp(我现在的版本是5.5.9)的时候,img标签中的src只能跟绝对路径. 在百度上找了一个上午,有一 ...

  4. zip函数-Python 3

    zip函数接受任意多个(包括0个和1个)序列作为参数,返回一个tuple列表. zip函数在获取数据后,生成字典(dict)时比较好用. for examples: # Code based on P ...

  5. 航旅事业群面试(li)

    一.JVM 1.如何观察垃圾回收? 2.JAVA应用的JVM参数调优? 3.举例说明你所知道的JVM profile方法? 4.GC tunning实战.假如你是一个大型网站的总架构师,有次web应用 ...

  6. Mybatis配置一对多的关联关系(五)

    问题:是查询一个部门中的员工? 一.web项目构架 二.lib文件的jar 三.配置大小配置和该工具类 1大配置mybatis-config.xml <?xml version="1. ...

  7. IoC组件~Autofac将多实现一次注入,根据别名Resove实例

    回到目录 对于IoC容器来说,性能最好的莫过于Autofac了,而对于灵活度来说,它也是值得称赞的,为了考虑系统的性能,我们经常是在系统初始化于将所有依赖注册到容器里,当需要于根据别名把实现拿出来,然 ...

  8. js picker webapp仿ios picker

    iosselect 在webapp下的一个picker组件 可以轻松实现各类选择器效果.比如地区选择 时间选择 日期选择等. 可以定制依赖关系,可以定制选择层级,可以定制高度 展示项数.无论你是px还 ...

  9. 5.1 JS中Object类型

    1.Object类型是引用类型中的一种. 2.创建Object实例(对象)的方式: 方式1:使用new操作符,后面跟上Object构造函数.如: var obj = new Object();//创建 ...

  10. GitHub + VSTS 开源代码双向同步

    GitHub已经是全球开源代码的大本营了,通过以下统计你可以看到仅仅javascript在github就有超过32万个活动的repo.很多开发人员都会把自己的一部分代码分享到github上进行开源,一 ...