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