160 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2017 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specic language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
 | |
| #define LOG_TAG "libperfmgr"
 | |
| 
 | |
| #include "perfmgr/NodeLooperThread.h"
 | |
| 
 | |
| #include <android-base/file.h>
 | |
| #include <android-base/logging.h>
 | |
| #include <android-base/properties.h>
 | |
| #include <utils/Trace.h>
 | |
| 
 | |
| namespace android {
 | |
| namespace perfmgr {
 | |
| 
 | |
| bool NodeLooperThread::Request(const std::vector<NodeAction>& actions,
 | |
|                                const std::string& hint_type) {
 | |
|     if (::android::Thread::exitPending()) {
 | |
|         LOG(WARNING) << "NodeLooperThread is exiting";
 | |
|         return false;
 | |
|     }
 | |
|     if (!::android::Thread::isRunning()) {
 | |
|         LOG(WARNING) << "NodeLooperThread is not running, request " << hint_type;
 | |
|     }
 | |
| 
 | |
|     bool ret = true;
 | |
|     ::android::AutoMutex _l(lock_);
 | |
|     for (const auto& a : actions) {
 | |
|         if (!a.enable_property.empty() &&
 | |
|             !android::base::GetBoolProperty(a.enable_property, true)) {
 | |
|             // Disabled action based on its control property
 | |
|             continue;
 | |
|         }
 | |
|         if (a.node_index >= nodes_.size()) {
 | |
|             LOG(ERROR) << "Node index out of bound: " << a.node_index
 | |
|                        << " ,size: " << nodes_.size();
 | |
|             ret = false;
 | |
|         } else {
 | |
|             // End time set to steady time point max
 | |
|             ReqTime end_time = ReqTime::max();
 | |
|             // Timeout is non-zero
 | |
|             if (a.timeout_ms != std::chrono::milliseconds::zero()) {
 | |
|                 auto now = std::chrono::steady_clock::now();
 | |
|                 // Overflow protection in case timeout_ms is too big to overflow
 | |
|                 // time point which is unsigned integer
 | |
|                 if (std::chrono::duration_cast<std::chrono::milliseconds>(
 | |
|                         ReqTime::max() - now) > a.timeout_ms) {
 | |
|                     end_time = now + a.timeout_ms;
 | |
|                 }
 | |
|             }
 | |
|             ret = nodes_[a.node_index]->AddRequest(a.value_index, hint_type,
 | |
|                                                    end_time) &&
 | |
|                   ret;
 | |
|         }
 | |
|     }
 | |
|     wake_cond_.signal();
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| bool NodeLooperThread::Cancel(const std::vector<NodeAction>& actions,
 | |
|                               const std::string& hint_type) {
 | |
|     if (::android::Thread::exitPending()) {
 | |
|         LOG(WARNING) << "NodeLooperThread is exiting";
 | |
|         return false;
 | |
|     }
 | |
|     if (!::android::Thread::isRunning()) {
 | |
|         LOG(WARNING) << "NodeLooperThread is not running, cancel " << hint_type;
 | |
|     }
 | |
| 
 | |
|     bool ret = true;
 | |
|     ::android::AutoMutex _l(lock_);
 | |
|     for (const auto& a : actions) {
 | |
|         if (a.node_index >= nodes_.size()) {
 | |
|             LOG(ERROR) << "Node index out of bound: " << a.node_index
 | |
|                        << " ,size: " << nodes_.size();
 | |
|             ret = false;
 | |
|         } else {
 | |
|             nodes_[a.node_index]->RemoveRequest(hint_type);
 | |
|         }
 | |
|     }
 | |
|     wake_cond_.signal();
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| void NodeLooperThread::DumpToFd(int fd) {
 | |
|     ::android::AutoMutex _l(lock_);
 | |
|     for (auto& n : nodes_) {
 | |
|         n->DumpToFd(fd);
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool NodeLooperThread::threadLoop() {
 | |
|     ::android::AutoMutex _l(lock_);
 | |
|     std::chrono::milliseconds timeout_ms = kMaxUpdatePeriod;
 | |
| 
 | |
|     // Update 2 passes: some node may have dependency in other node
 | |
|     // e.g. update cpufreq min to VAL while cpufreq max still set to
 | |
|     // a value lower than VAL, is expected to fail in first pass
 | |
|     ATRACE_BEGIN("update_nodes");
 | |
|     for (auto& n : nodes_) {
 | |
|         n->Update(false);
 | |
|     }
 | |
|     for (auto& n : nodes_) {
 | |
|         timeout_ms = std::min(n->Update(true), timeout_ms);
 | |
|     }
 | |
|     ATRACE_END();
 | |
| 
 | |
|     nsecs_t sleep_timeout_ns = std::numeric_limits<nsecs_t>::max();
 | |
|     if (timeout_ms.count() < sleep_timeout_ns / 1000 / 1000) {
 | |
|         sleep_timeout_ns = timeout_ms.count() * 1000 * 1000;
 | |
|     }
 | |
|     // VERBOSE level won't print by default in user/userdebug build
 | |
|     LOG(VERBOSE) << "NodeLooperThread will wait for " << sleep_timeout_ns
 | |
|                  << "ns";
 | |
|     ATRACE_BEGIN("wait");
 | |
|     wake_cond_.waitRelative(lock_, sleep_timeout_ns);
 | |
|     ATRACE_END();
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool NodeLooperThread::Start() {
 | |
|     auto ret = this->run("NodeLooperThread", PRIORITY_HIGHEST);
 | |
|     if (ret != NO_ERROR) {
 | |
|         LOG(ERROR) << "NodeLooperThread start failed: " << ret;
 | |
|     } else {
 | |
|         LOG(INFO) << "NodeLooperThread started";
 | |
|     }
 | |
|     return ret == NO_ERROR;
 | |
| }
 | |
| 
 | |
| void NodeLooperThread::Stop() {
 | |
|     if (::android::Thread::isRunning()) {
 | |
|         LOG(INFO) << "NodeLooperThread stopping";
 | |
|         {
 | |
|             ::android::AutoMutex _l(lock_);
 | |
|             wake_cond_.signal();
 | |
|             ::android::Thread::requestExit();
 | |
|         }
 | |
|         ::android::Thread::join();
 | |
|         LOG(INFO) << "NodeLooperThread stopped";
 | |
|     }
 | |
| }
 | |
| 
 | |
| }  // namespace perfmgr
 | |
| }  // namespace android
 |