OSDN Git Service

Snap for 4751833 from ca4e5e87e5bf18698638b43a4b0a954e1f900028 to pi-release
[android-x86/system-extras.git] / libperfmgr / Node.cc
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