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