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>
This commit is contained in:
parent
f19ccbfa65
commit
df08a31b76
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
} // namespace aidl
|
||||
|
Loading…
x
Reference in New Issue
Block a user