Home | History | Annotate | Download | only in libperfmgr
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specic language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "libperfmgr"
     18 
     19 #include <android-base/file.h>
     20 #include <android-base/logging.h>
     21 #include <android-base/stringprintf.h>
     22 #include <android-base/strings.h>
     23 
     24 #include "perfmgr/Node.h"
     25 
     26 namespace android {
     27 namespace perfmgr {
     28 
     29 Node::Node(std::string name, std::string node_path,
     30            std::vector<RequestGroup> req_sorted, std::size_t default_val_index,
     31            bool reset_on_init, bool hold_fd)
     32     : name_(name),
     33       node_path_(node_path),
     34       req_sorted_(std::move(req_sorted)),
     35       default_val_index_(default_val_index),
     36       reset_on_init_(reset_on_init),
     37       hold_fd_(hold_fd) {
     38     if (reset_on_init) {
     39         // Assigning an invalid value so the next Update() will update the
     40         // Node's value to default
     41         current_val_index_ = req_sorted_.size();
     42         Update();
     43     } else {
     44         current_val_index_ = default_val_index;
     45     }
     46 }
     47 
     48 bool Node::AddRequest(std::size_t value_index, const std::string& hint_type,
     49                       ReqTime end_time) {
     50     if (value_index >= req_sorted_.size()) {
     51         LOG(ERROR) << "Value index out of bound: " << value_index
     52                    << " ,size: " << req_sorted_.size();
     53         return false;
     54     }
     55     // Add/Update request to the new end_time for the specific hint_type
     56     req_sorted_[value_index].AddRequest(hint_type, end_time);
     57     return true;
     58 }
     59 
     60 bool Node::RemoveRequest(const std::string& hint_type) {
     61     bool ret = false;
     62     // Remove all requests for the specific hint_type
     63     for (auto& value : req_sorted_) {
     64         ret = value.RemoveRequest(hint_type) || ret;
     65     }
     66     return ret;
     67 }
     68 
     69 std::chrono::milliseconds Node::Update() {
     70     std::size_t value_index = default_val_index_;
     71     std::chrono::milliseconds expire_time = std::chrono::milliseconds::max();
     72 
     73     // Find the highest outstanding request's expire time
     74     for (std::size_t i = 0; i < req_sorted_.size(); i++) {
     75         if (req_sorted_[i].GetExpireTime(&expire_time)) {
     76             value_index = i;
     77             break;
     78         }
     79     }
     80 
     81     // Update node only if request index changes
     82     if (value_index != current_val_index_) {
     83         std::string req_value = req_sorted_[value_index].GetRequestValue();
     84 
     85         fd_.reset(TEMP_FAILURE_RETRY(
     86             open(node_path_.c_str(), O_WRONLY | O_CLOEXEC | O_TRUNC)));
     87 
     88         if (fd_ == -1 || !android::base::WriteStringToFd(req_value, fd_)) {
     89             LOG(ERROR) << "Failed to write to node: " << node_path_
     90                        << " with value: " << req_value << ", fd: " << fd_;
     91             // Retry in 500ms or sooner
     92             expire_time = std::min(expire_time, std::chrono::milliseconds(500));
     93         } else {
     94             // For regular file system, we need fsync
     95             fsync(fd_);
     96             // Some dev node requires file to remain open during the entire hint
     97             // duration e.g. /dev/cpu_dma_latency, so fd_ is intentionally kept
     98             // open during any requested value other than default one. If
     99             // request a default value, node will write the value and then
    100             // release the fd.
    101             if ((!hold_fd_) || value_index == default_val_index_) {
    102                 fd_.reset();
    103             }
    104             // Update current index only when succeed
    105             current_val_index_ = value_index;
    106         }
    107     }
    108     return expire_time;
    109 }
    110 
    111 std::string Node::GetName() const {
    112     return name_;
    113 }
    114 
    115 std::string Node::GetPath() const {
    116     return node_path_;
    117 }
    118 
    119 bool Node::GetValueIndex(const std::string value, std::size_t* index) const {
    120     bool found = false;
    121     for (std::size_t i = 0; i < req_sorted_.size(); i++) {
    122         if (req_sorted_[i].GetRequestValue() == value) {
    123             *index = i;
    124             found = true;
    125             break;
    126         }
    127     }
    128     return found;
    129 }
    130 
    131 std::size_t Node::GetDefaultIndex() const {
    132     return default_val_index_;
    133 }
    134 
    135 bool Node::GetResetOnInit() const {
    136     return reset_on_init_;
    137 }
    138 
    139 bool Node::GetHoldFd() const {
    140     return hold_fd_;
    141 }
    142 
    143 std::vector<std::string> Node::GetValues() const {
    144     std::vector<std::string> values;
    145     for (const auto& value : req_sorted_) {
    146         values.emplace_back(value.GetRequestValue());
    147     }
    148     return values;
    149 }
    150 
    151 void Node::DumpToFd(int fd) {
    152     std::string node_value;
    153     if (!android::base::ReadFileToString(node_path_, &node_value)) {
    154         LOG(ERROR) << "Failed to read node path: " << node_path_;
    155     }
    156     node_value = android::base::Trim(node_value);
    157     std::string buf(android::base::StringPrintf(
    158         "%s\t%s\t%zu\t%s\n", name_.c_str(), node_path_.c_str(),
    159         current_val_index_, node_value.c_str()));
    160     if (!android::base::WriteStringToFd(buf, fd)) {
    161         LOG(ERROR) << "Failed to dump fd: " << fd;
    162     }
    163 }
    164 
    165 }  // namespace perfmgr
    166 }  // namespace android
    167