前些时间,在学习android的耗电问题。不可避免,会涉及到wakelock的部分。

在root权限下,可以通过查看/d/wakeup_sources来查看wakelock的情况。

name                 active_count    event_count wakeup_count    expire_count    active_since    total_time  max_time    last_change prevent_suspend_time
HVDCPD_WL                           18      18      0       0       0       100     11      76513       0
ipc000000ef_sensors@1.0-ser        2536        2891        0       0       0       483     6       85772       0
ipc000000ee_sensors@1.0-ser        3       3       0       0       0       0       0       45133       0
ipc000000ed_sensors@1.0-ser        9       9       0       0       0       8       6       84263       0
bluetooth_timer                     64      64      0       0       0       3213        3001        69776       0
hal_bluetooth_lock                  1       1       0       0       0       79      79      33380       0
SMD_TTY_APPS_RIVA_BT_ACL_RA         0       0       0       0       0       0       0       33297       0
APPS_RIVA_BT_ACL                    0       0       0       0       0       0       0       33297       0
SMD_TTY_APPS_RIVA_BT_CMD_RA         109     114     0       0       0       4       0       69775       0

那后面就通过code来分析一下这个节点,也看看什么参数对分析耗电比较重要。

1. 节点的创建

根据节点的名称,先查看节点生成的文件为kernel/msm-3.18/drivers/base/power/wakeup.c

static int __init wakeup_sources_debugfs_init(void)
{wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops);    //创建"/d/wakeup_sources"。return 0;
}

2.节点操作的相关函数

static const struct file_operations wakeup_sources_stats_fops = {.owner = THIS_MODULE,.open = wakeup_sources_stats_open,.read = seq_read,.llseek = seq_lseek,.release = single_release,
};

3.cat /d/wakeup_sources时调用的函数,wakeup_sources_stats_open

static int wakeup_sources_stats_open(struct inode *inode, struct file *file)
{return single_open(file, wakeup_sources_stats_show, NULL);
}

再看看wakeup_sources_stats_show。

/*** wakeup_sources_stats_show - Print wakeup sources statistics information.* @m: seq_file to print the statistics into.*/
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
{struct wakeup_source *ws;seq_puts(m, "name\t\t\t\t\tactive_count\tevent_count\twakeup_count\t""expire_count\tactive_since\ttotal_time\tmax_time\t""last_change\tprevent_suspend_time\n");   //这就是上面的第一行。rcu_read_lock();  list_for_each_entry_rcu(ws, &wakeup_sources, entry)  //互斥遍历wakeup_sources,每次取出其中之一ws.print_wakeup_source_stats(m, ws); //打印出照这个ws的相关信息rcu_read_unlock();return 0;
}

再看看print_wakeup_source_stats:

/*** print_wakeup_source_stats - Print wakeup source statistics information.* @m: seq_file to print the statistics into.* @ws: Wakeup source object to print the statistics for.*/
static int print_wakeup_source_stats(struct seq_file *m,struct wakeup_source *ws)
{unsigned long flags;ktime_t total_time;ktime_t max_time;unsigned long active_count;ktime_t active_time;ktime_t prevent_sleep_time;int ret;spin_lock_irqsave(&ws->lock, flags);total_time = ws->total_time;  //之前的total_timemax_time = ws->max_time;prevent_sleep_time = ws->prevent_sleep_time;active_count = ws->active_count;if (ws->active) {    //如果这个wakelock还在,没有释放掉ktime_t now = ktime_get();active_time = ktime_sub(now, ws->last_time); //active_time就是开始上锁到目前时间差total_time = ktime_add(total_time, active_time);  // total_time 就是上一次的total_time加上active_timeif (active_time.tv64 > max_time.tv64)max_time = active_time;if (ws->autosleep_enabled)prevent_sleep_time = ktime_add(prevent_sleep_time,ktime_sub(now, ws->start_prevent_time));} else {active_time = ktime_set(0, 0);}ret = seq_printf(m, "%-32s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t""%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",ws->name, active_count, ws->event_count,ws->wakeup_count, ws->expire_count,ktime_to_ms(active_time), ktime_to_ms(total_time),ktime_to_ms(max_time), ktime_to_ms(ws->last_time),ktime_to_ms(prevent_sleep_time));     //结果。spin_unlock_irqrestore(&ws->lock, flags);return ret;
}

4. wakeup_sources,一个当前文件中的全局list。在init一个wakelock的时候添加。

上面遍历的 wakeup_sources,本文件中的一个全局链表。很容易猜测到,每次申请一个wake_lock时,都会添加一个item到这个链表中。看看这个全局的list的声明和初始化。

static LIST_HEAD(wakeup_sources);  //初始化。

接下来看这个list的添加。想要使用wakelock,肯定是要先调用下面的init函数。我们在kernel中声明的wake_lock结构都有wakeup_source结构成员。后面更多的是用这个wakeup_source结构来管理。

static inline void wake_lock_init(struct wake_lock *lock, int type,
                  const char *name)
{
    wakeup_source_init(&lock->ws, name);
}

接着看被调用的wakeup_source_init。

static inline void wakeup_source_init(struct wakeup_source *ws,const char *name)
{wakeup_source_prepare(ws, name); //准备工作wakeup_source_add(ws); //真正的添加。
}

继续看wakeup_source_add.

/*** wakeup_source_add - Add given object to the list of wakeup sources.* @ws: Wakeup source object to add to the list.*/
void wakeup_source_add(struct wakeup_source *ws)
{unsigned long flags;if (WARN_ON(!ws))return;spin_lock_init(&ws->lock);setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);ws->active = false;  //初始化为非activews->last_time = ktime_get();   //当前时间。spin_lock_irqsave(&events_lock, flags);list_add_rcu(&ws->entry, &wakeup_sources);  //添加到wakeup_sourcesspin_unlock_irqrestore(&events_lock, flags);
}
EXPORT_SYMBOL_GPL(wakeup_source_add);

5.wakelock上锁时的操作

上锁时,都会调用下面的wake_lock函数。

static inline void wake_lock(struct wake_lock *lock)
{__pm_stay_awake(&lock->ws);
}

继续看__pm_stay_awake。

/*** __pm_stay_awake - Notify the PM core of a wakeup event.* @ws: Wakeup source object associated with the source of the event.** It is safe to call this function from interrupt context.*/
void __pm_stay_awake(struct wakeup_source *ws)
{unsigned long flags;if (!ws)return;spin_lock_irqsave(&ws->lock, flags);wakeup_source_report_event(ws);  //主要函数。del_timer(&ws->timer);ws->timer_expires = 0;spin_unlock_irqrestore(&ws->lock, flags);
}
EXPORT_SYMBOL_GPL(__pm_stay_awake);

继续看wakeup_source_report_event。

/*** wakeup_source_report_event - Report wakeup event using the given source.* @ws: Wakeup source to report the event for.*/
static void wakeup_source_report_event(struct wakeup_source *ws)
{ws->event_count++;  //event_count计数/* This is racy, but the counter is approximate anyway. */if (events_check_enabled)ws->wakeup_count++;//wakeup_count计数if (!ws->active)  //如果是非active状态wakeup_source_activate(ws); //那就变成active
}

接着看wakeup_source_activate.

/*** wakup_source_activate - Mark given wakeup source as active.* @ws: Wakeup source to handle.** Update the @ws' statistics and, if @ws has just been activated, notify the PM* core of the event by incrementing the counter of of wakeup events being* processed.*/
static void wakeup_source_activate(struct wakeup_source *ws)
{unsigned int cec;/** active wakeup source should bring the system* out of PM_SUSPEND_FREEZE state*/freeze_wake();  //保证上锁期间CPU不会睡下去ws->active = true;ws->active_count++; //active_count计数ws->last_time = ktime_get();  //这时的时间,也就是开始上锁的时间if (ws->autosleep_enabled)ws->start_prevent_time = ws->last_time;/* Increment the counter of events in progress. */cec = atomic_inc_return(&combined_event_count);trace_wakeup_source_activate(ws->name, cec);
}

6.wakelock释放时的操作

在kernel wakelock释放的时候,都会调用下面的wake_unlock函数。

static inline void wake_unlock(struct wake_lock *lock)
{__pm_relax(&lock->ws);
}

继续看看__pm_relax。

/*** __pm_relax - Notify the PM core that processing of a wakeup event has ended.* @ws: Wakeup source object associated with the source of the event.** Call this function for wakeup events whose processing started with calling* __pm_stay_awake().** It is safe to call it from interrupt context.*/
void __pm_relax(struct wakeup_source *ws)
{unsigned long flags;if (!ws)return;spin_lock_irqsave(&ws->lock, flags);if (ws->active)   //如果目前仍是active,那就要释放掉wakeup_source_deactivate(ws);spin_unlock_irqrestore(&ws->lock, flags);
}
EXPORT_SYMBOL_GPL(__pm_relax);

再看wakeup_source_deactivate。

/*** wakup_source_deactivate - Mark given wakeup source as inactive.* @ws: Wakeup source to handle.** Update the @ws' statistics and notify the PM core that the wakeup source has* become inactive by decrementing the counter of wakeup events being processed* and incrementing the counter of registered wakeup events.*/
static void wakeup_source_deactivate(struct wakeup_source *ws)
{unsigned int cnt, inpr, cec;ktime_t duration;ktime_t now;ws->relax_count++;/** __pm_relax() may be called directly or from a timer function.* If it is called directly right after the timer function has been* started, but before the timer function calls __pm_relax(), it is* possible that __pm_stay_awake() will be called in the meantime and* will set ws->active.  Then, ws->active may be cleared immediately* by the __pm_relax() called from the timer function, but in such a* case ws->relax_count will be different from ws->active_count.*/if (ws->relax_count != ws->active_count) {ws->relax_count--;return;}ws->active = false;now = ktime_get();duration = ktime_sub(now, ws->last_time);   //完整上锁的时间ws->total_time = ktime_add(ws->total_time, duration); //这把所从init之后所有上锁的时间总和if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))ws->max_time = duration;ws->last_time = now;del_timer(&ws->timer);ws->timer_expires = 0;if (ws->autosleep_enabled)update_prevent_sleep_time(ws, now);/** Increment the counter of registered wakeup events and decrement the* couter of wakeup events in progress simultaneously.*/cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);trace_wakeup_source_deactivate(ws->name, cec);split_counters(&cnt, &inpr);if (!inpr && waitqueue_active(&wakeup_count_wait_queue))wake_up(&wakeup_count_wait_queue);
}

7. 总结

wakeup_sources这个节点的信息对分析耗电比较有用的数据有active_count, active_since,total_time。

active_count--上锁的次数

active_since--当前的wakelock已经持续的时间

total_time--这个锁开机以来一共lock的时间

当CPU无法睡下去时,很可能就是因为某个driver持有wakelock不放导致的。这时可以这个节点来分析,找出根源。

不过,这个节点只有root权限才能查看,这是限制条件。

Android kernel中wakeup_sources解析相关推荐

  1. Android中怎获取json,Android应用中如何解析获取的json数据

    Android应用中如何解析获取的json数据 发布时间:2020-11-24 17:10:08 来源:亿速云 阅读:107 作者:Leah 这篇文章将为大家详细讲解有关Android应用中如何解析获 ...

  2. android xml 未能解析文件,Android Studio中“无法解析符号R”

    这是一个非常古老的问题,但它仍然发生了很多,这里没有真正全面的答案. 我遇到这个问题的次数比我想承认的要多. 它可能是由各种各样的问题引起的,这些问题主要与您的项目结构不符合预期的问题有关. 这是我所 ...

  3. android studio中光线传感器解析

    要学习Android需要先了解android activity的生命历程,请看下图(他人博客复制):图中我们可以清晰可看到android的生命周期,onCreate() ,onStart(),onRe ...

  4. 【CMake】Android Studio 中使用 CMake 编译单个 C++ 源文件 ( 常用的 CMake 命令解析 )

    文章目录 一.Android Studio 中使用 CMake 编译单个 C++ 源文件 二.cmake_minimum_required 命令设置最小 CMake 版本 三.project 命令设置 ...

  5. android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件

    简介 XStream 是一个开源项目,一套简单实用的类库,用于序列化对象与 XML 对象之间的相互转换. 将 XML 文件内容解析为一个对象或将一个对象序列化为 XML 文件. 1.下载工具 xstr ...

  6. android工程中的软件,通过Android Studio创建Android应用程序(附带解析)

    这一节我们主要来创建一个简单的 Android 的应用程序. 创建 HelloWorld 工程 启动 Android Studio,依次选择 File --> New --> New Pr ...

  7. (转)Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法

    版权声明:本文出自郭霖的博客,转载必须注明出处. 目录(?)[-] ValueAnimator的高级用法 ObjectAnimator的高级用法 转载请注明出处:http://blog.csdn.ne ...

  8. android 属性动画实例,Android属性动画完全解析 中 ,ValueAnimator和ObjectAnimator的高级用法...

    大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法,当然也是最常用的一些用法,这些用法足以覆盖我们平时大多情况下的动画需求了.但是,正如上篇文章当中所说到的,属性动画对补间动画进行了 ...

  9. android 中xml解析方式

    2019独角兽企业重金招聘Python工程师标准>>> XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重 ...

  10. Android开发中的WMS详细解析

    /   今日科技快讯   / 近日,小冰公司宣布对旗下人工智能数字员工产品线启动年度升级.本次升级加强的技术包括大模型对话引擎.3D神经网络渲染.超级自然语音及AIGC人工智能内容生成.小冰公司计划将 ...

最新文章

  1. 【Android Protobuf 序列化】Protobuf 使用 ( Protobuf 源码分析 | 创建 Protobuf 对象 )
  2. Repository模式与UnitOfWorks模式的运用
  3. eclipse导入远程库的git项目
  4. 小程序 上拉刷新 下拉加载 代码备忘
  5. 6、EIGRP配置实验之负载均衡
  6. 怎么在谷歌浏览器中安装.crx扩展名的离线Chrome插件?
  7. linux 平行运行命令,Linux paste命令
  8. 解决8080端口被占用问题
  9. 翻译:group_concat()函数(已提交到MariaDB官方手册)
  10. bch编码c语言有库么,BCH码的译码方法与流程
  11. OA系统权限分派实施方案
  12. html 倒计时 插件,jQuery倒计时插件leftTime.js
  13. python读写、导入导出数据操作(简)
  14. 语义分割论文:FastFCN:Rethinking Dilated Convolution in the Backbone for Semantic Segmentation(arxiv2019)
  15. 湖南科技职业学院计算机网络技术在哪个校区,湖南科技职业学院地址在哪里
  16. 动脑学院 java_动脑学院Rxjava预习资料 Rxjava入门
  17. 这24款效率办公神器,简直不要太强大!
  18. MindManager盘点——舌尖上的中国
  19. 「Win」Windows注册表介绍与操作
  20. 跳跃游戏-算法-简单易懂的解法

热门文章

  1. 【南北小和尚的一个禅】
  2. 【专业发展】技术领导力
  3. 华为机试--火车进站
  4. js截取视频第一帧_学学javascript如何截取视频第一帧
  5. 力扣438题找到字符串中所有字母异位词
  6. WWW 2022 | 搜索广告CVR延迟反馈建模DEFUSE
  7. macOS在使用音视频通话时会降低其他音频声音的解决方法
  8. k8s使用命令报错:error: You must be logged in to the server (Unauthorized)
  9. 视频分割技巧,把视频分割成多段进行保存
  10. Android数据编码之Base64