blob: b8d40eae19b78a85cc3bed4239b5b12c504f9310 [file] [log] [blame]
Darren Hsu673d3b02021-12-28 21:31:24 +08001/*
2 * Copyright (C) 2020 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
17#include "AocStateResidencyDataProvider.h"
18
19#include <android-base/logging.h>
Darren Hsuaee3d1a2022-03-28 14:26:25 +080020#include <chrono>
21#include <pthread.h>
Darren Hsu673d3b02021-12-28 21:31:24 +080022
23namespace aidl {
24namespace android {
25namespace hardware {
26namespace power {
27namespace stats {
28
Darren Hsuaee3d1a2022-03-28 14:26:25 +080029struct async_data_t {
30 pthread_cond_t *cond;
31 pthread_mutex_t *lock;
32 std::unordered_map<std::string, std::vector<StateResidency>> *residencies;
33 std::unordered_map<std::string,
34 std::vector<std::unique_ptr<GenericStateResidencyDataProvider>>> *providers;
35};
36
Darren Hsu673d3b02021-12-28 21:31:24 +080037AocStateResidencyDataProvider::AocStateResidencyDataProvider(std::vector<std::pair<std::string,
Darren Hsuaee3d1a2022-03-28 14:26:25 +080038 std::string>> ids, std::vector<std::pair<std::string, std::string>> states,
39 const uint64_t timeoutMillis) {
Darren Hsu673d3b02021-12-28 21:31:24 +080040 // AoC stats are reported in ticks of 244.140625ns. The transform
41 // function converts ticks to milliseconds.
42 // 1000000 / 244.140625 = 4096.
43 static const uint64_t AOC_CLK = 4096;
Darren Hsuaee3d1a2022-03-28 14:26:25 +080044 static const uint64_t TIMEOUT_MILLIS = 120;
Darren Hsu673d3b02021-12-28 21:31:24 +080045 std::function<uint64_t(uint64_t)> aocTickToMs = [](uint64_t a) { return a / AOC_CLK; };
46 GenericStateResidencyDataProvider::StateResidencyConfig config = {
47 .entryCountSupported = true,
48 .entryCountPrefix = "Counter:",
49 .totalTimeSupported = true,
50 .totalTimePrefix = "Cumulative time:",
51 .totalTimeTransform = aocTickToMs,
52 .lastEntrySupported = true,
53 .lastEntryPrefix = "Time last entered:",
54 .lastEntryTransform = aocTickToMs,
55 };
56 for (const auto &id : ids) {
57 for (const auto &state : states) {
58 std::vector<std::pair<std::string, std::string>> aocStateHeaders = {
59 std::make_pair(state.first, ""),
60 };
61 std::vector<GenericStateResidencyDataProvider::PowerEntityConfig> cfgs;
62 cfgs.emplace_back(generateGenericStateResidencyConfigs(config, aocStateHeaders),
63 id.first, "");
64 std::unique_ptr<GenericStateResidencyDataProvider> sdp(
65 new GenericStateResidencyDataProvider(id.second + state.second, cfgs));
66 mProviders[id.first].push_back(std::move(sdp));
67 }
68 }
Darren Hsuaee3d1a2022-03-28 14:26:25 +080069 mStateCount = states.size();
70 mTimeoutMillis = timeoutMillis == 0 ? TIMEOUT_MILLIS : timeoutMillis;
Darren Hsu673d3b02021-12-28 21:31:24 +080071}
72
Darren Hsuaee3d1a2022-03-28 14:26:25 +080073void *getStateResidenciesAsync(void *arg) {
74 struct async_data_t *async = (struct async_data_t*)arg;
75 const auto *originalContainer = async->residencies;
76
Darren Hsu673d3b02021-12-28 21:31:24 +080077 // States from the same power entity are merged.
Darren Hsuaee3d1a2022-03-28 14:26:25 +080078 for (const auto &providerList : *async->providers) {
Darren Hsu673d3b02021-12-28 21:31:24 +080079 int32_t stateId = 0;
80 std::string curEntity = providerList.first;
81 std::vector<StateResidency> stateResidencies;
82
83 // Iterate over each provider in the providerList, appending each of the states
84 for (const auto &provider : providerList.second) {
85 std::unordered_map<std::string, std::vector<StateResidency>> residency;
Darren Hsuaee3d1a2022-03-28 14:26:25 +080086 provider->getStateResidencies(&residency);
Darren Hsu673d3b02021-12-28 21:31:24 +080087
88 // Each provider should only return data for curEntity but checking anyway
89 if (residency.find(curEntity) != residency.end()) {
90 for (auto &r : residency.at(curEntity)) {
91 /*
92 * Modifying stateId here because we are stitching together infos from
93 * multiple GenericStateResidencyDataProviders. stateId must be modified
94 * to maintain uniqueness for a given entity
95 */
96 r.id = stateId++;
97 stateResidencies.push_back(r);
98 }
99 }
100 }
101
Darren Hsuaee3d1a2022-03-28 14:26:25 +0800102 if (async->residencies != originalContainer) {
103 /*
104 * When provider->gretStateResidencies() exceeds timeout expiration, the main thread
105 * stops waiting and continue, then the original residency pointer is erased in the
106 * main thread when AocStateResidencyDataProvider::getStateResidencies() ends, and new
107 * container will be created in the async thread later. In this situation, we ignore
108 * delayed residency data and end the async thread.
109 */
110 return 0;
111 }
112
113 async->residencies->emplace(curEntity, stateResidencies);
Darren Hsu673d3b02021-12-28 21:31:24 +0800114 }
Darren Hsuaee3d1a2022-03-28 14:26:25 +0800115
116 pthread_mutex_lock(async->lock);
117 pthread_cond_signal(async->cond);
118 pthread_mutex_unlock(async->lock);
119
120 return 0;
121}
122
123bool AocStateResidencyDataProvider::getStateResidencies(
124 std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
125 bool ret = true;
126 int condResult = 0;
127 pthread_t tid;
128 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
129 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
130 std::unordered_map<std::string, std::vector<StateResidency>> stateResidencies;
131 struct timespec start, timeout;
132 struct async_data_t async = {
133 .cond = &cond,
134 .lock = &lock,
135 .residencies = &stateResidencies,
136 .providers = &mProviders
137 };
138
139 pthread_create(&tid, NULL, &getStateResidenciesAsync, (void*)&async);
140
141 clock_gettime(CLOCK_REALTIME, &start);
142
143 uint64_t expirationMillis = mTimeoutMillis * mStateCount;
144 timeout.tv_sec = start.tv_sec + expirationMillis / 1000;
145 uint64_t nsec = start.tv_nsec + (expirationMillis % 1000) * 1000000;
146 if (nsec < 1000000000) {
147 timeout.tv_nsec = nsec;
148 } else {
149 timeout.tv_sec += 1;
150 timeout.tv_nsec = nsec - 1000000000;
151 }
152
153 pthread_mutex_lock(&lock);
154 condResult = pthread_cond_timedwait(&cond, &lock, &timeout);
155 pthread_mutex_unlock(&lock);
156
157 if (condResult != 0) {
158 if (condResult == ETIMEDOUT) {
159 LOG(WARNING) << __func__ << " latency for AoC timeout: " << expirationMillis << " ms";
160 } else {
161 LOG(ERROR) << "Failed to wait for the condition variable: " << condResult;
162 }
163 ret = false;
164 } else {
165 for (const auto &residency : stateResidencies) {
166 residencies->emplace(residency.first, residency.second);
167 }
168 }
169
Darren Hsu673d3b02021-12-28 21:31:24 +0800170 return ret;
171}
172
173std::unordered_map<std::string, std::vector<State>> AocStateResidencyDataProvider::getInfo() {
174 // States from the same power entity are merged
175 std::unordered_map<std::string, std::vector<State>> infos;
176 for (const auto &providerList : mProviders) {
177 int32_t stateId = 0;
178 std::string curEntity = providerList.first;
179 std::vector<State> stateInfos;
180
181 // Iterate over each provider in the providerList, appending each of the states
182 for (const auto &provider : providerList.second) {
183 std::unordered_map<std::string, std::vector<State>> info = provider->getInfo();
184
185 // Each provider should only return data for curEntity but checking anyway
186 if (info.find(curEntity) != info.end()) {
187 for (auto &i : info.at(curEntity)) {
188 /*
189 * Modifying stateId because we are stitching together infos from
190 * multiple GenericStateResidencyDataProviders. stateId must be modified
191 * to maintain uniqueness for a given entity
192 */
193 i.id = stateId++;
194 stateInfos.push_back(i);
195 }
196 }
197 }
198
199 infos.emplace(curEntity, stateInfos);
200 }
201
202 return infos;
203}
204
205} // namespace stats
206} // namespace power
207} // namespace hardware
208} // namespace android
209} // namespace aidl