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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
18 #define LOG_TAG "libperfmgr"
19
20 #include "perfmgr/NodeLooperThread.h"
21
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/properties.h>
25 #include <utils/Trace.h>
26
27 namespace android {
28 namespace perfmgr {
29
Request(const std::vector<NodeAction> & actions,const std::string & hint_type)30 bool NodeLooperThread::Request(const std::vector<NodeAction>& actions,
31 const std::string& hint_type) {
32 if (::android::Thread::exitPending()) {
33 LOG(WARNING) << "NodeLooperThread is exiting";
34 return false;
35 }
36 if (!::android::Thread::isRunning()) {
37 LOG(WARNING) << "NodeLooperThread is not running, request " << hint_type;
38 }
39
40 bool ret = true;
41 ::android::AutoMutex _l(lock_);
42 for (const auto& a : actions) {
43 if (!a.enable_property.empty() &&
44 !android::base::GetBoolProperty(a.enable_property, true)) {
45 // Disabled action based on its control property
46 continue;
47 }
48 if (a.node_index >= nodes_.size()) {
49 LOG(ERROR) << "Node index out of bound: " << a.node_index
50 << " ,size: " << nodes_.size();
51 ret = false;
52 } else {
53 // End time set to steady time point max
54 ReqTime end_time = ReqTime::max();
55 // Timeout is non-zero
56 if (a.timeout_ms != std::chrono::milliseconds::zero()) {
57 auto now = std::chrono::steady_clock::now();
58 // Overflow protection in case timeout_ms is too big to overflow
59 // time point which is unsigned integer
60 if (std::chrono::duration_cast<std::chrono::milliseconds>(
61 ReqTime::max() - now) > a.timeout_ms) {
62 end_time = now + a.timeout_ms;
63 }
64 }
65 ret = nodes_[a.node_index]->AddRequest(a.value_index, hint_type,
66 end_time) &&
67 ret;
68 }
69 }
70 wake_cond_.signal();
71 return ret;
72 }
73
Cancel(const std::vector<NodeAction> & actions,const std::string & hint_type)74 bool NodeLooperThread::Cancel(const std::vector<NodeAction>& actions,
75 const std::string& hint_type) {
76 if (::android::Thread::exitPending()) {
77 LOG(WARNING) << "NodeLooperThread is exiting";
78 return false;
79 }
80 if (!::android::Thread::isRunning()) {
81 LOG(WARNING) << "NodeLooperThread is not running, cancel " << hint_type;
82 }
83
84 bool ret = true;
85 ::android::AutoMutex _l(lock_);
86 for (const auto& a : actions) {
87 if (a.node_index >= nodes_.size()) {
88 LOG(ERROR) << "Node index out of bound: " << a.node_index
89 << " ,size: " << nodes_.size();
90 ret = false;
91 } else {
92 nodes_[a.node_index]->RemoveRequest(hint_type);
93 }
94 }
95 wake_cond_.signal();
96 return ret;
97 }
98
DumpToFd(int fd)99 void NodeLooperThread::DumpToFd(int fd) {
100 ::android::AutoMutex _l(lock_);
101 for (auto& n : nodes_) {
102 n->DumpToFd(fd);
103 }
104 }
105
threadLoop()106 bool NodeLooperThread::threadLoop() {
107 ::android::AutoMutex _l(lock_);
108 std::chrono::milliseconds timeout_ms = kMaxUpdatePeriod;
109
110 // Update 2 passes: some node may have dependency in other node
111 // e.g. update cpufreq min to VAL while cpufreq max still set to
112 // a value lower than VAL, is expected to fail in first pass
113 ATRACE_BEGIN("update_nodes");
114 for (auto& n : nodes_) {
115 n->Update(false);
116 }
117 for (auto& n : nodes_) {
118 timeout_ms = std::min(n->Update(true), timeout_ms);
119 }
120 ATRACE_END();
121
122 nsecs_t sleep_timeout_ns = std::numeric_limits<nsecs_t>::max();
123 if (timeout_ms.count() < sleep_timeout_ns / 1000 / 1000) {
124 sleep_timeout_ns = timeout_ms.count() * 1000 * 1000;
125 }
126 // VERBOSE level won't print by default in user/userdebug build
127 LOG(VERBOSE) << "NodeLooperThread will wait for " << sleep_timeout_ns
128 << "ns";
129 ATRACE_BEGIN("wait");
130 wake_cond_.waitRelative(lock_, sleep_timeout_ns);
131 ATRACE_END();
132 return true;
133 }
134
Start()135 bool NodeLooperThread::Start() {
136 auto ret = this->run("NodeLooperThread", PRIORITY_HIGHEST);
137 if (ret != NO_ERROR) {
138 LOG(ERROR) << "NodeLooperThread start failed: " << ret;
139 } else {
140 LOG(INFO) << "NodeLooperThread started";
141 }
142 return ret == NO_ERROR;
143 }
144
Stop()145 void NodeLooperThread::Stop() {
146 if (::android::Thread::isRunning()) {
147 LOG(INFO) << "NodeLooperThread stopping";
148 {
149 ::android::AutoMutex _l(lock_);
150 wake_cond_.signal();
151 ::android::Thread::requestExit();
152 }
153 ::android::Thread::join();
154 LOG(INFO) << "NodeLooperThread stopped";
155 }
156 }
157
158 } // namespace perfmgr
159 } // namespace android
160