OSDN Git Service

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