pullers now cache data to throttle frequent pull requests.

all pullers have a default 1s cool down before next pull.
We can adjust these later.
Also add puller stats in StatsdStats

Test: unit test
Change-Id: I71894a24c41e059d841591312dbb852f54387b7d
This commit is contained in:
Chenjie Yu
2017-12-18 15:15:34 -08:00
parent 6041a4a240
commit b038b70956
18 changed files with 386 additions and 169 deletions

View File

@@ -34,6 +34,7 @@ statsd_common_src := \
src/config/ConfigKey.cpp \
src/config/ConfigListener.cpp \
src/config/ConfigManager.cpp \
src/external/StatsPuller.cpp \
src/external/StatsCompanionServicePuller.cpp \
src/external/ResourcePowerManagerPuller.cpp \
src/external/CpuTimePerUidPuller.cpp \

View File

@@ -20,6 +20,9 @@
#include <fstream>
#include "external/CpuTimePerUidFreqPuller.h"
#include "../guardrail/StatsdStats.h"
#include "CpuTimePerUidFreqPuller.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
@@ -45,43 +48,47 @@ static const int kLineBufferSize = 1024;
* This provides the times a UID's processes spent executing at each different cpu frequency.
* The file contains a monotonically increasing count of time for a single boot.
*/
bool CpuTimePerUidFreqPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
data->clear();
CpuTimePerUidFreqPuller::CpuTimePerUidFreqPuller()
: StatsPuller(android::util::CPU_TIME_PER_UID_FREQ) {
}
ifstream fin;
fin.open(sProcFile);
if (!fin.good()) {
VLOG("Failed to read pseudo file %s", sProcFile.c_str());
return false;
}
bool CpuTimePerUidFreqPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
data->clear();
uint64_t timestamp = time(nullptr) * NS_PER_SEC;
char buf[kLineBufferSize];
// first line prints the format and frequencies
fin.getline(buf, kLineBufferSize);
char * pch;
while(!fin.eof()){
ifstream fin;
fin.open(sProcFile);
if (!fin.good()) {
VLOG("Failed to read pseudo file %s", sProcFile.c_str());
return false;
}
uint64_t timestamp = time(nullptr) * NS_PER_SEC;
char buf[kLineBufferSize];
// first line prints the format and frequencies
fin.getline(buf, kLineBufferSize);
pch = strtok (buf, " :");
if (pch == NULL) break;
uint64_t uid = std::stoull(pch);
pch = strtok(NULL, " ");
uint64_t timeMs;
int idx = 0;
do {
timeMs = std::stoull(pch);
auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ, timestamp);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
ptr->init();
data->push_back(ptr);
VLOG("uid %lld, freq idx %d, sys time %lld", (long long)uid, idx, (long long)timeMs);
idx ++;
pch = strtok(NULL, " ");
} while (pch != NULL);
}
return true;
char* pch;
while (!fin.eof()) {
fin.getline(buf, kLineBufferSize);
pch = strtok(buf, " :");
if (pch == NULL) break;
uint64_t uid = std::stoull(pch);
pch = strtok(NULL, " ");
uint64_t timeMs;
int idx = 0;
do {
timeMs = std::stoull(pch);
auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ, timestamp);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
ptr->init();
data->push_back(ptr);
VLOG("uid %lld, freq idx %d, sys time %lld", (long long)uid, idx, (long long)timeMs);
idx++;
pch = strtok(NULL, " ");
} while (pch != NULL);
}
return true;
}
} // namespace statsd

View File

@@ -33,7 +33,8 @@ namespace statsd {
*/
class CpuTimePerUidFreqPuller : public StatsPuller {
public:
bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
CpuTimePerUidFreqPuller();
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
} // namespace statsd

View File

@@ -20,6 +20,8 @@
#include <fstream>
#include "external/CpuTimePerUidPuller.h"
#include "CpuTimePerUidPuller.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
@@ -42,38 +44,42 @@ static const int kLineBufferSize = 1024;
* This provides the time a UID's processes spent executing in user-space and kernel-space.
* The file contains a monotonically increasing count of time for a single boot.
*/
bool CpuTimePerUidPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
data->clear();
CpuTimePerUidPuller::CpuTimePerUidPuller() : StatsPuller(android::util::CPU_TIME_PER_UID) {
}
ifstream fin;
fin.open(sProcFile);
if (!fin.good()) {
VLOG("Failed to read pseudo file %s", sProcFile.c_str());
return false;
}
bool CpuTimePerUidPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
data->clear();
uint64_t timestamp = time(nullptr) * NS_PER_SEC;
char buf[kLineBufferSize];
char * pch;
while(!fin.eof()){
fin.getline(buf, kLineBufferSize);
pch = strtok(buf, " :");
if (pch == NULL) break;
uint64_t uid = std::stoull(pch);
pch = strtok(buf, " ");
uint64_t userTimeMs = std::stoull(pch);
pch = strtok(buf, " ");
uint64_t sysTimeMs = std::stoull(pch);
ifstream fin;
fin.open(sProcFile);
if (!fin.good()) {
VLOG("Failed to read pseudo file %s", sProcFile.c_str());
return false;
}
auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID, timestamp);
ptr->write(uid);
ptr->write(userTimeMs);
ptr->write(sysTimeMs);
ptr->init();
data->push_back(ptr);
VLOG("uid %lld, user time %lld, sys time %lld", (long long)uid, (long long)userTimeMs, (long long)sysTimeMs);
}
return true;
uint64_t timestamp = time(nullptr) * NS_PER_SEC;
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
fin.getline(buf, kLineBufferSize);
pch = strtok(buf, " :");
if (pch == NULL) break;
uint64_t uid = std::stoull(pch);
pch = strtok(buf, " ");
uint64_t userTimeMs = std::stoull(pch);
pch = strtok(buf, " ");
uint64_t sysTimeMs = std::stoull(pch);
auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID, timestamp);
ptr->write(uid);
ptr->write(userTimeMs);
ptr->write(sysTimeMs);
ptr->init();
data->push_back(ptr);
VLOG("uid %lld, user time %lld, sys time %lld", (long long)uid, (long long)userTimeMs,
(long long)sysTimeMs);
}
return true;
}
} // namespace statsd

View File

@@ -33,7 +33,8 @@ namespace statsd {
*/
class CpuTimePerUidPuller : public StatsPuller {
public:
bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
CpuTimePerUidPuller();
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
} // namespace statsd

View File

@@ -33,6 +33,7 @@
#include "external/ResourcePowerManagerPuller.h"
#include "external/StatsPuller.h"
#include "ResourcePowerManagerPuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
@@ -72,7 +73,10 @@ bool getPowerHal() {
return gPowerHalV1_0 != nullptr;
}
bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
ResourcePowerManagerPuller::ResourcePowerManagerPuller(int tagId) : StatsPuller(tagId) {
}
bool ResourcePowerManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
if (!getPowerHal()) {
@@ -83,79 +87,87 @@ bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEven
uint64_t timestamp = time(nullptr) * NS_PER_SEC;
data->clear();
Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
[&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
if (status != Status::SUCCESS) return;
for (size_t i = 0; i < states.size(); i++) {
const PowerStatePlatformSleepState& state = states[i];
auto statePtr = make_shared<LogEvent>(
android::util::PLATFORM_SLEEP_STATE, timestamp);
statePtr->write(state.name);
statePtr->write(state.residencyInMsecSinceBoot);
statePtr->write(state.totalTransitions);
statePtr->write(state.supportedOnlyInSuspend);
statePtr->init();
data->push_back(statePtr);
VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
(long long)state.residencyInMsecSinceBoot,
(long long)state.totalTransitions, state.supportedOnlyInSuspend ? 1 : 0);
for (auto voter : state.voters) {
auto voterPtr =
make_shared<LogEvent>(android::util::SLEEP_STATE_VOTER, timestamp);
voterPtr->write(state.name);
voterPtr->write(voter.name);
voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
voterPtr->init();
data->push_back(voterPtr);
VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
voter.name.c_str(), (long long)voter.totalTimeInMsecVotedForSinceBoot,
(long long)voter.totalNumberOfTimesVotedSinceBoot);
}
}
});
if (!ret.isOk()) {
ALOGE("getLowPowerStats() failed: power HAL service not available");
gPowerHalV1_0 = nullptr;
return false;
}
// Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 != nullptr) {
ret = gPowerHal_1_1->getSubsystemLowPowerStats(
[&data, timestamp](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
Return<void> ret;
if (mTagId == android::util::PLATFORM_SLEEP_STATE ||
mTagId == android::util::SLEEP_STATE_VOTER) {
ret = gPowerHalV1_0->getPlatformLowPowerStats(
[&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
if (status != Status::SUCCESS) return;
if (subsystems.size() > 0) {
for (size_t i = 0; i < subsystems.size(); i++) {
const PowerStateSubsystem& subsystem = subsystems[i];
for (size_t j = 0; j < subsystem.states.size(); j++) {
const PowerStateSubsystemSleepState& state = subsystem.states[j];
auto subsystemStatePtr = make_shared<LogEvent>(
android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
subsystemStatePtr->write(subsystem.name);
subsystemStatePtr->write(state.name);
subsystemStatePtr->write(state.residencyInMsecSinceBoot);
subsystemStatePtr->write(state.totalTransitions);
subsystemStatePtr->write(state.lastEntryTimestampMs);
subsystemStatePtr->write(state.supportedOnlyInSuspend);
subsystemStatePtr->init();
data->push_back(subsystemStatePtr);
VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
subsystem.name.c_str(), state.name.c_str(),
(long long)state.residencyInMsecSinceBoot,
(long long)state.totalTransitions,
(long long)state.lastEntryTimestampMs);
}
for (size_t i = 0; i < states.size(); i++) {
const PowerStatePlatformSleepState& state = states[i];
auto statePtr = make_shared<LogEvent>(android::util::PLATFORM_SLEEP_STATE,
timestamp);
statePtr->write(state.name);
statePtr->write(state.residencyInMsecSinceBoot);
statePtr->write(state.totalTransitions);
statePtr->write(state.supportedOnlyInSuspend);
statePtr->init();
data->push_back(statePtr);
VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
(long long)state.residencyInMsecSinceBoot,
(long long)state.totalTransitions,
state.supportedOnlyInSuspend ? 1 : 0);
for (auto voter : state.voters) {
auto voterPtr = make_shared<LogEvent>(android::util::SLEEP_STATE_VOTER,
timestamp);
voterPtr->write(state.name);
voterPtr->write(voter.name);
voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
voterPtr->init();
data->push_back(voterPtr);
VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
voter.name.c_str(),
(long long)voter.totalTimeInMsecVotedForSinceBoot,
(long long)voter.totalNumberOfTimesVotedSinceBoot);
}
}
});
if (!ret.isOk()) {
ALOGE("getLowPowerStats() failed: power HAL service not available");
gPowerHalV1_0 = nullptr;
return false;
}
}
if (mTagId == android::util::SUBSYSTEM_SLEEP_STATE) {
// Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 != nullptr) {
ret = gPowerHal_1_1->getSubsystemLowPowerStats(
[&data, timestamp](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
if (status != Status::SUCCESS) return;
if (subsystems.size() > 0) {
for (size_t i = 0; i < subsystems.size(); i++) {
const PowerStateSubsystem& subsystem = subsystems[i];
for (size_t j = 0; j < subsystem.states.size(); j++) {
const PowerStateSubsystemSleepState& state =
subsystem.states[j];
auto subsystemStatePtr = make_shared<LogEvent>(
android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
subsystemStatePtr->write(subsystem.name);
subsystemStatePtr->write(state.name);
subsystemStatePtr->write(state.residencyInMsecSinceBoot);
subsystemStatePtr->write(state.totalTransitions);
subsystemStatePtr->write(state.lastEntryTimestampMs);
subsystemStatePtr->write(state.supportedOnlyInSuspend);
subsystemStatePtr->init();
data->push_back(subsystemStatePtr);
VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
subsystem.name.c_str(), state.name.c_str(),
(long long)state.residencyInMsecSinceBoot,
(long long)state.totalTransitions,
(long long)state.lastEntryTimestampMs);
}
}
}
});
}
}
return true;
}

View File

@@ -28,7 +28,8 @@ namespace statsd {
*/
class ResourcePowerManagerPuller : public StatsPuller {
public:
bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
ResourcePowerManagerPuller(int tagId);
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
} // namespace statsd

View File

@@ -22,6 +22,7 @@
#include <private/android_filesystem_config.h>
#include "StatsCompanionServicePuller.h"
#include "StatsService.h"
#include "guardrail/StatsdStats.h"
using namespace android;
using namespace android::base;
@@ -39,13 +40,16 @@ const int kLogMsgHeaderSize = 28;
// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
// let StatsCompanionService handle that and send the data back.
bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEvent> >* data) {
StatsCompanionServicePuller::StatsCompanionServicePuller(int tagId) : StatsPuller(tagId) {
}
bool StatsCompanionServicePuller::PullInternal(vector<shared_ptr<LogEvent> >* data) {
sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
vector<StatsLogEventWrapper> returned_value;
if (statsCompanion != NULL) {
Status status = statsCompanion->pullData(tagId, &returned_value);
Status status = statsCompanion->pullData(mTagId, &returned_value);
if (!status.isOk()) {
ALOGW("error pulling for %d", tagId);
ALOGW("error pulling for %d", mTagId);
return false;
}
data->clear();
@@ -60,7 +64,7 @@ bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEve
std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
data->push_back(make_shared<LogEvent>(tmp));
}
ALOGD("StatsCompanionServicePuller::pull succeeded for %d", tagId);
ALOGD("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
return true;
} else {
ALOGW("statsCompanion not found!");

View File

@@ -25,7 +25,8 @@ namespace statsd {
class StatsCompanionServicePuller : public StatsPuller {
public:
bool Pull(const int tagId, vector<std::shared_ptr<LogEvent> >* data) override;
StatsCompanionServicePuller(int tagId);
bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
};
} // namespace statsd

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define DEBUG false // STOPSHIP if true
#include "Log.h"
#include "StatsPuller.h"
#include "guardrail/StatsdStats.h"
namespace android {
namespace os {
namespace statsd {
using std::lock_guard;
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
StatsPuller::StatsPuller(const int tagId)
: mTagId(tagId) {
if (StatsdStats::kPullerCooldownMap.find(tagId) == StatsdStats::kPullerCooldownMap.end()) {
mCoolDownSec = StatsdStats::kDefaultPullerCooldown;
} else {
mCoolDownSec = StatsdStats::kPullerCooldownMap[tagId];
}
VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec);
}
bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
lock_guard<std::mutex> lock(mLock);
StatsdStats::getInstance().notePull(mTagId);
long curTime = time(nullptr);
if (curTime - mLastPullTimeSec < mCoolDownSec) {
(*data) = mCachedData;
StatsdStats::getInstance().notePullFromCache(mTagId);
return true;
}
if (mMinPullIntervalSec > curTime - mLastPullTimeSec) {
mMinPullIntervalSec = curTime - mLastPullTimeSec;
StatsdStats::getInstance().updateMinPullIntervalSec(mTagId, mMinPullIntervalSec);
}
mCachedData.clear();
mLastPullTimeSec = curTime;
bool ret = PullInternal(&mCachedData);
if (ret) {
(*data) = mCachedData;
}
return ret;
}
} // namespace statsd
} // namespace os
} // namespace android

View File

@@ -18,11 +18,13 @@
#include <android/os/StatsLogEventWrapper.h>
#include <utils/String16.h>
#include <mutex>
#include <vector>
#include "logd/LogEvent.h"
#include "guardrail/StatsdStats.h"
using android::os::StatsLogEventWrapper;
using std::vector;
namespace android {
namespace os {
@@ -30,9 +32,33 @@ namespace statsd {
class StatsPuller {
public:
virtual ~StatsPuller(){};
StatsPuller(const int tagId);
virtual bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) = 0;
virtual ~StatsPuller() {}
bool Pull(std::vector<std::shared_ptr<LogEvent>>* data);
protected:
// The atom tag id this puller pulls
const int mTagId;
private:
mutable std::mutex mLock;
// Minimum time before this puller does actual pull again.
// If a pull request comes before cooldown, a cached version from purevious pull
// will be returned.
// The actual value should be determined by individual pullers.
long mCoolDownSec;
// For puller stats
long mMinPullIntervalSec = LONG_MAX;
virtual bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) = 0;
// Cache of data from last pull. If next request comes before cool down finishes,
// cached data will be returned.
std::vector<std::shared_ptr<LogEvent>> mCachedData;
long mLastPullTimeSec;
};
} // namespace statsd

View File

@@ -45,29 +45,29 @@ namespace statsd {
StatsPullerManagerImpl::StatsPullerManagerImpl()
: mCurrentPullingInterval(LONG_MAX) {
shared_ptr<StatsPuller> statsCompanionServicePuller = make_shared<StatsCompanionServicePuller>();
shared_ptr<StatsPuller> resourcePowerManagerPuller = make_shared<ResourcePowerManagerPuller>();
shared_ptr<StatsPuller> cpuTimePerUidPuller = make_shared<CpuTimePerUidPuller>();
shared_ptr<StatsPuller> cpuTimePerUidFreqPuller = make_shared<CpuTimePerUidFreqPuller>();
mPullers.insert({android::util::KERNEL_WAKELOCK,
statsCompanionServicePuller});
make_shared<StatsCompanionServicePuller>(android::util::KERNEL_WAKELOCK)});
mPullers.insert({android::util::WIFI_BYTES_TRANSFER,
statsCompanionServicePuller});
mPullers.insert({android::util::MOBILE_BYTES_TRANSFER,
statsCompanionServicePuller});
make_shared<StatsCompanionServicePuller>(android::util::WIFI_BYTES_TRANSFER)});
mPullers.insert(
{android::util::MOBILE_BYTES_TRANSFER,
make_shared<StatsCompanionServicePuller>(android::util::MOBILE_BYTES_TRANSFER)});
mPullers.insert({android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
statsCompanionServicePuller});
make_shared<StatsCompanionServicePuller>(
android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)});
mPullers.insert({android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
statsCompanionServicePuller});
make_shared<StatsCompanionServicePuller>(
android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)});
mPullers.insert({android::util::PLATFORM_SLEEP_STATE,
resourcePowerManagerPuller});
make_shared<ResourcePowerManagerPuller>(android::util::PLATFORM_SLEEP_STATE)});
mPullers.insert({android::util::SLEEP_STATE_VOTER,
resourcePowerManagerPuller});
mPullers.insert({android::util::SUBSYSTEM_SLEEP_STATE,
resourcePowerManagerPuller});
mPullers.insert({android::util::CPU_TIME_PER_UID, cpuTimePerUidPuller});
mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, cpuTimePerUidFreqPuller});
make_shared<ResourcePowerManagerPuller>(android::util::SLEEP_STATE_VOTER)});
mPullers.insert(
{android::util::SUBSYSTEM_SLEEP_STATE,
make_shared<ResourcePowerManagerPuller>(android::util::SUBSYSTEM_SLEEP_STATE)});
mPullers.insert({android::util::CPU_TIME_PER_FREQ, make_shared<StatsCompanionServicePuller>(android::util::CPU_TIME_PER_FREQ)});
mPullers.insert({android::util::CPU_TIME_PER_UID, make_shared<CpuTimePerUidPuller>()});
mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, make_shared<CpuTimePerUidFreqPuller>()});
mStatsCompanionService = StatsService::getStatsCompanionService();
}
@@ -76,7 +76,7 @@ bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data)
if (DEBUG) ALOGD("Initiating pulling %d", tagId);
if (mPullers.find(tagId) != mPullers.end()) {
bool ret = mPullers.find(tagId)->second->Pull(tagId, data);
bool ret = mPullers.find(tagId)->second->Pull(data);
ALOGD("pulled %d items", (int)data->size());
return ret;
} else {

View File

@@ -19,6 +19,7 @@
#include "StatsdStats.h"
#include <android/util/ProtoOutputStream.h>
#include "../stats_log_util.h"
#include "statslog.h"
namespace android {
@@ -59,6 +60,20 @@ const int FIELD_ID_ATOM_STATS_COUNT = 2;
const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
std::map<int, long> StatsdStats::kPullerCooldownMap = {
{android::util::KERNEL_WAKELOCK, 1},
{android::util::WIFI_BYTES_TRANSFER, 1},
{android::util::MOBILE_BYTES_TRANSFER, 1},
{android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1},
{android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1},
{android::util::PLATFORM_SLEEP_STATE, 1},
{android::util::SLEEP_STATE_VOTER, 1},
{android::util::SUBSYSTEM_SLEEP_STATE, 1},
{android::util::CPU_TIME_PER_FREQ, 1},
{android::util::CPU_TIME_PER_UID, 1},
{android::util::CPU_TIME_PER_UID_FREQ, 1},
};
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
@@ -231,6 +246,21 @@ void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
mAnomalyAlarmRegisteredStats++;
}
void StatsdStats::updateMinPullIntervalSec(int pullAtomId, long intervalSec) {
lock_guard<std::mutex> lock(mLock);
mPulledAtomStats[pullAtomId].minPullIntervalSec = intervalSec;
}
void StatsdStats::notePull(int pullAtomId) {
lock_guard<std::mutex> lock(mLock);
mPulledAtomStats[pullAtomId].totalPull++;
}
void StatsdStats::notePullFromCache(int pullAtomId) {
lock_guard<std::mutex> lock(mLock);
mPulledAtomStats[pullAtomId].totalPullFromCache++;
}
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
@@ -401,7 +431,7 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
configStats.clear_alert_stats();
}
VLOG("********Atom stats***********");
VLOG("********Pushed Atom stats***********");
const size_t atomCounts = mPushedAtomStats.size();
for (size_t i = 2; i < atomCounts; i++) {
if (mPushedAtomStats[i] > 0) {
@@ -415,6 +445,12 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
}
}
VLOG("********Pulled Atom stats***********");
for (const auto& pair : mPulledAtomStats) {
android::os::statsd::writePullerStatsToStream(pair, &proto);
VLOG("Atom %d->%ld, %ld, %ld\n", (int) pair.first, (long) pair.second.totalPull, (long) pair.second.totalPullFromCache, (long) pair.second.minPullIntervalSec);
}
if (mAnomalyAlarmRegisteredStats > 0) {
VLOG("********AnomalyAlarmStats stats***********");
long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS);

View File

@@ -17,6 +17,7 @@
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "statslog.h"
#include <gtest/gtest_prod.h>
#include <log/log_time.h>
@@ -62,6 +63,13 @@ public:
/* Min period between two checks of byte size per config key in nanoseconds. */
static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
// Default minimum interval between pulls for an atom. Pullers can return cached values if
// another pull request happens within this interval.
static std::map<int, long> kPullerCooldownMap;
// Default cooldown time for a puller
static const long kDefaultPullerCooldown = 1;
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -154,6 +162,15 @@ public:
void setUidMapChanges(int changes);
void setCurrentUidMapMemory(int bytes);
// Update minimum interval between pulls for an pulled atom
void updateMinPullIntervalSec(int pullAtomId, long intervalSec);
// Notify pull request for an atom
void notePull(int pullAtomId);
// Notify pull request for an atom served from cached data
void notePullFromCache(int pullAtomId);
/**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
@@ -168,6 +185,12 @@ public:
*/
void dumpStats(std::vector<uint8_t>* buffer, bool reset);
typedef struct {
long totalPull;
long totalPullFromCache;
long minPullIntervalSec;
} PulledAtomStats;
private:
StatsdStats();
@@ -200,6 +223,8 @@ private:
// This is a vector, not a map because it will be accessed A LOT -- for each stats log.
std::vector<int> mPushedAtomStats;
std::map<int, PulledAtomStats> mPulledAtomStats;
// Stores the number of times statsd modified the anomaly alarm registered with
// StatsCompanionService.
int mAnomalyAlarmRegisteredStats = 0;

View File

@@ -326,6 +326,7 @@ void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
}
}
mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
mCurrentSlicedBucket = std::make_shared<DimToGaugeFieldsMap>();
// Adjusts the bucket start time

View File

@@ -246,4 +246,12 @@ message StatsdStatsReport {
optional int32 alarms_registered = 1;
}
optional AnomalyAlarmStats anomaly_alarm_stats = 9;
message PulledAtomStats {
optional int32 atom_id = 1;
optional int64 total_pull = 2;
optional int64 total_pull_from_cache = 3;
optional int64 min_pull_interval_sec = 4;
}
repeated PulledAtomStats pulled_atom_stats = 10;
}

View File

@@ -45,6 +45,13 @@ const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
// for MessageValue Proto
const int FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO = 1;
// for PulledAtomStats proto
const int FIELD_ID_PULLED_ATOM_STATS = 10;
const int FIELD_ID_PULL_ATOM_ID = 1;
const int FIELD_ID_TOTAL_PULL = 2;
const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
void writeDimensionsValueProtoToStream(const DimensionsValue& dimensionsValue,
ProtoOutputStream* protoOutput) {
protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, dimensionsValue.field());
@@ -248,6 +255,19 @@ int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
}
}
void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
util::ProtoOutputStream* protoOutput) {
long long token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
FIELD_COUNT_REPEATED);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
(long long)pair.second.totalPullFromCache);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
(long long)pair.second.minPullIntervalSec);
protoOutput->end(token);
}
} // namespace statsd
} // namespace os
} // namespace android

View File

@@ -17,29 +17,32 @@
#pragma once
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "field_util.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "guardrail/StatsdStats.h"
namespace android {
namespace os {
namespace statsd {
// Helper function to write DimensionsValue proto to ProtoOutputStream.
void writeDimensionsValueProtoToStream(
const DimensionsValue& fieldValue, util::ProtoOutputStream* protoOutput);
void writeDimensionsValueProtoToStream(const DimensionsValue& fieldValue,
util::ProtoOutputStream* protoOutput);
// Helper function to write Field proto to ProtoOutputStream.
void writeFieldProtoToStream(
const Field& field, util::ProtoOutputStream* protoOutput);
void writeFieldProtoToStream(const Field& field, util::ProtoOutputStream* protoOutput);
// Helper function to construct the field value tree and write to ProtoOutputStream
void writeFieldValueTreeToStream(const FieldValueMap &fieldValueMap,
util::ProtoOutputStream* protoOutput);
void writeFieldValueTreeToStream(const FieldValueMap& fieldValueMap,
util::ProtoOutputStream* protoOutput);
// Convert the TimeUnit enum to the bucket size in millis.
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit);
// Helper function to write PulledAtomStats to ProtoOutputStream
void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
util::ProtoOutputStream* protoOutput);
} // namespace statsd
} // namespace os
} // namespace android