2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > wakeup_sources

wakeup_sources

时间:2020-03-25 22:37:02

相关推荐

wakeup_sources

android的耗电问题,会涉及到wakelock部分。

/weixin_42322147/article/details/80469590

/*** struct wakeup_source - Representation of wakeup sources** @total_time: Total time this wakeup source has been active.* @max_time: Maximum time this wakeup source has been continuously active.* @last_time: Monotonic clock when the wakeup source's was touched last time.* @prevent_sleep_time: Total time this source has been preventing autosleep.* @event_count: Number of signaled wakeup events.* @active_count: Number of times the wakeup source was activated.* @relax_count: Number of times the wakeup source was deactivated.* @expire_count: Number of times the wakeup source's timeout has expired.* @wakeup_count: Number of times the wakeup source might abort suspend.* @active: Status of the wakeup source.* @has_timeout: The wakeup source has been activated with a timeout.*/struct wakeup_source {const char *name;struct list_headentry;spinlock_tlock;struct timer_listtimer;unsigned longtimer_expires;ktime_t total_time; //wakeup source处于active的总时长ktime_t max_time;ktime_t last_time;ktime_t start_prevent_time;ktime_t prevent_sleep_time;unsigned longevent_count; unsigned longactive_count;unsigned longrelax_count;unsigned longexpire_count;unsigned longwakeup_count;boolactive:1;boolautosleep_enabled:1;};

在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

bluetooth_timer 64 64 0 0 0 3213 3001 69776 0

wakeup_sources这个节点的信息对分析耗电比较有用的数据有:

active_count, active_since, total_time。

active_count:上锁的次数

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

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

上文中active_count=64次

上文中active_since=3213毫秒

上文中total_time=3001毫秒

当CPU无法睡下去时,很可能就是因为某个driver持有wakelock不放导致的。

这时可以从这个节点来分析,找出根源。

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

一、 节点的创建

根据节点的名称,先查看节点生成的文件为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;}

二、节点操作的相关函数

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,

};

三、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;}

四、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);

五、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);}

六、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);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。
扩展阅读