Home | History | Annotate | Download | only in libperfmgr
      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 <set>
     20 
     21 #include <android-base/file.h>
     22 #include <android-base/logging.h>
     23 
     24 #include <json/reader.h>
     25 #include <json/value.h>
     26 
     27 #include "perfmgr/HintManager.h"
     28 
     29 namespace android {
     30 namespace perfmgr {
     31 
     32 bool HintManager::ValidateHint(const std::string& hint_type) const {
     33     if (nm_.get() == nullptr) {
     34         LOG(ERROR) << "NodeLooperThread not present";
     35         return false;
     36     }
     37     if (actions_.find(hint_type) == actions_.end()) {
     38         LOG(ERROR) << "PowerHint type not present in actions: " << hint_type;
     39         return false;
     40     }
     41     return true;
     42 }
     43 
     44 bool HintManager::DoHint(const std::string& hint_type) {
     45     LOG(VERBOSE) << "Do Powerhint: " << hint_type;
     46     return ValidateHint(hint_type)
     47                ? nm_->Request(actions_.at(hint_type), hint_type)
     48                : false;
     49 }
     50 
     51 bool HintManager::DoHint(const std::string& hint_type,
     52                          std::chrono::milliseconds timeout_ms_override) {
     53     LOG(VERBOSE) << "Do Powerhint: " << hint_type << " for "
     54                  << timeout_ms_override.count() << "ms";
     55     if (!ValidateHint(hint_type)) {
     56         return false;
     57     }
     58     std::vector<NodeAction> actions_override = actions_.at(hint_type);
     59     for (auto& action : actions_override) {
     60         action.timeout_ms = timeout_ms_override;
     61     }
     62     return nm_->Request(actions_override, hint_type);
     63 }
     64 
     65 bool HintManager::EndHint(const std::string& hint_type) {
     66     LOG(VERBOSE) << "End Powerhint: " << hint_type;
     67     return ValidateHint(hint_type)
     68                ? nm_->Cancel(actions_.at(hint_type), hint_type)
     69                : false;
     70 }
     71 
     72 bool HintManager::IsRunning() const {
     73     return (nm_.get() == nullptr) ? false : nm_->isRunning();
     74 }
     75 
     76 std::vector<std::string> HintManager::GetHints() const {
     77     std::vector<std::string> hints;
     78     for (auto const& action : actions_) {
     79         hints.push_back(action.first);
     80     }
     81     return hints;
     82 }
     83 
     84 void HintManager::DumpToFd(int fd) {
     85     std::string header(
     86         "========== Begin perfmgr nodes ==========\n"
     87         "Node Name\t"
     88         "Node Path\t"
     89         "Current Index\t"
     90         "Current Value\n");
     91     if (!android::base::WriteStringToFd(header, fd)) {
     92         LOG(ERROR) << "Failed to dump fd: " << fd;
     93     }
     94     nm_->DumpToFd(fd);
     95     std::string footer("==========  End perfmgr nodes  ==========\n");
     96     if (!android::base::WriteStringToFd(footer, fd)) {
     97         LOG(ERROR) << "Failed to dump fd: " << fd;
     98     }
     99     fsync(fd);
    100 }
    101 
    102 std::unique_ptr<HintManager> HintManager::GetFromJSON(
    103     const std::string& config_path) {
    104     std::string json_doc;
    105 
    106     if (!android::base::ReadFileToString(config_path, &json_doc)) {
    107         LOG(ERROR) << "Failed to read JSON config from " << config_path;
    108         return nullptr;
    109     }
    110 
    111     std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
    112     if (nodes.empty()) {
    113         LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
    114         return nullptr;
    115     }
    116     std::map<std::string, std::vector<NodeAction>> actions =
    117         HintManager::ParseActions(json_doc, nodes);
    118 
    119     if (actions.empty()) {
    120         LOG(ERROR) << "Failed to parse Actions section from " << config_path;
    121         return nullptr;
    122     }
    123 
    124     sp<NodeLooperThread> nm = new NodeLooperThread(std::move(nodes));
    125     std::unique_ptr<HintManager> hm =
    126         std::make_unique<HintManager>(std::move(nm), actions);
    127 
    128     LOG(INFO) << "Initialized HintManager from JSON config: " << config_path;
    129     return hm;
    130 }
    131 
    132 std::vector<std::unique_ptr<Node>> HintManager::ParseNodes(
    133     const std::string& json_doc) {
    134     // function starts
    135     std::vector<std::unique_ptr<Node>> nodes_parsed;
    136     std::set<std::string> nodes_name_parsed;
    137     std::set<std::string> nodes_path_parsed;
    138     Json::Value root;
    139     Json::Reader reader;
    140 
    141     if (!reader.parse(json_doc, root)) {
    142         LOG(ERROR) << "Failed to parse JSON config";
    143         return nodes_parsed;
    144     }
    145 
    146     Json::Value nodes = root["Nodes"];
    147     for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) {
    148         std::string name = nodes[i]["Name"].asString();
    149         LOG(VERBOSE) << "Node[" << i << "]'s Name: " << name;
    150         if (name.empty()) {
    151             LOG(ERROR) << "Failed to read "
    152                        << "Node[" << i << "]'s Name";
    153             nodes_parsed.clear();
    154             return nodes_parsed;
    155         }
    156 
    157         auto result = nodes_name_parsed.insert(name);
    158         if (!result.second) {
    159             LOG(ERROR) << "Duplicate Node[" << i << "]'s Name";
    160             nodes_parsed.clear();
    161             return nodes_parsed;
    162         }
    163 
    164         std::string path = nodes[i]["Path"].asString();
    165         LOG(VERBOSE) << "Node[" << i << "]'s Path: " << path;
    166         if (path.empty()) {
    167             LOG(ERROR) << "Failed to read "
    168                        << "Node[" << i << "]'s Path";
    169             nodes_parsed.clear();
    170             return nodes_parsed;
    171         }
    172 
    173         result = nodes_path_parsed.insert(path);
    174         if (!result.second) {
    175             LOG(ERROR) << "Duplicate Node[" << i << "]'s Path";
    176             nodes_parsed.clear();
    177             return nodes_parsed;
    178         };
    179 
    180         std::vector<RequestGroup> values_parsed;
    181         Json::Value values = nodes[i]["Values"];
    182         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
    183             std::string value = values[j].asString();
    184             LOG(VERBOSE) << "Node[" << i << "]'s Value[" << j << "]: " << value;
    185             if (value.empty()) {
    186                 LOG(ERROR) << "Failed to read Node" << i << "'s Value[" << j
    187                            << "]";
    188                 nodes_parsed.clear();
    189                 return nodes_parsed;
    190             }
    191             values_parsed.emplace_back(value);
    192         }
    193         if (values_parsed.size() < 1) {
    194             LOG(ERROR) << "Failed to read Node" << i << "'s Values";
    195             nodes_parsed.clear();
    196             return nodes_parsed;
    197         }
    198 
    199         Json::UInt64 default_index = values_parsed.size() - 1;
    200         if (nodes[i]["DefaultIndex"].empty() ||
    201             !nodes[i]["DefaultIndex"].isUInt64()) {
    202             LOG(INFO) << "Failed to read Node" << i
    203                       << "'s DefaultIndex, set to last index: " << default_index;
    204         } else {
    205             default_index = nodes[i]["DefaultIndex"].asUInt64();
    206         }
    207         if (default_index > values_parsed.size() - 1) {
    208             default_index = values_parsed.size() - 1;
    209             LOG(ERROR) << "Node" << i
    210                        << "'s DefaultIndex out of bound, max value index: "
    211                        << default_index;
    212             nodes_parsed.clear();
    213             return nodes_parsed;
    214         }
    215         LOG(VERBOSE) << "Node[" << i << "]'s DefaultIndex: " << default_index;
    216 
    217         bool reset = false;
    218         if (nodes[i]["ResetOnInit"].empty() ||
    219             !nodes[i]["ResetOnInit"].isBool()) {
    220             LOG(INFO) << "Failed to read Node" << i
    221                       << "'s ResetOnInit, set to 'false'";
    222         } else {
    223             reset = nodes[i]["ResetOnInit"].asBool();
    224         }
    225         LOG(VERBOSE) << "Node[" << i << "]'s ResetOnInit: " << reset;
    226 
    227         bool hold_fd = false;
    228         if (nodes[i]["HoldFd"].empty() || !nodes[i]["HoldFd"].isBool()) {
    229             LOG(INFO) << "Failed to read Node" << i
    230                       << "'s HoldFd, set to 'false'";
    231         } else {
    232             hold_fd = nodes[i]["HoldFd"].asBool();
    233         }
    234         LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << hold_fd;
    235 
    236         nodes_parsed.emplace_back(std::make_unique<Node>(
    237             name, path, values_parsed, static_cast<std::size_t>(default_index),
    238             reset, hold_fd));
    239     }
    240     LOG(INFO) << nodes_parsed.size() << " Nodes parsed successfully";
    241     return nodes_parsed;
    242 }
    243 
    244 std::map<std::string, std::vector<NodeAction>> HintManager::ParseActions(
    245     const std::string& json_doc,
    246     const std::vector<std::unique_ptr<Node>>& nodes) {
    247     // function starts
    248     std::map<std::string, std::vector<NodeAction>> actions_parsed;
    249     Json::Value root;
    250     Json::Reader reader;
    251 
    252     if (!reader.parse(json_doc, root)) {
    253         LOG(ERROR) << "Failed to parse JSON config";
    254         return actions_parsed;
    255     }
    256 
    257     Json::Value actions = root["Actions"];
    258     std::size_t total_parsed = 0;
    259 
    260     std::map<std::string, std::size_t> nodes_index;
    261     for (std::size_t i = 0; i < nodes.size(); ++i) {
    262         nodes_index[nodes[i]->GetName()] = i;
    263     }
    264 
    265     for (Json::Value::ArrayIndex i = 0; i < actions.size(); ++i) {
    266         const std::string& hint_type = actions[i]["PowerHint"].asString();
    267         LOG(VERBOSE) << "Action[" << i << "]'s PowerHint: " << hint_type;
    268         if (hint_type.empty()) {
    269             LOG(ERROR) << "Failed to read "
    270                        << "Action[" << i << "]'s PowerHint";
    271             actions_parsed.clear();
    272             return actions_parsed;
    273         }
    274 
    275         std::string node_name = actions[i]["Node"].asString();
    276         LOG(VERBOSE) << "Action[" << i << "]'s Node: " << node_name;
    277         std::size_t node_index;
    278 
    279         if (nodes_index.find(node_name) == nodes_index.end()) {
    280             LOG(ERROR) << "Failed to find "
    281                        << "Action" << i
    282                        << "'s Node from Nodes section: " << node_name;
    283             actions_parsed.clear();
    284             return actions_parsed;
    285         }
    286         node_index = nodes_index[node_name];
    287 
    288         std::string value_name = actions[i]["Value"].asString();
    289         LOG(VERBOSE) << "Action[" << i << "]'s Value: " << value_name;
    290         std::size_t value_index = 0;
    291 
    292         if (!nodes[node_index]->GetValueIndex(value_name, &value_index)) {
    293             LOG(ERROR) << "Failed to read Action" << i << "'s Value";
    294             LOG(ERROR) << "Action[" << i << "]'s Value " << value_name
    295                        << " is not defined in Node[" << node_name;
    296             actions_parsed.clear();
    297             return actions_parsed;
    298         }
    299         LOG(VERBOSE) << "Action[" << i << "]'s ValueIndex: " << value_index;
    300 
    301         Json::UInt64 duration = 0;
    302         if (actions[i]["Duration"].empty() ||
    303             !actions[i]["Duration"].isUInt64()) {
    304             LOG(ERROR) << "Failed to read Action" << i << "'s Duration";
    305             actions_parsed.clear();
    306             return actions_parsed;
    307         } else {
    308             duration = actions[i]["Duration"].asUInt64();
    309         }
    310         LOG(VERBOSE) << "Action[" << i << "]'s Duration: " << duration;
    311 
    312         if (actions_parsed.find(hint_type) == actions_parsed.end()) {
    313             actions_parsed[hint_type] = std::vector<NodeAction>{
    314                 {node_index, value_index, std::chrono::milliseconds(duration)}};
    315         } else {
    316             for (const auto& action : actions_parsed[hint_type]) {
    317                 if (action.node_index == node_index) {
    318                     LOG(ERROR)
    319                         << "Action[" << i
    320                         << "]'s NodeIndex is duplicated with another Action";
    321                     actions_parsed.clear();
    322                     return actions_parsed;
    323                 }
    324             }
    325             actions_parsed[hint_type].emplace_back(
    326                 node_index, value_index, std::chrono::milliseconds(duration));
    327         }
    328 
    329         ++total_parsed;
    330     }
    331 
    332     LOG(INFO) << total_parsed << " Actions parsed successfully";
    333 
    334     for (const auto& action : actions_parsed) {
    335         LOG(INFO) << "PowerHint " << action.first << " has "
    336                   << action.second.size() << " actions parsed";
    337     }
    338 
    339     return actions_parsed;
    340 }
    341 
    342 }  // namespace perfmgr
    343 }  // namespace android
    344