blob: 2a17a4312e6a11e6c90bbb5cfe3fb391c1fa4526 [file] [log] [blame]
Benjamin Schwartz683e61c2018-11-05 11:24:10 -08001/*
2 * Copyright (C) 2018 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
Benjamin Schwartz012a5ba2018-11-06 14:28:21 -080017#define LOG_TAG "libpixelpowerstats"
18
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -070019#include <memory>
20#include <string>
21#include <unordered_map>
22#include <utility>
23#include <vector>
24
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -080025#include <pixelpowerstats/PowerStats.h>
Benjamin Schwartzddac36e2018-11-30 10:46:41 -080026
27#include <android-base/file.h>
Benjamin Schwartz6d141702018-11-14 11:56:43 -080028#include <android-base/logging.h>
Benjamin Schwartzddac36e2018-11-30 10:46:41 -080029#include <android-base/stringprintf.h>
30
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -080031#include <inttypes.h>
32#include <time.h>
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080033
34namespace android {
35namespace hardware {
36namespace power {
37namespace stats {
38namespace V1_0 {
39namespace implementation {
40
Benjamin Schwartz37d7b622018-11-08 10:04:34 -080041void PowerStats::setRailDataProvider(std::unique_ptr<IRailDataProvider> dataProvider) {
42 mRailDataProvider = std::move(dataProvider);
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080043}
44
45Return<void> PowerStats::getRailInfo(getRailInfo_cb _hidl_cb) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -080046 if (!mRailDataProvider) {
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080047 _hidl_cb({}, Status::NOT_SUPPORTED);
48 return Void();
49 }
Benjamin Schwartz6d141702018-11-14 11:56:43 -080050
51 return mRailDataProvider->getRailInfo(_hidl_cb);
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080052}
53
54Return<void> PowerStats::getEnergyData(const hidl_vec<uint32_t> &railIndices,
55 getEnergyData_cb _hidl_cb) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -080056 if (!mRailDataProvider) {
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080057 _hidl_cb({}, Status::NOT_SUPPORTED);
58 return Void();
59 }
Benjamin Schwartz6d141702018-11-14 11:56:43 -080060
61 return mRailDataProvider->getEnergyData(railIndices, _hidl_cb);
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080062}
63
64Return<void> PowerStats::streamEnergyData(uint32_t timeMs, uint32_t samplingRate,
65 streamEnergyData_cb _hidl_cb) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -080066 if (!mRailDataProvider) {
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080067 _hidl_cb({}, 0, 0, Status::NOT_SUPPORTED);
68 return Void();
69 }
Benjamin Schwartz6d141702018-11-14 11:56:43 -080070
71 return mRailDataProvider->streamEnergyData(timeMs, samplingRate, _hidl_cb);
72}
73
Benjamin Schwartza991ef52018-12-04 13:48:52 -080074uint32_t PowerStats::addPowerEntity(const std::string &name, PowerEntityType type) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -080075 uint32_t id = mPowerEntityInfos.size();
76 mPowerEntityInfos.push_back({id, name, type});
77 return id;
78}
79
Benjamin Schwartz6317ff32019-02-06 12:37:57 -080080void PowerStats::addStateResidencyDataProvider(sp<IStateResidencyDataProvider> p) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -080081 std::vector<PowerEntityStateSpace> stateSpaces = p->getStateSpaces();
Benjamin Schwartzddac36e2018-11-30 10:46:41 -080082 for (auto stateSpace : stateSpaces) {
Benjamin Schwartza991ef52018-12-04 13:48:52 -080083 mPowerEntityStateSpaces.emplace(stateSpace.powerEntityId, stateSpace);
84 mStateResidencyDataProviders.emplace(stateSpace.powerEntityId, p);
Benjamin Schwartz6d141702018-11-14 11:56:43 -080085 }
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080086}
87
88Return<void> PowerStats::getPowerEntityInfo(getPowerEntityInfo_cb _hidl_cb) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -080089 // If not configured, return NOT_SUPPORTED
90 if (mPowerEntityInfos.empty()) {
91 _hidl_cb({}, Status::NOT_SUPPORTED);
92 return Void();
93 }
94
95 _hidl_cb(mPowerEntityInfos, Status::SUCCESS);
Benjamin Schwartz683e61c2018-11-05 11:24:10 -080096 return Void();
97}
98
99Return<void> PowerStats::getPowerEntityStateInfo(const hidl_vec<uint32_t> &powerEntityIds,
100 getPowerEntityStateInfo_cb _hidl_cb) {
Benjamin Schwartz37d7b622018-11-08 10:04:34 -0800101 // If not configured, return NOT_SUPPORTED
102 if (mPowerEntityStateSpaces.empty()) {
103 _hidl_cb({}, Status::NOT_SUPPORTED);
104 return Void();
105 }
106
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800107 std::vector<PowerEntityStateSpace> stateSpaces;
Benjamin Schwartz37d7b622018-11-08 10:04:34 -0800108
109 // If powerEntityIds is empty then return state space info for all entities
110 if (powerEntityIds.size() == 0) {
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800111 stateSpaces.reserve(mPowerEntityStateSpaces.size());
Benjamin Schwartz37d7b622018-11-08 10:04:34 -0800112 for (auto i : mPowerEntityStateSpaces) {
Benjamin Schwartza991ef52018-12-04 13:48:52 -0800113 stateSpaces.emplace_back(i.second);
Benjamin Schwartz37d7b622018-11-08 10:04:34 -0800114 }
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800115 _hidl_cb(stateSpaces, Status::SUCCESS);
Benjamin Schwartz37d7b622018-11-08 10:04:34 -0800116 return Void();
117 }
118
119 // Return state space information only for valid ids
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800120 auto ret = Status::SUCCESS;
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800121 stateSpaces.reserve(powerEntityIds.size());
122 for (const uint32_t id : powerEntityIds) {
123 auto stateSpace = mPowerEntityStateSpaces.find(id);
124 if (stateSpace != mPowerEntityStateSpaces.end()) {
Benjamin Schwartza991ef52018-12-04 13:48:52 -0800125 stateSpaces.emplace_back(stateSpace->second);
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800126 } else {
127 ret = Status::INVALID_INPUT;
Benjamin Schwartz37d7b622018-11-08 10:04:34 -0800128 }
129 }
130
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800131 _hidl_cb(stateSpaces, ret);
Benjamin Schwartz683e61c2018-11-05 11:24:10 -0800132 return Void();
133}
134
135Return<void> PowerStats::getPowerEntityStateResidencyData(
136 const hidl_vec<uint32_t> &powerEntityIds, getPowerEntityStateResidencyData_cb _hidl_cb) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800137 // If not configured, return NOT_SUPPORTED
138 if (mStateResidencyDataProviders.empty() || mPowerEntityStateSpaces.empty()) {
139 _hidl_cb({}, Status::NOT_SUPPORTED);
140 return Void();
141 }
142
143 // If powerEntityIds is empty then return data for all supported entities
144 if (powerEntityIds.size() == 0) {
145 std::vector<uint32_t> ids;
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800146 for (auto stateSpace : mPowerEntityStateSpaces) {
Benjamin Schwartza991ef52018-12-04 13:48:52 -0800147 ids.emplace_back(stateSpace.first);
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800148 }
149 return getPowerEntityStateResidencyData(ids, _hidl_cb);
150 }
151
Benjamin Schwartz383b1292019-01-16 11:16:40 -0800152 std::unordered_map<uint32_t, PowerEntityStateResidencyResult> stateResidencies;
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800153 std::vector<PowerEntityStateResidencyResult> results;
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800154 results.reserve(powerEntityIds.size());
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800155
156 // return results for only the given powerEntityIds
157 bool invalidInput = false;
158 bool filesystemError = false;
159 for (auto id : powerEntityIds) {
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800160 auto dataProvider = mStateResidencyDataProviders.find(id);
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800161 // skip if the given powerEntityId does not have an associated StateResidencyDataProvider
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800162 if (dataProvider == mStateResidencyDataProviders.end()) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800163 invalidInput = true;
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800164 continue;
165 }
166
167 // get the results if we have not already done so.
168 if (stateResidencies.find(id) == stateResidencies.end()) {
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800169 if (!dataProvider->second->getResults(stateResidencies)) {
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800170 filesystemError = true;
171 }
172 }
173
174 // append results
Benjamin Schwartz3b2518d2018-11-28 09:34:02 -0800175 auto stateResidency = stateResidencies.find(id);
176 if (stateResidency != stateResidencies.end()) {
Benjamin Schwartza991ef52018-12-04 13:48:52 -0800177 results.emplace_back(stateResidency->second);
Benjamin Schwartz6d141702018-11-14 11:56:43 -0800178 }
179 }
180
181 auto ret = Status::SUCCESS;
182 if (filesystemError) {
183 ret = Status::FILESYSTEM_ERROR;
184 } else if (invalidInput) {
185 ret = Status::INVALID_INPUT;
186 }
187
188 _hidl_cb(results, ret);
Benjamin Schwartz683e61c2018-11-05 11:24:10 -0800189 return Void();
190}
191
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800192//
193// Debugging utilities to support printing data via debug()
194//
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800195
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700196static uint64_t getTimeElapsedMs(const struct timespec &now, const struct timespec &then) {
197 uint64_t thenMs = then.tv_sec * 1000 + (then.tv_nsec / 1000000);
198 uint64_t nowMs = now.tv_sec * 1000 + (now.tv_nsec / 1000000);
199 return (nowMs - thenMs);
200}
201
202static const char RESIDENCY_HEADER[] =
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800203 "\n============= PowerStats HAL 1.0 state residencies ==============\n";
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700204static const char RESIDENCY_FOOTER[] =
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800205 "========== End of PowerStats HAL 1.0 state residencies ==========\n";
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800206
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800207static bool DumpResidencyDataToFd(
208 const std::unordered_map<uint32_t, std::string> &entityNames,
209 const std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> stateNames,
210 const hidl_vec<PowerEntityStateResidencyResult> &results, int fd) {
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800211 std::ostringstream dumpStats;
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700212 const char *headerFormat = " %14s %14s %16s %15s %17s\n";
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800213 const char *dataFormat =
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700214 " %14s %14s %13" PRIu64 " ms %15" PRIu64 " %14" PRIu64 " ms\n";
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800215
216 dumpStats << RESIDENCY_HEADER;
Benjamin Schwartz383b1292019-01-16 11:16:40 -0800217 dumpStats << android::base::StringPrintf(headerFormat, "Entity", "State", "Total time",
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700218 "Total entries", "Last entry tstamp");
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800219
220 for (auto result : results) {
221 for (auto stateResidency : result.stateResidencyData) {
222 dumpStats << android::base::StringPrintf(
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800223 dataFormat, entityNames.at(result.powerEntityId).c_str(),
224 stateNames.at(result.powerEntityId)
225 .at(stateResidency.powerEntityStateId).c_str(),
226 stateResidency.totalTimeInStateMs, stateResidency.totalStateEntryCount,
227 stateResidency.lastEntryTimestampMs);
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800228 }
229 }
230
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800231 dumpStats << RESIDENCY_FOOTER;
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800232
233 return android::base::WriteStringToFd(dumpStats.str(), fd);
234}
235
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800236static bool DumpResidencyDataDiffToFd(
237 const std::unordered_map<uint32_t, std::string> &entityNames,
238 const std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> stateNames,
239 uint64_t elapsedTimeMs, const hidl_vec<PowerEntityStateResidencyResult> &prevResults,
240 const hidl_vec<PowerEntityStateResidencyResult> &results, int fd) {
241 std::ostringstream dumpStats;
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700242 const char *headerFormat = " %14s %14s %16s (%14s) %15s (%16s) %17s (%14s)\n";
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800243 const char *dataFormatWithDelta =
244 " %14s %14s %13" PRIu64 " ms (%14" PRId64 ") %15" PRIu64 " (%16" PRId64 ")"
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700245 " %14" PRIu64 " ms (%14" PRId64 ")\n";
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800246 const char *dataFormatWithoutDelta =
247 " %14s %14s %13" PRIu64 " ms ( none) %15" PRIu64 " ( none)"
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700248 " %14" PRIu64 " ms ( none)\n";
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800249
250 dumpStats << RESIDENCY_HEADER;
251 dumpStats << "Elapsed time: "
252 << (elapsedTimeMs == 0 ? "unknown" : std::to_string(elapsedTimeMs)) << " ms\n";
253
254 dumpStats << android::base::StringPrintf(headerFormat, "Entity", "State", "Total time",
255 "Delta ", "Total entries", "Delta ",
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700256 "Last entry tstamp", "Delta ");
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800257
258 // Process prevResults into a 2-tier lookup table for easy reference
259 std::unordered_map<uint32_t, std::unordered_map<uint32_t, PowerEntityStateResidencyData>>
260 prevResultsMap;
261 for (auto prevResult : prevResults) {
262 prevResultsMap.emplace(prevResult.powerEntityId,
263 std::unordered_map<uint32_t, PowerEntityStateResidencyData>());
264 for (auto stateResidency : prevResult.stateResidencyData) {
265 prevResultsMap.at(prevResult.powerEntityId)
266 .emplace(stateResidency.powerEntityStateId, stateResidency);
267 }
268 }
269
270 // Iterate over the new result data (one "result" per entity)
271 for (auto result : results) {
272 uint32_t entityId = result.powerEntityId;
273 const char *entityName = entityNames.at(entityId).c_str();
274
275 // Look up previous result data for the same entity
276 auto prevEntityResultIt = prevResultsMap.find(entityId);
277
278 // Iterate over individual states within the current entity's new result
279 for (auto stateResidency : result.stateResidencyData) {
280 uint32_t stateId = stateResidency.powerEntityStateId;
281 const char *stateName = stateNames.at(entityId).at(stateId).c_str();
282
283 // If a previous result was found for the same entity, see if that
284 // result also contains data for the current state
285 bool prevValueFound = false;
286 if (prevEntityResultIt != prevResultsMap.end()) {
287 auto prevStateResidencyIt = prevEntityResultIt->second.find(stateId);
288 // If a previous result was found for the current entity and state, calculate the
289 // deltas and display them along with new result
290 if (prevStateResidencyIt != prevEntityResultIt->second.end()) {
291 int64_t deltaTotalTime = stateResidency.totalTimeInStateMs -
292 prevStateResidencyIt->second.totalTimeInStateMs;
293 int64_t deltaTotalCount = stateResidency.totalStateEntryCount -
294 prevStateResidencyIt->second.totalStateEntryCount;
295 int64_t deltaTimestamp = stateResidency.lastEntryTimestampMs -
296 prevStateResidencyIt->second.lastEntryTimestampMs;
297
298 dumpStats << android::base::StringPrintf(
299 dataFormatWithDelta, entityName, stateName,
300 stateResidency.totalTimeInStateMs, deltaTotalTime,
301 stateResidency.totalStateEntryCount, deltaTotalCount,
302 stateResidency.lastEntryTimestampMs, deltaTimestamp);
303 prevValueFound = true;
304 }
305 }
306
307 // If no previous result was found for the current entity and state, display the new
308 // result without deltas
309 if (!prevValueFound) {
310 dumpStats << android::base::StringPrintf(
311 dataFormatWithoutDelta, entityName, stateName,
312 stateResidency.totalTimeInStateMs, stateResidency.totalStateEntryCount,
313 stateResidency.lastEntryTimestampMs);
314 }
315 }
316 }
317
318 dumpStats << RESIDENCY_FOOTER;
319
320 return android::base::WriteStringToFd(dumpStats.str(), fd);
321}
322
323void PowerStats::debugStateResidency(const std::unordered_map<uint32_t, std::string> &entityNames,
324 int fd, bool delta) {
325 static struct timespec prevDataTime;
326 static bool prevDataTimeValid = false;
327 struct timespec dataTime;
328 bool dataTimeValid;
329
330 // Get power entity state space information
331 Status status;
332 hidl_vec<PowerEntityStateSpace> stateSpaces;
333 getPowerEntityStateInfo({}, [&status, &stateSpaces](auto rStateSpaces, auto rStatus) {
334 status = rStatus;
335 stateSpaces = rStateSpaces;
336 });
337 if (status != Status::SUCCESS) {
338 LOG(ERROR) << "Error getting state info";
339 return;
340 }
341
342 // Construct lookup table of powerEntityId, powerEntityStateId to state name
343 std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> stateNames;
344 for (auto stateSpace : stateSpaces) {
345 stateNames.emplace(stateSpace.powerEntityId, std::unordered_map<uint32_t, std::string>());
346 auto &entityStateNames = stateNames.at(stateSpace.powerEntityId);
347 for (auto state : stateSpace.states) {
348 entityStateNames.emplace(state.powerEntityStateId, state.powerEntityStateName);
349 }
350 }
351
352 // Get power entity state residency data
353 hidl_vec<PowerEntityStateResidencyResult> results;
354 getPowerEntityStateResidencyData(
355 {}, [&status, &results, &dataTime, &dataTimeValid](auto rResults, auto rStatus) {
356 status = rStatus;
357 results = rResults;
358 dataTimeValid = (clock_gettime(CLOCK_BOOTTIME, &dataTime) == 0);
359 });
360
361 // This implementation of getPowerEntityStateResidencyData supports the
362 // return of partial results if status == FILESYSTEM_ERROR.
363 if (status != Status::SUCCESS) {
364 LOG(ERROR) << "Error getting residency data -- Some results missing";
365 }
366
367 if (!delta) {
368 // If no delta argument was supplied, just dump the latest data
369 if (!DumpResidencyDataToFd(entityNames, stateNames, results, fd)) {
370 PLOG(ERROR) << "Failed to dump residency data to fd";
371 }
372 } else {
373 // If the delta argument was supplied, calculate the elapsed time since the previous
374 // result and then dump the latest data along with elapsed time and deltas
375 static hidl_vec<PowerEntityStateResidencyResult> prevResults;
376 uint64_t elapsedTimeMs = 0;
377 if (dataTimeValid && prevDataTimeValid) {
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700378 elapsedTimeMs = getTimeElapsedMs(dataTime, prevDataTime);
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800379 }
380
381 if (!DumpResidencyDataDiffToFd(entityNames, stateNames, elapsedTimeMs, prevResults,
382 results, fd)) {
383 PLOG(ERROR) << "Failed to dump residency data delta to fd";
384 }
385
386 prevResults = results;
387 prevDataTime = dataTime;
388 prevDataTimeValid = dataTimeValid;
389 }
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700390}
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800391
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700392static const char ENERGYDATA_HEADER[] =
393 "\n============= PowerStats HAL 1.0 rail energy data ==============\n";
394static const char ENERGYDATA_FOOTER[] =
395 "========== End of PowerStats HAL 1.0 rail energy data ==========\n";
396
397static bool DumpEnergyDataToFd(
398 const std::unordered_map<uint32_t, std::pair<std::string, std::string>> &railNames,
399 const hidl_vec<EnergyData> &energyData, int fd) {
400 std::ostringstream dumpStats;
401 const char *headerFormat = " %14s %18s %18s\n";
402 const char *dataFormat = " %14s %18s %14.2f mWs\n";
403
404 dumpStats << ENERGYDATA_HEADER;
Benjamin Schwartzfc0aa7b2019-03-18 16:09:37 -0700405 dumpStats << android::base::StringPrintf(headerFormat, "Subsys", "Rail", "Cumulative Energy");
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700406
407 for (auto data : energyData) {
408 dumpStats << android::base::StringPrintf(dataFormat, railNames.at(data.index).first.c_str(),
409 railNames.at(data.index).second.c_str(),
410 static_cast<float>(data.energy) / 1000.0);
411 }
412
413 dumpStats << ENERGYDATA_FOOTER;
414
415 return android::base::WriteStringToFd(dumpStats.str(), fd);
416}
417
418static bool DumpEnergyDataDiffToFd(
419 const std::unordered_map<uint32_t, std::pair<std::string, std::string>> &railNames,
420 uint64_t elapsedTimeMs, const hidl_vec<EnergyData> &prevEnergyData,
421 const hidl_vec<EnergyData> &energyData, int fd) {
422 std::ostringstream dumpStats;
423 const char *headerFormat = " %14s %18s %18s (%14s)\n";
424 const char *dataFormatWithDelta = " %14s %18s %14.2f mWs (%14.2f)\n";
425 const char *dataFormatWithoutDelta = " %14s %18s %14.2f mWs ( none)\n";
426
427 dumpStats << ENERGYDATA_HEADER;
428 dumpStats << "Elapsed time: "
429 << (elapsedTimeMs == 0 ? "unknown" : std::to_string(elapsedTimeMs)) << " ms\n";
430
Benjamin Schwartzfc0aa7b2019-03-18 16:09:37 -0700431 dumpStats << android::base::StringPrintf(headerFormat, "Subsys", "Rail", "Cumulative Energy",
432 "Delta ");
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700433
434 std::unordered_map<uint32_t, uint64_t> prevEnergyDataMap;
435 for (auto data : prevEnergyData) {
436 prevEnergyDataMap.emplace(data.index, data.energy);
437 }
438
439 for (auto data : energyData) {
440 const char *subsysName = railNames.at(data.index).first.c_str();
441 const char *railName = railNames.at(data.index).second.c_str();
442
443 auto prevEnergyDataIt = prevEnergyDataMap.find(data.index);
444
445 if (prevEnergyDataIt != prevEnergyDataMap.end()) {
446 int64_t deltaEnergy = data.energy - prevEnergyDataIt->second;
447
448 dumpStats << android::base::StringPrintf(dataFormatWithDelta, subsysName, railName,
449 static_cast<float>(data.energy) / 1000.0,
450 static_cast<float>(deltaEnergy) / 1000.0);
451 } else {
452 dumpStats << android::base::StringPrintf(dataFormatWithoutDelta, subsysName, railName,
453 static_cast<float>(data.energy) / 1000.0);
454 }
455 }
456
457 dumpStats << ENERGYDATA_FOOTER;
458
459 return android::base::WriteStringToFd(dumpStats.str(), fd);
460}
461
462void PowerStats::debugEnergyData(int fd, bool delta) {
463 static struct timespec prevDataTime;
464 static bool prevDataTimeValid = false;
465 struct timespec dataTime;
466 bool dataTimeValid = false;
467
468 std::unordered_map<uint32_t, std::pair<std::string, std::string>> railNames;
469 getRailInfo([&railNames](auto infos, auto /* status */) {
470 // Don't care about the status. infos will be nonempty if rail energy is supported.
471 for (auto info : infos) {
472 railNames.emplace(info.index, std::make_pair(info.subsysName, info.railName));
473 }
474 });
475 if (railNames.empty()) {
476 return;
477 }
478
479 Status status;
480 hidl_vec<EnergyData> energyData;
481 getEnergyData(
482 {}, [&status, &energyData, &dataTime, &dataTimeValid](auto rEnergyData, auto rStatus) {
483 status = rStatus;
484 energyData = rEnergyData;
485 dataTimeValid = (clock_gettime(CLOCK_BOOTTIME, &dataTime) == 0);
486 });
487
488 // getEnergyData returns no results if status != SUCCESS.
489 if (status != Status::SUCCESS) {
490 LOG(ERROR) << "Error getting rail data";
491 return;
492 }
493
494 if (!delta) {
495 if (!DumpEnergyDataToFd(railNames, energyData, fd)) {
496 PLOG(ERROR) << "Failed to dump energy data to fd";
497 }
498 } else {
499 // If the delta argument was supplied, calculate the elapsed time since the previous
500 // result and then dump the latest data along with elapsed time and deltas
501 static hidl_vec<EnergyData> prevEnergyData;
502 uint64_t elapsedTimeMs = 0;
503 if (dataTimeValid && prevDataTimeValid) {
504 elapsedTimeMs = getTimeElapsedMs(dataTime, prevDataTime);
505 }
506
507 if (!DumpEnergyDataDiffToFd(railNames, elapsedTimeMs, prevEnergyData, energyData, fd)) {
508 PLOG(ERROR) << "Failed to dump energy data delta to fd";
509 }
510
511 prevEnergyData = energyData;
512 prevDataTime = dataTime;
513 prevDataTimeValid = dataTimeValid;
514 }
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800515}
516
517Return<void> PowerStats::debug(const hidl_handle &handle, const hidl_vec<hidl_string> &args) {
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800518 if (handle == nullptr || handle->numFds < 1) {
519 return Void();
520 }
521
522 int fd = handle->data[0];
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800523 bool delta = (args.size() == 1) && (args[0] == "delta");
524
525 // Get power entity information, which is common across all supported data categories
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800526 Status status;
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700527 hidl_vec<PowerEntityInfo> stateInfos;
528 getPowerEntityInfo([&status, &stateInfos](auto rInfos, auto rStatus) {
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800529 status = rStatus;
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700530 stateInfos = rInfos;
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800531 });
532 if (status != Status::SUCCESS) {
533 LOG(ERROR) << "Error getting power entity info";
534 return Void();
535 }
536
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800537 // Construct lookup table of powerEntityId to name
538 std::unordered_map<uint32_t, std::string> entityNames;
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700539 for (auto info : stateInfos) {
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800540 entityNames.emplace(info.powerEntityId, info.powerEntityName);
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800541 }
542
Kelly Rossmoyer741f76c2019-02-13 14:52:18 -0800543 // Generate debug output for supported data categories
544 debugStateResidency(entityNames, fd, delta);
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800545
Benjamin Schwartz6663d0a2019-03-15 13:16:29 -0700546 // Generate debug output for energy data
547 debugEnergyData(fd, delta);
548
549 fsync(fd);
Benjamin Schwartzddac36e2018-11-30 10:46:41 -0800550 return Void();
551}
552
Benjamin Schwartz683e61c2018-11-05 11:24:10 -0800553} // namespace implementation
554} // namespace V1_0
555} // namespace stats
556} // namespace power
557} // namespace hardware
558} // namespace android