搜索

这个lowpower的代码稍加修改后,可以运行在x86下的linux系统...

[复制链接]
193|6
 楼主 | 2020-3-25 13:08 | 显示全部楼层 |阅读模式
本帖最后由 keer_zu 于 2020-3-25 16:08 编辑

lowpower

@icecut @海中水 @yyy71cj


20395e7ae702273e1.png
系统自动进入休眠,并被中断唤醒

后边我们一起分析一下代码的实现。


先看主函数:

  1. /*
  2. * insomniad - user space policy for Linux's autosleep mechanism
  3. *
  4. * Copyright (C) 2014 Tyler Hall <tylerwhall@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. /*
  21. #include <stdlib.h>
  22. #include <limits.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include <unistd.h>
  29. #include <errno.h>
  30. #include <assert.h>
  31. */
  32. #include "common.h"
  33. #include "policy.h"
  34. #include "cfm.h"


  35. int main(int argc, char *argv[])
  36. {
  37.     struct insomniad_ctx ctx;

  38.     get_opts(argc, argv);

  39.     insomniad_init(&ctx);
  40.     pr_info("Using hysteresis time of %lu ms\n", hysteresis_ms);

  41.     while (1) {
  42.         int rc;

  43.         /* Blocks until no wakeup sources are active */
  44.         read_wakeup_count(&ctx);

  45.         /* Allow policy to futher delay */
  46.         evaluate_policy();

  47.         rc = write_wakeup_count(&ctx);
  48.         if (rc) {
  49.             /* This will fail when an event happens between read() and
  50.              * write(). We raced with a wakeup event, so start over. */
  51.             pr_info("Event occurred since reading wakeup_count\n");
  52.             continue;
  53.         }

  54.         /* write successful. Going down now. */
  55.         pr_info("Going to sleep\n");
  56.         rc = go_to_sleep(&ctx);
  57.         if (rc) {
  58.             /* Non-fatal error. Try again. */
  59.             pr_info("Non-fatal error %s writing to suspend state\n", strerror(-rc));
  60.             /* Rate-limit suspend attempts to avoid thrashing aborted suspends */
  61.             usleep_signal_safe(1000);
  62.             continue;
  63.         }
  64.         pr_info("Exited sleep\n");

  65.         /*
  66.          * Sleep for at least the requested timeout after wake, emulating a
  67.          * wakeup source on resume. Normally this would be taken care of by the
  68.          * kernel generating a wakeup event on resume and we would make sure
  69.          * not to sleep until it is released + our timeout. This makes sure our
  70.          * timeout is applied to spurious wakeups as well.
  71.          */
  72.         usleep_signal_safe(hysteresis_ms * 1000);
  73.     };
  74.     return 0;
  75. }
复制代码

首先是调用insomniad_init()初始化一个insomniad_ctx,代码如下:

  1. void insomniad_init(struct insomniad_ctx *ctx)
  2. {
  3.     /* Necessary to flush logging to systemd journal in a timely manner */
  4.     setlinebuf(stdout);
  5.     setlinebuf(stderr);

  6.     ctx->state_fd = open("/sys/power/state", O_WRONLY, O_CLOEXEC);
  7.     if (ctx->state_fd == -1) {
  8.         perror("Error opening power state");
  9.         exit(1);
  10.     }
  11.     ctx->wakeup_count_fd = -1;
  12. }
复制代码

里面主要是打开系统文件/sys/power/state。


然后进入一个无限循环,通过read_wakeup_count读取/sys/power/wakeup_count:

  1. void read_wakeup_count(struct insomniad_ctx *ctx)
  2. {
  3.     int rc;

  4.     open_wakeup_count(ctx);
  5.     memset(&ctx->wakeup_count, 0, sizeof(ctx->wakeup_count));
  6.     //rc = TEMP_FAILURE_RETRY(read(ctx->wakeup_count_fd, &ctx->wakeup_count, sizeof(ctx->wakeup_count)));
  7.     rc = read(ctx->wakeup_count_fd, &ctx->wakeup_count, sizeof(ctx->wakeup_count));
  8.     if (rc == -1) {
  9.         perror("Error reading wakeup_count");
  10.         exit(1);
  11.     }
  12. }
复制代码



然后是evaluate_policy(),代码如下:

  1. int evaluate_policy(void)
  2. {
  3.     struct wakeup_source *wup = get_most_recent_event();
  4.     uint64_t current_time = get_time_ms();
  5.     uint64_t delta;

  6.     if (!wup)
  7.         return -ENOMEM;
  8.     assert(current_time >= wup->last_change);

  9.     delta = current_time - wup->last_change;
  10.     pr_info("Last wakeup event at %" PRIu64 "ms\n", wup->last_change);
  11.     pr_info("Current time         %" PRIu64 "ms\n", current_time);
  12.     pr_info("Delta                %" PRIu64 "ms\n", delta);

  13.     wakeup_source_unref(wup);

  14.     if (delta < hysteresis_ms) {
  15.         uint64_t delay = hysteresis_ms - delta;

  16.         pr_info("Delaying for         %" PRIu64 "ms\n", delay);
  17.         usleep_signal_safe(delay * 1000);
  18.     }

  19.     return 1;
  20. }
复制代码

evaluate_policy()主要是获取有效的wakeup_source。






使用特权

评论回复
| 2020-3-25 13:10 | 显示全部楼层
感谢分享,奖励您100家园币,家园币可以兑换礼品或抽奖,欢迎体验~

使用特权

评论回复
| 2020-3-25 13:26 | 显示全部楼层
这个是用于应用层功耗测试的吗?

使用特权

评论回复
 楼主 | 2020-3-25 13:47 | 显示全部楼层
海中水 发表于 2020-3-25 13:26
这个是用于应用层功耗测试的吗?

是的

使用特权

评论回复
| 2020-3-25 14:44 | 显示全部楼层
EOsc-3AWoAIx1v1.jpg

使用特权

评论回复
| 2020-3-26 09:33 | 显示全部楼层

你现在转搞这块了吗?

使用特权

评论回复
 楼主 | 2020-3-26 09:35 | 显示全部楼层
海中水 发表于 2020-3-26 09:33
你现在转搞这块了吗?

这两天在弄

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

关闭

热门推荐上一条 /2 下一条

在线客服 快速回复 返回顶部 返回列表