日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

wakeup_sources

發布時間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 wakeup_sources 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

android的耗電問題,會涉及到wakelock部分。
https://blog.csdn.net/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_head entry;spinlock_t lock;struct timer_list timer;unsigned long timer_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 long event_count; unsigned long active_count;unsigned long relax_count;unsigned long expire_count;unsigned long wakeup_count;bool active:1;bool autosleep_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); }

總結

以上是生活随笔為你收集整理的wakeup_sources的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品扒开腿做爽爽爽男男 | 久久精品在线免费观看 | 天天操夜操 | 欧美精品免费一区二区 | 淫妹妹影院 | 国模av| caopeng在线视频| 亚洲不卡在线视频 | 高清视频免费在线观看 | 麻豆高清视频 | av天天在线 | 女人洗澡一级特黄毛片 | 久射久| 在线网站黄 | 操白虎逼 | 亚洲一区二区三区加勒比 | 在线观看欧美成人 | 欧美日本免费 | 欧美熟妇一区二区 | 欧产日产国产精品 | 欧美精品一区二区免费 | 亚洲成人一级 | 欧美肉大捧一进一出免费视频 | 熟女精品一区二区三区 | 人人看人人艹 | 日本一区二区网站 | 国产1级片 | 高潮喷水一区二区三区 | 丰满熟女人妻一区二区三区 | 久久婷婷影视 | 免费看欧美一级特黄a大片 国产免费的av | 中文写幕一区二区三区免费观成熟 | 亚洲一区日韩 | 精品人妻一区二区三区久久嗨 | 91成人天堂久久成人 | 少妇被又大又粗又爽毛片久久黑人 | 一区二区日韩av | 色综合久久88色综合天天免费 | 哈利波特3在线观看免费版英文版 | 色片网站在线观看 | 樱桃视频一区二区三区 | 国产高清视频在线 | 中文字幕精品一区二区三区视频 | 中国黄色免费网站 | av在线最新 | 亚洲欧美伊人 | 国产又粗又长又黄的视频 | 偷拍欧美另类 | 国产视频一级 | 国产精品一区久久 | 永久久久久久久 | 91传媒理伦片在线观看 | 天堂在线视频观看 | 一本色道久久综合狠狠躁的推荐 | 2019毛片| 日韩综合第一页 | 黄色免费91 | 国产啪视频 | 另类色综合 | 1769国产精品 | 天天看天天摸 | 中国av一区二区 | 久久午夜免费视频 | 中文字幕日韩在线播放 | 日本成人在线免费视频 | 日本少妇一区 | 黄色wwww | 中字av在线| 97福利视频 | 国产专区av| 日韩综合在线观看 | 少妇毛片视频 | 美女露出粉嫩尿囗让男人桶 | 热久久精品 | 欧类av怡春院| 亚洲制服在线观看 | 麻豆精品国产传媒av绿帽社 | av天天堂 | 亚州欧美日韩 | 91成年人视频 | 久久天天躁狠狠躁夜夜躁2014 | 日韩精品一区二区免费视频 | 少妇一级淫片免费观看 | 老司机午夜免费视频 | www.精品国产 | 精品偷拍网 | 最新黄色网页 | 三级在线免费 | 亚洲精品一区二区三区蜜臀 | 久久久久夜夜夜精品国产 | 日韩黄色录像 | 国产精品99re | 青草青在线 | 亚洲精品7777 | av小说免费在线观看 | jizz欧洲 | 国产亚洲毛片 | 日韩一级片免费观看 | 国产精品入口 |