19d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang/*
29d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * Copyright (C) 2017 The Android Open Source Project
39d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang *
49d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * Licensed under the Apache License, Version 2.0 (the "License");
59d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * you may not use this file except in compliance with the License.
69d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * You may obtain a copy of the License at
79d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang *
89d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang *      http://www.apache.org/licenses/LICENSE-2.0
99d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang *
109d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * Unless required by applicable law or agreed to in writing, software
119d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * distributed under the License is distributed on an "AS IS" BASIS,
129d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * See the License for the specic language governing permissions and
149d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang * limitations under the License.
159d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang */
169d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
177ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang#define LOG_TAG "libperfmgr"
187ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang
199d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang#include <android-base/file.h>
209d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang#include <android-base/logging.h>
21b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang#include <android-base/stringprintf.h>
224ea001c2d3dc3f5c8421a5e86098272b295b213eWei Wang#include <android-base/strings.h>
239d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
249d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang#include "perfmgr/Node.h"
259d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
269d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangnamespace android {
279d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangnamespace perfmgr {
289d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
299d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei WangNode::Node(std::string name, std::string node_path,
309d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang           std::vector<RequestGroup> req_sorted, std::size_t default_val_index,
319d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang           bool reset_on_init, bool hold_fd)
329d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    : name_(name),
339d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang      node_path_(node_path),
349d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang      req_sorted_(std::move(req_sorted)),
359d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang      default_val_index_(default_val_index),
369d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang      reset_on_init_(reset_on_init),
379d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang      hold_fd_(hold_fd) {
389d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    if (reset_on_init) {
399d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        // Assigning an invalid value so the next Update() will update the
409d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        // Node's value to default
417ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang        current_val_index_ = req_sorted_.size();
429d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        Update();
439d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    } else {
449d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        current_val_index_ = default_val_index;
459d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
469d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
479d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
489d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangbool Node::AddRequest(std::size_t value_index, const std::string& hint_type,
499d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang                      ReqTime end_time) {
509d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    if (value_index >= req_sorted_.size()) {
519d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        LOG(ERROR) << "Value index out of bound: " << value_index
529d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang                   << " ,size: " << req_sorted_.size();
539d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        return false;
549d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
559d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    // Add/Update request to the new end_time for the specific hint_type
569d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    req_sorted_[value_index].AddRequest(hint_type, end_time);
579d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return true;
589d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
599d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
609d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangbool Node::RemoveRequest(const std::string& hint_type) {
619d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    bool ret = false;
629d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    // Remove all requests for the specific hint_type
639d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    for (auto& value : req_sorted_) {
649d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        ret = value.RemoveRequest(hint_type) || ret;
659d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
669d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return ret;
679d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
689d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
699d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangstd::chrono::milliseconds Node::Update() {
709d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    std::size_t value_index = default_val_index_;
719d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    std::chrono::milliseconds expire_time = std::chrono::milliseconds::max();
729d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
739d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    // Find the highest outstanding request's expire time
749d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    for (std::size_t i = 0; i < req_sorted_.size(); i++) {
759d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        if (req_sorted_[i].GetExpireTime(&expire_time)) {
769d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            value_index = i;
779d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            break;
789d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        }
799d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
809d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
819d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    // Update node only if request index changes
829d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    if (value_index != current_val_index_) {
837ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang        std::string req_value = req_sorted_[value_index].GetRequestValue();
849d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
859d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        fd_.reset(TEMP_FAILURE_RETRY(
869d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            open(node_path_.c_str(), O_WRONLY | O_CLOEXEC | O_TRUNC)));
879d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
889d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        if (fd_ == -1 || !android::base::WriteStringToFd(req_value, fd_)) {
899d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            LOG(ERROR) << "Failed to write to node: " << node_path_
907ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang                       << " with value: " << req_value << ", fd: " << fd_;
917ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang            // Retry in 500ms or sooner
927ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang            expire_time = std::min(expire_time, std::chrono::milliseconds(500));
939d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        } else {
949d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            // For regular file system, we need fsync
959d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            fsync(fd_);
969d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            // Some dev node requires file to remain open during the entire hint
979d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            // duration e.g. /dev/cpu_dma_latency, so fd_ is intentionally kept
989d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            // open during any requested value other than default one. If
999d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            // request a default value, node will write the value and then
1009d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            // release the fd.
1019d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            if ((!hold_fd_) || value_index == default_val_index_) {
1029d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang                fd_.reset();
1039d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            }
1047ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang            // Update current index only when succeed
1057ef92c9684700a19eef5f4e71d8261535bbdded8Wei Wang            current_val_index_ = value_index;
1069d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        }
1079d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
1089d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return expire_time;
1099d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1109d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1119d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangstd::string Node::GetName() const {
1129d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return name_;
1139d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1149d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1159d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangstd::string Node::GetPath() const {
1169d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return node_path_;
1179d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1189d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1199d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangbool Node::GetValueIndex(const std::string value, std::size_t* index) const {
1209d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    bool found = false;
1219d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    for (std::size_t i = 0; i < req_sorted_.size(); i++) {
1229d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        if (req_sorted_[i].GetRequestValue() == value) {
1239d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            *index = i;
1249d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            found = true;
1259d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang            break;
1269d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        }
1279d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
1289d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return found;
1299d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1309d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1319d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangstd::size_t Node::GetDefaultIndex() const {
1329d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return default_val_index_;
1339d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1349d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1359d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangbool Node::GetResetOnInit() const {
1369d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return reset_on_init_;
1379d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1389d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1399d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangbool Node::GetHoldFd() const {
1409d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return hold_fd_;
1419d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1429d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
1439d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wangstd::vector<std::string> Node::GetValues() const {
1449d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    std::vector<std::string> values;
1459d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    for (const auto& value : req_sorted_) {
1469d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang        values.emplace_back(value.GetRequestValue());
1479d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    }
1489d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang    return values;
1499d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}
1509d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang
151b243f99965c7f9b780854233273f9d8f9e13b39cWei Wangvoid Node::DumpToFd(int fd) {
152b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang    std::string node_value;
153b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang    if (!android::base::ReadFileToString(node_path_, &node_value)) {
154b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang        LOG(ERROR) << "Failed to read node path: " << node_path_;
155b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang    }
156b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang    node_value = android::base::Trim(node_value);
1574ea001c2d3dc3f5c8421a5e86098272b295b213eWei Wang    std::string buf(android::base::StringPrintf(
1584ea001c2d3dc3f5c8421a5e86098272b295b213eWei Wang        "%s\t%s\t%zu\t%s\n", name_.c_str(), node_path_.c_str(),
1594ea001c2d3dc3f5c8421a5e86098272b295b213eWei Wang        current_val_index_, node_value.c_str()));
160b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang    if (!android::base::WriteStringToFd(buf, fd)) {
161b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang        LOG(ERROR) << "Failed to dump fd: " << fd;
162b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang    }
163b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang}
164b243f99965c7f9b780854233273f9d8f9e13b39cWei Wang
1659d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}  // namespace perfmgr
1669d337a7df3ba6d6a8418f58ed59611678ae7b8cdWei Wang}  // namespace android
167