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