aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Hsu <darrenhsu@google.com>2022-04-19 08:40:05 +0800
committerDarren Hsu <darrenhsu@google.com>2022-04-20 07:45:56 +0000
commitdf08a31b762c00220673003b1f46b4b4746637e1 (patch)
treec130893e90c7e7e8763c64b643bca6577a8be6aa
parentf19ccbfa6529b07a9b7b075135a799b003923ed6 (diff)
downloadgs-common-df08a31b762c00220673003b1f46b4b4746637e1.tar.gz
powerstats: timeout mechanism for AoC data provider
Reading data from an AoC sysfs node by getline takes 1 second. In total there are 17 AoC sysfs nodes that must be read. The worst case is taking 17 seconds long that is greater than dumpsys timeout. Therefore, we need the timeout mechanism to ignore the AoC power stats reporting when AoC latency exceeds the allowed time. Bug: 219630658 Test: dumpsys android.hardware.power.stats.IPowerStats/default Change-Id: I71a9e681780471f31141599c53bb516aef445add Signed-off-by: Darren Hsu <darrenhsu@google.com>
-rw-r--r--powerstats/AocStateResidencyDataProvider.cpp98
-rw-r--r--powerstats/include/AocStateResidencyDataProvider.h7
2 files changed, 96 insertions, 9 deletions
diff --git a/powerstats/AocStateResidencyDataProvider.cpp b/powerstats/AocStateResidencyDataProvider.cpp
index c64496d..574a23d 100644
--- a/powerstats/AocStateResidencyDataProvider.cpp
+++ b/powerstats/AocStateResidencyDataProvider.cpp
@@ -17,6 +17,8 @@
#include "AocStateResidencyDataProvider.h"
#include <android-base/logging.h>
+#include <chrono>
+#include <pthread.h>
namespace aidl {
namespace android {
@@ -24,12 +26,23 @@ namespace hardware {
namespace power {
namespace stats {
+struct async_data_t {
+ pthread_cond_t *cond;
+ pthread_mutex_t *lock;
+ uint64_t timeoutMillis;
+ std::unordered_map<std::string, std::vector<StateResidency>> *residencies;
+ std::unordered_map<std::string,
+ std::vector<std::unique_ptr<GenericStateResidencyDataProvider>>> *providers;
+};
+
AocStateResidencyDataProvider::AocStateResidencyDataProvider(std::vector<std::pair<std::string,
- std::string>> ids, std::vector<std::pair<std::string, std::string>> states) {
+ std::string>> ids, std::vector<std::pair<std::string, std::string>> states,
+ const uint64_t timeoutMillis) {
// AoC stats are reported in ticks of 244.140625ns. The transform
// function converts ticks to milliseconds.
// 1000000 / 244.140625 = 4096.
static const uint64_t AOC_CLK = 4096;
+ static const uint64_t TIMEOUT_MILLIS = 120;
std::function<uint64_t(uint64_t)> aocTickToMs = [](uint64_t a) { return a / AOC_CLK; };
GenericStateResidencyDataProvider::StateResidencyConfig config = {
.entryCountSupported = true,
@@ -54,13 +67,17 @@ AocStateResidencyDataProvider::AocStateResidencyDataProvider(std::vector<std::pa
mProviders[id.first].push_back(std::move(sdp));
}
}
+ mStateCount = states.size();
+ mTimeoutMillis = timeoutMillis == 0 ? TIMEOUT_MILLIS : timeoutMillis;
}
-bool AocStateResidencyDataProvider::getStateResidencies(
- std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
+void *getStateResidenciesAsync(void *arg) {
+ struct timespec start, end;
+ struct async_data_t *async = (struct async_data_t*)arg;
+ uint64_t timeoutUs = async->timeoutMillis * 1000;
+
// States from the same power entity are merged.
- bool ret = true;
- for (const auto &providerList : mProviders) {
+ for (const auto &providerList : *async->providers) {
int32_t stateId = 0;
std::string curEntity = providerList.first;
std::vector<StateResidency> stateResidencies;
@@ -68,7 +85,18 @@ bool AocStateResidencyDataProvider::getStateResidencies(
// Iterate over each provider in the providerList, appending each of the states
for (const auto &provider : providerList.second) {
std::unordered_map<std::string, std::vector<StateResidency>> residency;
- ret &= provider->getStateResidencies(&residency);
+
+ clock_gettime(CLOCK_REALTIME, &start);
+ provider->getStateResidencies(&residency);
+ clock_gettime(CLOCK_REALTIME, &end);
+ uint64_t elapsedUs =
+ ((end.tv_sec - start.tv_sec) * 1000000) + ((end.tv_nsec - start.tv_nsec) / 1000);
+
+ if (elapsedUs >= timeoutUs) {
+ LOG(WARNING) << "getStateResidencies latency for " << curEntity
+ << " exceeds time allowed: " << elapsedUs << " us";
+ return 0;
+ }
// Each provider should only return data for curEntity but checking anyway
if (residency.find(curEntity) != residency.end()) {
@@ -84,8 +112,64 @@ bool AocStateResidencyDataProvider::getStateResidencies(
}
}
- residencies->emplace(curEntity, stateResidencies);
+ async->residencies->emplace(curEntity, stateResidencies);
}
+
+ pthread_mutex_lock(async->lock);
+ pthread_cond_signal(async->cond);
+ pthread_mutex_unlock(async->lock);
+
+ return 0;
+}
+
+bool AocStateResidencyDataProvider::getStateResidencies(
+ std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
+ bool ret = true;
+ int condResult = 0;
+ pthread_t tid;
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ std::unordered_map<std::string, std::vector<StateResidency>> stateResidencies;
+ struct timespec start, timeout;
+ struct async_data_t async = {
+ .cond = &cond,
+ .lock = &lock,
+ .timeoutMillis = mTimeoutMillis,
+ .residencies = &stateResidencies,
+ .providers = &mProviders
+ };
+
+ pthread_create(&tid, NULL, &getStateResidenciesAsync, (void*)&async);
+
+ clock_gettime(CLOCK_REALTIME, &start);
+
+ uint64_t expirationMillis = mTimeoutMillis * mStateCount;
+ timeout.tv_sec = start.tv_sec + expirationMillis / 1000;
+ uint64_t nsec = start.tv_nsec + (expirationMillis % 1000) * 1000000;
+ if (nsec < 1000000000) {
+ timeout.tv_nsec = nsec;
+ } else {
+ timeout.tv_sec += 1;
+ timeout.tv_nsec = nsec - 1000000000;
+ }
+
+ pthread_mutex_lock(&lock);
+ condResult = pthread_cond_timedwait(&cond, &lock, &timeout);
+ pthread_mutex_unlock(&lock);
+
+ if (condResult != 0) {
+ if (condResult == ETIMEDOUT) {
+ LOG(WARNING) << __func__ << " latency for AoC timeout: " << expirationMillis << " ms";
+ } else {
+ LOG(ERROR) << "Failed to wait for the condition variable: " << condResult;
+ }
+ ret = false;
+ } else {
+ for (const auto &residency : stateResidencies) {
+ residencies->emplace(residency.first, residency.second);
+ }
+ }
+
return ret;
}
diff --git a/powerstats/include/AocStateResidencyDataProvider.h b/powerstats/include/AocStateResidencyDataProvider.h
index 5008912..150f335 100644
--- a/powerstats/include/AocStateResidencyDataProvider.h
+++ b/powerstats/include/AocStateResidencyDataProvider.h
@@ -27,7 +27,8 @@ namespace stats {
class AocStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider {
public:
AocStateResidencyDataProvider(std::vector<std::pair<std::string, std::string>> ids,
- std::vector<std::pair<std::string, std::string>> states);
+ std::vector<std::pair<std::string, std::string>> states,
+ const uint64_t timeoutMillis);
~AocStateResidencyDataProvider() = default;
bool getStateResidencies(
std::unordered_map<std::string, std::vector<StateResidency>> *residencies) override;
@@ -36,10 +37,12 @@ class AocStateResidencyDataProvider : public PowerStats::IStateResidencyDataProv
private:
std::unordered_map<std::string /* entity name */,
std::vector<std::unique_ptr<GenericStateResidencyDataProvider>> /* providers */> mProviders;
+ int32_t mStateCount;
+ uint64_t mTimeoutMillis;
};
} // namespace stats
} // namespace power
} // namespace hardware
} // namespace android
-} // namespace aidl \ No newline at end of file
+} // namespace aidl