打印

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

[复制链接]
674|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2020-3-25 13:08 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 keer_zu 于 2020-3-25 16:08 编辑

lowpower

@icecut @海中水 @yyy71cj



系统自动进入休眠,并被中断唤醒

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


先看主函数:

/* 
* insomniad - user space policy for Linux's autosleep mechanism
*
* Copyright (C) 2014 Tyler Hall <tylerwhall@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
*/
#include "common.h"
#include "policy.h"
#include "cfm.h"


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

    get_opts(argc, argv);

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

    while (1) {
        int rc;

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

        /* Allow policy to futher delay */
        evaluate_policy();

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

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

        /*
         * Sleep for at least the requested timeout after wake, emulating a
         * wakeup source on resume. Normally this would be taken care of by the
         * kernel generating a wakeup event on resume and we would make sure
         * not to sleep until it is released + our timeout. This makes sure our
         * timeout is applied to spurious wakeups as well.
         */
        usleep_signal_safe(hysteresis_ms * 1000);
    };
    return 0;
}

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

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

    ctx->state_fd = open("/sys/power/state", O_WRONLY, O_CLOEXEC);
    if (ctx->state_fd == -1) {
        perror("Error opening power state");
        exit(1);
    }
    ctx->wakeup_count_fd = -1;
}

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


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

void read_wakeup_count(struct insomniad_ctx *ctx)
{
    int rc;

    open_wakeup_count(ctx);
    memset(&ctx->wakeup_count, 0, sizeof(ctx->wakeup_count));
    //rc = TEMP_FAILURE_RETRY(read(ctx->wakeup_count_fd, &ctx->wakeup_count, sizeof(ctx->wakeup_count)));
    rc = read(ctx->wakeup_count_fd, &ctx->wakeup_count, sizeof(ctx->wakeup_count));
    if (rc == -1) {
        perror("Error reading wakeup_count");
        exit(1);
    }
}



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

int evaluate_policy(void)
{
    struct wakeup_source *wup = get_most_recent_event();
    uint64_t current_time = get_time_ms();
    uint64_t delta;

    if (!wup)
        return -ENOMEM;
    assert(current_time >= wup->last_change);

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

    wakeup_source_unref(wup);

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

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

    return 1;
}

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






使用特权

评论回复

相关帖子

沙发
21ic小喇叭| | 2020-3-25 13:10 | 只看该作者
感谢分享,奖励您100家园币,家园币可以兑换礼品或抽奖,欢迎体验~

使用特权

评论回复
板凳
海中水| | 2020-3-25 13:26 | 只看该作者
这个是用于应用层功耗测试的吗?

使用特权

评论回复
地板
keer_zu|  楼主 | 2020-3-25 13:47 | 只看该作者
海中水 发表于 2020-3-25 13:26
这个是用于应用层功耗测试的吗?

是的

使用特权

评论回复
5
arlph| | 2020-3-25 14:44 | 只看该作者

使用特权

评论回复
6
海中水| | 2020-3-26 09:33 | 只看该作者

你现在转搞这块了吗?

使用特权

评论回复
7
keer_zu|  楼主 | 2020-3-26 09:35 | 只看该作者
海中水 发表于 2020-3-26 09:33
你现在转搞这块了吗?

这两天在弄

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1352

主题

12436

帖子

53

粉丝