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