Linux Driver优化S4 hibernate休眠速度
创始人
2024-03-09 14:53:24
0

前言

  Driver的S3睡眠时间太慢了,原因找到了,但是S4休眠时间也比友商慢,S4要比S3复杂一点,中间涉及到kernel image的生成和写入disk,这部分花的时间挺多,所以想办法看能不能S4优化一下。

正文

  

hibernate

Kernel version V5.18
int hibernate(void)
{//只给出重要代码pm_prepare_console(); //切换成虚拟console/* 通知其他子系统要准备休眠了*/error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);ksys_sync_helper(); //同步文件系统error = freeze_processes(); //冻结用户层进程error = create_basic_memory_bitmaps(); //创建包含page属性的bitmapserror = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); //分配image所需的pageif (in_suspend) {pm_pr_dbg("Writing hibernation image.\n");error = swsusp_write(flags); /*将image的page写入swap分区*/swsusp_free(); // 释放image的pageif (!error) {if (hibernation_mode == HIBERNATION_TEST_RESUME) //如果Kernel S4有问题,可以测试是Software的问题还是Hardware和BIOS Firmware的问题snapshot_test = true; elsepower_down(); //下电咯,device close}

  pm_prepare_console:VT switch,将当前console切换到一个虚拟console并重定向内核的kmsg,这部分代码比较复杂,就不展开看源码了。

  create_basic_memory_bitmaps() 计算和预留page给image。

  swsusp_write() 即swap suspend write,将休眠用的image写入swap分区所在的disk。

  顺便提一下,Kernel本身提供测试选项用于 测试S4的功能是否正常,因为S4不仅仅是Kernel负责,BIOS,硬件的上电时序也参与了这一个过程,如果这些有问题,那S4也会有问题,所以预留了测试选项,使得hibernate()也可以不下电,而是马上进行resume,可以测试S4的问题是软件还是硬件的锅,

我们继续看hibernation_snapshot()

hibernation_snapshot

Kernel version V5.18
int hibernation_snapshot(int platform_mode)
{//只给出重要代码hibernate_preallocate_memory(); //计算和预分配image所需的pageerror = freeze_kernel_threads(); //冻结内核线程error = dpm_prepare(PMSG_FREEZE); //执行所有device的prepare电源管理回调suspend_console(); //挂起consoleerror = dpm_suspend(PMSG_FREEZE); //执行所有device的freeze电源管理回调if (error || hibernation_test(TEST_DEVICES))platform_recover(platform_mode);elseerror = create_image(platform_mode); //创建imagemsg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;dpm_resume(msg); //执行thaw电源管理回调,相当于撤销之前的freeze电源回调,活还没干完 起来干resume_console(); //恢复控制台
}

  主要就是调用hibernate_preallocate_memory计算大概需要多少page,是否满足用户的需求,接着创建休眠的image。
  接着看一下hibernate_preallocate_memory是如何让计算哪些page需要保存进image里。

hibernate_preallocate_memory

这个是最恶心的函数,它这代码一写的看起来很绕。

在看之前先补充一点知识:
/sys/power/image_size 是休眠image的最大大小
Kernel创建的image不得大于这个值,用户可以更改这个值。哪些page需要保存? 当然是当然伙伴系统已经被用的page需要保存
image放在哪? 先放在内存里,所以我们需要申请page去存储image
如果伙伴系统里用掉的page比剩余的多,或者说使用量大于50%,这个时候还能生成image吗? 可能就不能了,这个问题后面解释。Kernel version V5.18
int hibernate_preallocate_memory(void)
{//Fucking Source Codestruct zone *zone;unsigned long saveable, size, max_size, count, highmem, pages = 0;unsigned long alloc, save_highmem, pages_highmem, avail_normal;ktime_t start, stop;int error;alloc_normal = 0;alloc_highmem = 0;/* Count the number of saveable data pages. */save_highmem = count_highmem_pages(); //计算需要保存的high-mem pagesaveable = count_data_pages();	//计算需要保存的normal-mem page/** Compute the total number of page frames we can use (count) and the* number of pages needed for image metadata (size).*/count = saveable;saveable += save_highmem;  //所有应该保存的pagehighmem = save_highmem;size = 0;for_each_populated_zone(zone) {size += snapshot_additional_pages(zone);if (is_highmem(zone))highmem += zone_page_state(zone, NR_FREE_PAGES);  //加上high-mem free pageelsecount += zone_page_state(zone, NR_FREE_PAGES); //加上normal-mem free page}avail_normal = count;  count += highmem;count -= totalreserve_pages;/* Compute the maximum number of saveable pages to leave in memory. */max_size = (count - (size + PAGES_FOR_IO)) / 2- 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE); //计算image可能达到的最大大小size = DIV_ROUND_UP(image_size, PAGE_SIZE); //image_size就是/sys/power/image_size 用户可以设定的值if (size > max_size) //如果用户允许我们保存这么大(这是理想情况)size = max_size;if (size >= saveable) { //并且有这么多空间保存imagepages = preallocate_image_highmem(save_highmem);pages += preallocate_image_memory(saveable - pages, avail_normal);goto out; //计算完所需的page,退出}/* 如果走到这来,非常抱歉,可能我们要抛弃一些page*//* Estimate the minimum size of the image. */pages = minimum_image_size(saveable);  //计算image的最小值if (avail_normal > pages)avail_normal -= pages;elseavail_normal = 0;if (size < pages) //如果计算出来的image比minimum_image_size还小,自求多福吧,取一个最小值size = min_t(unsigned long, pages, max_size);shrink_all_memory(saveable - size); //尝试清理内存pages_highmem = preallocate_image_highmem(highmem / 2);alloc = count - max_size;if (alloc > pages_highmem)alloc -= pages_highmem;elsealloc = 0;pages = preallocate_image_memory(alloc, avail_normal);if (pages < alloc) { //如果分配的不够,尝试从highmem再次分配一些出来/* We have exhausted non-highmem pages, try highmem. */alloc -= pages;pages += pages_highmem;pages_highmem = preallocate_image_highmem(alloc);if (pages_highmem < alloc) {pr_err("Image allocation is %lu pages short\n",alloc - pages_highmem);goto err_out;}pages += pages_highmem;/** size is the desired number of saveable pages to leave in* memory, so try to preallocate (all memory - size) pages.*/alloc = (count - pages) - size;pages += preallocate_image_highmem(alloc);} else {/** There are approximately max_size saveable pages at this point* and we want to reduce this number down to size.*/alloc = max_size - size;size = preallocate_highmem_fraction(alloc, highmem, count);pages_highmem += size;alloc -= size;size = preallocate_image_memory(alloc, avail_normal);pages_highmem += preallocate_image_highmem(alloc - size);pages += pages_highmem + size;}/** We only need as many page frames for the image as there are saveable* pages in memory, but we have allocated more.  Release the excessive* ones now.*/pages -= free_unnecessary_pages();out:stop = ktime_get();pr_info("Allocated %lu pages for snapshot\n", pages);swsusp_show_speed(start, stop, pages, "Allocated");}

count_highmem_pages()和count_data_pages()
  都是统计不是nosave区域或者在forbidden,free的page数量(看是否在对于bitmaps中)
preallocate_image_memory()和preallocate_image_highmem()
会分配page同时累加alloc_normal,alloc_highmem,记录已分配的page数量。

  这个函数的作用就是记录image需要多少page,预先分配这些page
当然还不是最终的,因为我们在hibernate的时候Driver可能会申请page,这些page也需要保存。

create_image

这里就是创建image的地方,因为我们以及预先分配了page,我们需要将需要保存的page拷贝到分配好的page中。Kernel version V5.18
static int create_image(int platform_mode)
{error = pm_sleep_disable_secondary_cpus(); //关SMP,只留一个CPUsave_processor_state(); //架构相关,保存CPU的当前的状态error = swsusp_arch_suspend(); //架构相关,生成image}

swsusp_save


swsusp_arch_suspend()是架构相关的,最终会调用到swsusp_save()
Kernel version V5.18
int swsusp_save(unsigned int flags)
{nr_pages = count_data_pages();nr_highmem = count_highmem_pages();if (!enough_free_mem(nr_pages, nr_highmem)) {pr_err("Not enough free memory\n");return -ENOMEM;}if (swsusp_alloc(©_bm, nr_pages, nr_highmem)) {pr_err("Memory allocation failed\n");return -ENOMEM;}drain_local_pages(NULL);copy_data_pages(©_bm, &orig_bm);/** End of critical section. From now on, we can write to memory,* but we should not touch disk. This specially means we must _not_* touch swap space! Except we must write out our image of course.*/nr_pages += nr_highmem;nr_copy_pages = nr_pages;nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);pr_info("Image created (%d pages copied)\n", nr_pages);}

  这个函数也很简单,因为Driver hibernate的可能会申请一些page,所以需要重新计算需要保存的page。
  然后orig_bm的bitmap中对需要保存page置位,copy_bm在分配page的时候会也被置位过,所以现在只要把orig_bm置位过的page拷贝到copy_bm置位的page中就行了。

swsusp_write

  这个函数不会还要再讲把,作用就是把上面的image写入swap分区里~,很简单的。

总结

Driver可优化的地方
  1.S4 hibernate会冻结用户层和内核层的线程,内核层冻结如果用时超过0.001S是需要优化的。
  2.预分配之后Driver额外使用大量的page,造成image大小增加,增加image写入disk的时间。这个其实也蛮难优化,可以考虑free一些cache page,以及减少内存的使用,或者考虑使用shmem?
  3.Driver电源管理回调耗时,计算一下各回调的时间,找一下哪些耗时。

Driver不可优化/难优化的:
  1.预分配阶段分配大量的page会耗时间
  2.文件系统同步

其他的有空再完善吧~

引用

http://www.wowotech.net/pm_subsystem/hibernation.html
里面有两个hibernate和resume流程的pdf,可以参考一下

相关内容

热门资讯

清朝有很多有名的历史人物,能给... 清朝有很多有名的历史人物,能给大家说几个清朝的历史人物吗?林则徐,张之洞,乾隆皇帝,曾国藩,朱耷,这...
曹丕的“太子四友”指的是谁 曹丕的“太子四友”指的是谁首先说,曹丕这四个,陈群司马懿是顶级的谋士和政治家,吴质有些小聪明,朱铄不...
在这次遇难者中存在了几名幸存者... 在这次遇难者中存在了几名幸存者。这句话是不是逻辑错误这句话的逻辑没有问题,有问题的是用词不当。遇难者...
在中国古代,有许多充满哲学智慧... 在中国古代,有许多充满哲学智慧的成语典故、寓言故事,如...在中国古代,有许多充满哲学智慧的成语典故...
清澈的意思是什么,… 清澈的意思是什么,…清净而明澈清而透明【造句】看着他清澈而又天真的眼眸,我的心久久不能平静……
蚂蚁森林合种爱情树一方退出怎么... 蚂蚁森林合种爱情树一方退出怎么找回来两个人合种的爱情树,我退出来,我怎么再次加入进去继续合作那个树?...
有好看的古代修炼小说推荐吗? 有好看的古代修炼小说推荐吗?古代重生穿越修炼......让我帮你找一下这些古代修炼的小说,找到这些类...
女主重生爱上前世辜负的人 女主重生爱上前世辜负的人重生我是你正妻渣女重生之竹马重生之弃渣重生之夫君可欺重生之换我疼你重生妇归来...
华胥引有广播剧吗 华胥引有广播剧吗现有的华胥引的广播剧是忆语广播剧社出品的,只有十三月和杯(这个是错字,请无视,居然输...
选文韩麦尔先生在说了,我的朋友... 选文韩麦尔先生在说了,我的朋友们我就要离开你们呢了,再见了银头鲑鱼tj75rt6yturdrruv ...
中通快递从北京保定市到广东揭阳... 中通快递从北京保定市到广东揭阳普宁要多久?中通快递从北京保定市到广东揭阳普宁要多久?从北京到广东需要...
关于离婚悲伤的歌曲 关于离婚悲伤的歌曲关于离婚悲伤的歌曲林俊杰《可惜没如果》 张靓颖《我走以后》 金志文《流着泪说分手》...
形容文笔差怎么说啊? 形容文笔差怎么说啊?哥哥姐姐,麻烦问下,我是做文员的,形容文案方面的工作很差应该怎么说啊?粗鄙怎么样...
我想做未婚妈妈,可行吗? 我想做未婚妈妈,可行吗?没关系吧?我同学好多他们妈妈都是30岁以后省得他们,都没事啊,但是如果你自己...
如何在两个excel表格里筛选... 如何在两个excel表格里筛选出重复的名字如何在两个excel表格里筛选出重复的名字1、电脑打开EX...
且试天下 哪些小说是用白绫做武... 且试天下 哪些小说是用白绫做武器的?神雕侠侣吖- -..小龙女一开始就是用白绫的聊斋 辛十四娘嘿嘿~...
自带高冷体质,笑起来温暖又治愈... 自带高冷体质,笑起来温暖又治愈的星座,你了解吗?虽然天生高冷体质,但是笑起来特别的温暖治愈的新作用天...
火星未解之谜 火星未解之谜多列举一些,每个事例最好长一点,谢啦~“火星人脸”, “地表被水冲击河道”,“原始大气和...
我是1991年10月4号生的,... 我是1991年10月4号生的,是什么星座啊有的说是处女座有的说是天平座,糊涂了,到底是什么啊很负责任...
梦见白狐狸,然后当时我骑着自行... 梦见白狐狸,然后当时我骑着自行车,我想躲开它,他很凶的的追赶我,最后它向我扑了过来,然后我就醒乐.你...