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. 在docker中运行ASP.NET Core Web API应用程序

    本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过程中,也会对docker的使用进行一些简单的描述.对于.NET Cor ...

  2. Ionic2系列——使用DeepLinker实现指定页面URL

    Ionic2使用了近似原生App的页面导航方式,并不支持Angular2的路由.这种方式在开发本地App的时候比较方便,但如果要用来开发纯Web页面就有点问题了,这种情况下Angular2的route ...

  3. JQuery的核心的一些方法[扒来的]

    JQuery的核心的一些方法 each(callback) '就像循环 $("Element").length; ‘元素的个数,是个属性 $("Element" ...

  4. mysql 安装

    编译环境yum install gcc gcc-c++ ncurses-devel perl 依赖yum install boost boost-devel boost-doc 安装cmake wge ...

  5. xinetd cpu 100%

    今天,有个给客户试用的环境出现xinetd cpu 100%,而且连续运行很长时间了.之前也有环境发生过,今天排查解决了三四个问题,实在是查的身体都不舒服了,还没时间查这个问题... 知道的求解...

  6. Sencha ExtJS 6 Widget Grid 入门

    最近由于业务需要,研究了一下Sencha ExtJS 6 ,虽然UI和性能上据相关资料说都有提升,但是用起来确实不太顺手,而且用Sencha cmd工具进行测试和发布,很多内部细节都是隐藏的,出了问题 ...

  7. 改变你代码习惯的ES6

    最近读阮一峰老师的ES6标准入门,让我感觉到了ES6的强大之处,读书之余整理了一些笔记,因为边读边记录的,所以可能会比较杂乱. ECMAScript和Javascript的关系 1996年11月,Ja ...

  8. 报表或BI的价值在哪?

    报表或者bi的价值在哪?这已经是十几年的问题啦! 为什么要解释这个并不新鲜的问题,是因为当一个两个问我的时候,并没有在意,被问的多了,觉得这问题并没有过时. 数据挖掘和建模分析,其价值很容易说出来,因 ...

  9. JavaScript学习(零)前引

    一)概述 JavaScript是一个面向web的编程语言,一种解释性语言,边执行边解释.也是一种基于对象(Object)和事件驱动(EventDriven)的,安全性好的脚本语言,语法和java类似. ...

  10. Scala For Java的一些参考

          变量 String yourPast = "Good Java Programmer"; val yourPast : String = "Good Java ...