1 /*
2  * Copyright (C) 2019 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 specific language governing permissions and
14  * limitations under the License.
15  */
16 #define LOG_TAG "pwrstats_util"
17 
18 #include "CstateResidencyDataProvider.h"
19 #include <dataproviders/DataProviderHelper.h>
20 
21 #include <regex>
22 #include <string>
23 #include <fstream>
24 #include <iostream>
25 #include <string>
26 
27 #include <android-base/parsedouble.h>
28 #include <android-base/logging.h>
29 
getImpl(PowerStatistic * stat) const30 int CstateResidencyDataProvider::getImpl(PowerStatistic* stat) const {
31     std::ifstream file("/sys/kernel/debug/lpm_stats/stats");
32 
33     std::smatch matches;
34     const std::regex searchExpr("\\[(.*?)\\] (.*?):");
35     std::string line;
36     const std::string searchStr = "total success time:";
37 
38     auto residencies = stat->mutable_c_state_residency();
39     while (std::getline(file, line)) {
40         if (std::regex_search(line, matches, searchExpr)) {
41             auto residency = residencies->add_residency();
42             residency->set_entity_name(matches[1]);
43             residency->set_state_name(matches[2]);
44 
45             while (std::getline(file, line)) {
46                 size_t pos = line.find(searchStr);
47                 if (pos != std::string::npos) {
48                     float val;
49                     if (android::base::ParseFloat(line.substr(pos + searchStr.size()), &val)) {
50                         residency->set_time_ms(static_cast<uint64_t>(val * 1000));
51                     } else {
52                         LOG(ERROR) << __func__ << ": failed to parse c-state data";
53                     }
54                     break;
55                 }
56             }
57         }
58     }
59 
60     // Sort entries first by entity_name, then by state_name.
61     // Sorting is needed to make interval processing efficient.
62     std::sort(residencies->mutable_residency()->begin(),
63         residencies->mutable_residency()->end(),
64         [](const auto& a, const auto& b) {
65             // First sort by entity_name, then by state_name
66             if (a.entity_name() != b.entity_name()) {
67                 return a.entity_name() < b.entity_name();
68             }
69 
70             return a.state_name() < b.state_name();
71         });
72     return 0;
73 }
74 
getImpl(const PowerStatistic & start,PowerStatistic * interval) const75 int CstateResidencyDataProvider::getImpl(const PowerStatistic& start, PowerStatistic* interval) const {
76     auto startResidency = start.c_state_residency().residency();
77     auto intervalResidency = interval->mutable_c_state_residency()->mutable_residency();
78 
79     if (0 != StateResidencyInterval(startResidency, intervalResidency)) {
80         interval->clear_c_state_residency();
81         return 1;
82     }
83 
84     return 0;
85 }
86 
dumpImpl(const PowerStatistic & stat,std::ostream * output) const87 void CstateResidencyDataProvider::dumpImpl(const PowerStatistic& stat,
88                                             std::ostream* output) const {
89     *output << "C-State Residencies:" << std::endl;
90     StateResidencyDump(stat.c_state_residency().residency(), output);
91 }
92 
typeOf() const93 PowerStatCase CstateResidencyDataProvider::typeOf() const {
94     return PowerStatCase::kCStateResidency;
95 }
96