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. asp.net web api 的版本升级到 2.2的记录

    asp.net web api 的版本 升级到 2.2的记录 asp.net web api 2.2相比1.0提升了不少 而且其中最重要的就是有了在线文档的自动字段注释的功能 再也不用写详细的字段说明 ...

  2. Android中使用ListView实现分页刷新(线程休眠模拟)

    当要显示的数据过多时,为了更好的提升用户感知,在很多APP中都会使用分页刷新显示,比如浏览新闻,向下滑动到当前ListView的最后一条信息(item)时,会提示刷新加载,然后加载更新后的内容.此过程 ...

  3. 详解java定时任务

    在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现.下面LZ就其原理.实例以及Timer缺陷三个方面来解析JavaTimer定时器. ...

  4. MP3文件信息批量更改器

    以前(估计是2003年)编写一个MP3文件信息批量更改器MP3TagChanger,现放上来参考.(VB6编码) 使用方法很简单,会Winamp或者千千静听的就懂使用. http://pan.baid ...

  5. Atitti.dw cc 2015 绿色版本安装总结

    Atitti.dw cc 2015 绿色版本安装总结 1.1. 安装程序无法初始化.请下载adobe Support Advisor检测该问题.1 1.1.1. Adobe Application M ...

  6. C#语言基础——集合(ArrayList集合)

    集合及特殊集合 集合的基本信息: System.Collections 命名空间包含接口和类,这些接口和类定义各种对象(如列表.队列.位数组.哈希表和字典)的集合.System.Collections ...

  7. 编译protobuf的jar文件

    1.准备工作 需要到github上下载相应的文件,地址https://github.com/google/protobuf/releases protobuf有很多不同语言的版本,因为我们需要的是ja ...

  8. 0039 Java学习笔记-多线程-线程控制、线程组

    join线程 假如A线程要B线程去完成一项任务,在B线程完成返回之前,不进行下一步执行,那么就可以调用B线程的join()方法 join()方法的重载: join():等待不限时间 join(long ...

  9. [Hadoop in Action] 第1章 Hadoop简介

    编写可扩展.分布式的数据密集型程序和基础知识 理解Hadoop和MapReduce 编写和运行一个基本的MapReduce程序   1.什么是Hadoop   Hadoop是一个开源的框架,可编写和运 ...

  10. easyUI的基础布局easyui-accordion

    ---恢复内容开始--- <html> <head> <meta charset="UTF-8"> <title>树状图</t ...