Revert "Revert "support work chain in pulled atoms""

This reverts commit 9c7b131996.

Reason for revert: Fixed build failures due to merge

Change-Id: I7d7bfed3a3234b966f3fe3fd6e0cbc63d2bedf83
Test: unit test
This commit is contained in:
Chenjie Yu
2018-11-28 21:29:44 +00:00
parent 01ce898135
commit d7e3a228be
15 changed files with 426 additions and 192 deletions

View File

@@ -59,7 +59,7 @@ bool StatsCompanionServicePuller::PullInternal(vector<shared_ptr<LogEvent> >* da
}
data->clear();
for (const StatsLogEventWrapper& it : returned_value) {
data->push_back(make_shared<LogEvent>(it));
LogEvent::createLogEvents(it, *data);
}
VLOG("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
return true;

View File

@@ -32,9 +32,10 @@ using std::lock_guard;
sp<UidMap> StatsPuller::mUidMap = nullptr;
void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
StatsPuller::StatsPuller(const int tagId)
: mTagId(tagId) {
// Pullers can cause significant impact to system health and battery.
// So that we don't pull too frequently.
mCoolDownNs = StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.coolDownNs;
VLOG("Puller for tag %d created. Cooldown set to %lld", mTagId, (long long)mCoolDownNs);
}
@@ -64,8 +65,8 @@ bool StatsPuller::Pull(const int64_t elapsedTimeNs, std::vector<std::shared_ptr<
data->setLogdWallClockTimestampNs(wallClockTimeNs);
}
if (ret && mCachedData.size() > 0) {
mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
(*data) = mCachedData;
mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
(*data) = mCachedData;
}
StatsdStats::getInstance().notePullDelay(mTagId, getElapsedRealtimeNs() - elapsedTimeNs);
return ret;

View File

@@ -54,52 +54,42 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// wifi_bytes_transfer
{android::util::WIFI_BYTES_TRANSFER,
{{2, 3, 4, 5},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
// wifi_bytes_transfer_by_fg_bg
{android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
{{3, 4, 5, 6},
{2},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
// mobile_bytes_transfer
{android::util::MOBILE_BYTES_TRANSFER,
{{2, 3, 4, 5},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
// mobile_bytes_transfer_by_fg_bg
{android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
{{3, 4, 5, 6},
{2},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
// bluetooth_bytes_transfer
{android::util::BLUETOOTH_BYTES_TRANSFER,
{{2, 3},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
// kernel_wakelock
{android::util::KERNEL_WAKELOCK,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
// subsystem_sleep_state
{android::util::SUBSYSTEM_SLEEP_STATE,
{{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}},
{{}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}},
// on_device_power_measurement
{android::util::ON_DEVICE_POWER_MEASUREMENT,
{{}, {}, 1 * NS_PER_SEC, new PowerStatsPuller()}},
{android::util::ON_DEVICE_POWER_MEASUREMENT, {{}, 1 * NS_PER_SEC, new PowerStatsPuller()}},
// cpu_time_per_freq
{android::util::CPU_TIME_PER_FREQ,
{{3},
{2},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
{{3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
// cpu_time_per_uid
{android::util::CPU_TIME_PER_UID,
{{2, 3},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
// cpu_time_per_uid_freq
@@ -107,169 +97,140 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
{android::util::CPU_TIME_PER_UID_FREQ,
{{4},
{2, 3},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
// cpu_active_time
// the throttling is 3sec, handled in
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
{android::util::CPU_ACTIVE_TIME,
{{2},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
{{2}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
// cpu_cluster_time
// the throttling is 3sec, handled in
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
{android::util::CPU_CLUSTER_TIME,
{{3},
{2},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
{{3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
// wifi_activity_energy_info
{android::util::WIFI_ACTIVITY_INFO,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}},
// modem_activity_info
{android::util::MODEM_ACTIVITY_INFO,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
// bluetooth_activity_info
{android::util::BLUETOOTH_ACTIVITY_INFO,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
// system_elapsed_realtime
{android::util::SYSTEM_ELAPSED_REALTIME,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
// system_uptime
{android::util::SYSTEM_UPTIME,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
// remaining_battery_capacity
{android::util::REMAINING_BATTERY_CAPACITY,
{{},
{},
1 * NS_PER_SEC,
new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
// full_battery_capacity
{android::util::FULL_BATTERY_CAPACITY,
{{},
{},
1 * NS_PER_SEC,
new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
// battery_voltage
{android::util::BATTERY_VOLTAGE,
{{}, {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
// battery_voltage
{{}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
// battery_level
{android::util::BATTERY_LEVEL,
{{}, {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}},
{{}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
{{4, 5, 6, 7, 8, 9},
{2, 3, 10},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
// native_process_memory_state
{android::util::NATIVE_PROCESS_MEMORY_STATE,
{{3, 4, 5, 6},
{2, 7},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
{android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
{{3},
{2},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
// temperature
{android::util::TEMPERATURE, {{}, {}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}},
{android::util::TEMPERATURE, {{}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}},
// binder_calls
{android::util::BINDER_CALLS,
{{4, 5, 6, 8, 12},
{2, 3, 7, 9, 10, 11, 13},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::BINDER_CALLS)}},
// binder_calls_exceptions
{android::util::BINDER_CALLS_EXCEPTIONS,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}},
// looper_stats
{android::util::LOOPER_STATS,
{{5, 6, 7, 8, 9},
{2, 3, 4, 10},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
// Disk Stats
{android::util::DISK_STATS,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_STATS)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_STATS)}},
// Directory usage
{android::util::DIRECTORY_USAGE,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
// Size of app's code, data, and cache
{android::util::APP_SIZE,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}},
// Size of specific categories of files. Eg. Music.
{android::util::CATEGORY_SIZE,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
// Number of fingerprints registered to each user.
{android::util::NUM_FINGERPRINTS,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
// ProcStats.
{android::util::PROC_STATS,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}},
// ProcStatsPkgProc.
{android::util::PROC_STATS_PKG_PROC,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}},
// Disk I/O stats per uid.
{android::util::DISK_IO,
{{2,3,4,5,6,7,8,9,10,11},
{},
{{2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
3 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::DISK_IO)}},
// PowerProfile constants for power model calculations.
{android::util::POWER_PROFILE,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
// Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses.
{android::util::PROCESS_CPU_TIME,
{{} /* additive fields */, {} /* non additive fields */,
5 * NS_PER_SEC /* min cool-down in seconds*/,
new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
{{} /* additive fields */,
5 * NS_PER_SEC /* min cool-down in seconds*/,
new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
{android::util::CPU_TIME_PER_THREAD_FREQ,
{{7},
{2, 3, 4, 5, 6},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
// DeviceCalculatedPowerUse.
{android::util::DEVICE_CALCULATED_POWER_USE,
{{}, {}, 1 * NS_PER_SEC,
{{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
// DeviceCalculatedPowerBlameUid.
{android::util::DEVICE_CALCULATED_POWER_BLAME_UID,
{{}, {}, // BatteryStats already merged isolated with host ids so it's unnecessary here.
{{}, // BatteryStats already merged isolated with host ids so it's unnecessary here.
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
// DeviceCalculatedPowerBlameOther.
{android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER,
{{}, {},
{{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
// BuildInformation.
{android::util::BUILD_INFORMATION,
{{}, {},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}},
{{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {

View File

@@ -36,9 +36,6 @@ typedef struct {
// The field numbers of the fields that need to be summed when merging
// isolated uid with host uid.
std::vector<int> additiveFields;
// The field numbers of the fields that can't be merged when merging
// data belong to isolated uid and host uid.
std::vector<int> nonAdditiveFields;
// How long should the puller wait before doing an actual pull again. Default
// 1 sec. Set this to 0 if this is handled elsewhere.
int64_t coolDownNs = 1 * NS_PER_SEC;

View File

@@ -25,67 +25,13 @@ namespace android {
namespace os {
namespace statsd {
using std::list;
using std::map;
using std::set;
using std::shared_ptr;
using std::sort;
using std::vector;
namespace {
bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
const vector<int>& nonAdditiveFields) {
const auto& l_values = lhs->getValues();
const auto& r_values = rhs->getValues();
for (size_t i : nonAdditiveFields) {
// We store everything starting from index 0, so we need to use i-1
if (!(l_values.size() > i - 1 && r_values.size() > i - 1 &&
l_values[i - 1].mValue == r_values[i - 1].mValue)) {
return false;
}
}
return true;
}
// merge rhs to lhs
// when calling this function, all sanity check should be done already.
// e.g., index boundary, nonAdditiveFields matching etc.
bool mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
const vector<int>& additiveFields) {
vector<FieldValue>* host_values = lhs->getMutableValues();
const auto& child_values = rhs->getValues();
for (int i : additiveFields) {
Value& host = (*host_values)[i - 1].mValue;
const Value& child = (child_values[i - 1]).mValue;
if (child.getType() != host.getType()) {
return false;
}
switch (child.getType()) {
case INT:
host.setInt(host.int_value + child.int_value);
break;
case LONG:
host.setLong(host.long_value + child.long_value);
break;
default:
ALOGE("Tried to merge 2 fields with unsupported type");
return false;
}
}
return true;
}
bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<int>& host_pos,
const vector<int>& nonAdditiveFields, const vector<int>& additiveFields) {
for (const auto& pos : host_pos) {
if (shouldMerge(data[pos], data[child_pos], nonAdditiveFields) &&
mergeEvent(data[pos], data[child_pos], additiveFields)) {
return true;
}
}
return false;
}
} // namespace
/**
* Process all data and merge isolated with host if necessary.
* For example:
@@ -95,7 +41,7 @@ bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<in
* int byte_send = 3;
* int byte_recv = 4;
* }
* additive fields are {3, 4}, non-additive field is {2}
* additive fields are {3, 4}
* If we pulled the following events (uid1_child is an isolated uid which maps to uid1):
* [uid1, fg, 100, 200]
* [uid1_child, fg, 100, 200]
@@ -104,65 +50,119 @@ bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<in
* We want to merge them and results should be:
* [uid1, fg, 200, 400]
* [uid1, bg, 100, 200]
*
* All atoms should be of the same tagId. All fields should be present.
*/
void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
int tagId) {
void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
int tagId) {
if (StatsPullerManager::kAllPullAtomInfo.find(tagId) ==
StatsPullerManager::kAllPullAtomInfo.end()) {
VLOG("Unknown pull atom id %d", tagId);
return;
}
int uidField;
auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId);
if (it == android::util::AtomsInfo::kAtomsWithUidField.end()) {
VLOG("No uid to merge for atom %d", tagId);
if ((android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) ==
android::util::AtomsInfo::kAtomsWithAttributionChain.end()) &&
(android::util::AtomsInfo::kAtomsWithUidField.find(tagId) ==
android::util::AtomsInfo::kAtomsWithUidField.end())) {
VLOG("No uid or attribution chain to merge, atom %d", tagId);
return;
} else {
uidField = it->second; // uidField is the field number in proto,
}
const vector<int>& additiveFields =
StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.additiveFields;
const vector<int>& nonAdditiveFields =
StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.nonAdditiveFields;
// map of host uid to their position in the original vector
map<int, vector<int>> hostPosition;
vector<bool> toRemove = vector<bool>(data.size(), false);
for (size_t i = 0; i < data.size(); i++) {
vector<FieldValue>* valueList = data[i]->getMutableValues();
int uid;
if (uidField > 0 && (int)data[i]->getValues().size() >= uidField &&
(data[i]->getValues())[uidField - 1].mValue.getType() == INT) {
uid = (*data[i]->getMutableValues())[uidField - 1].mValue.int_value;
} else {
ALOGE("Malformed log, uid not found. %s", data[i]->ToString().c_str());
continue;
// 1. Map all isolated uid in-place to host uid
for (shared_ptr<LogEvent>& event : data) {
if (event->GetTagId() != tagId) {
ALOGE("Wrong atom. Expecting %d, got %d", tagId, event->GetTagId());
return;
}
const int hostUid = uidMap->getHostUidOrSelf(uid);
if (hostUid != uid) {
(*valueList)[0].mValue.setInt(hostUid);
}
if (hostPosition.find(hostUid) == hostPosition.end()) {
hostPosition[hostUid].push_back(i);
if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) !=
android::util::AtomsInfo::kAtomsWithAttributionChain.end()) {
for (auto& value : *(event->getMutableValues())) {
if (value.mField.getPosAtDepth(0) > kAttributionField) {
break;
}
if (isAttributionUidField(value)) {
const int hostUid = uidMap->getHostUidOrSelf(value.mValue.int_value);
value.mValue.setInt(hostUid);
}
}
} else {
if (tryMerge(data, i, hostPosition[hostUid], nonAdditiveFields, additiveFields)) {
toRemove[i] = true;
} else {
hostPosition[hostUid].push_back(i);
auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId);
if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
int uidField = it->second; // uidField is the field number in proto,
// starting from 1
if (uidField > 0 && (int)event->getValues().size() >= uidField &&
(event->getValues())[uidField - 1].mValue.getType() == INT) {
Value& value = (*event->getMutableValues())[uidField - 1].mValue;
const int hostUid = uidMap->getHostUidOrSelf(value.int_value);
value.setInt(hostUid);
} else {
ALOGE("Malformed log, uid not found. %s", event->ToString().c_str());
return;
}
}
}
}
// 2. sort the data, bit-wise
sort(data.begin(), data.end(),
[](const shared_ptr<LogEvent>& lhs, const shared_ptr<LogEvent>& rhs) {
if (lhs->size() != rhs->size()) {
return lhs->size() < rhs->size();
}
const std::vector<FieldValue>& lhsValues = lhs->getValues();
const std::vector<FieldValue>& rhsValues = rhs->getValues();
for (int i = 0; i < (int)lhs->size(); i++) {
if (lhsValues[i] != rhsValues[i]) {
return lhsValues[i] < rhsValues[i];
}
}
return false;
});
vector<shared_ptr<LogEvent>> mergedData;
for (size_t i = 0; i < toRemove.size(); i++) {
if (!toRemove[i]) {
const vector<int>& additiveFieldsVec =
StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.additiveFields;
const set<int> additiveFields(additiveFieldsVec.begin(), additiveFieldsVec.end());
bool needMerge = true;
// 3. do the merge.
// The loop invariant is this: for every event, check if it differs on
// non-additive fields, or have different attribution chain length.
// If so, no need to merge, add itself to the result.
// Otherwise, merge the value onto the one immediately next to it.
for (int i = 0; i < (int)data.size() - 1; i++) {
// Size different, must be different chains.
if (data[i]->size() != data[i + 1]->size()) {
mergedData.push_back(data[i]);
continue;
}
vector<FieldValue>* lhsValues = data[i]->getMutableValues();
vector<FieldValue>* rhsValues = data[i + 1]->getMutableValues();
needMerge = true;
for (int p = 0; p < (int)lhsValues->size(); p++) {
if ((*lhsValues)[p] != (*rhsValues)[p]) {
int pos = (*lhsValues)[p].mField.getPosAtDepth(0);
// Differ on non-additive field, abort.
if (additiveFields.find(pos) == additiveFields.end()) {
needMerge = false;
break;
}
}
}
if (!needMerge) {
mergedData.push_back(data[i]);
continue;
}
// This should be infrequent operation.
for (int p = 0; p < (int)lhsValues->size(); p++) {
int pos = (*lhsValues)[p].mField.getPosAtDepth(0);
if (additiveFields.find(pos) != additiveFields.end()) {
(*rhsValues)[p].mValue += (*lhsValues)[p].mValue;
}
}
}
mergedData.push_back(data.back());
data.clear();
data = mergedData;
}

View File

@@ -25,8 +25,8 @@ namespace android {
namespace os {
namespace statsd {
void mergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data,
const sp<UidMap>& uidMap, int tagId);
void mapAndMergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data,
const sp<UidMap>& uidMap, int tagId);
} // namespace statsd
} // namespace os

View File

@@ -41,13 +41,28 @@ LogEvent::LogEvent(log_msg& msg) {
}
}
LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper) {
LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex) {
mTagId = statsLogEventWrapper.getTagId();
mLogdTimestampNs = statsLogEventWrapper.getWallClockTimeNs();
mElapsedTimestampNs = statsLogEventWrapper.getElapsedRealTimeNs();
mLogUid = 0;
int workChainPosOffset = 0;
if (workChainIndex != -1) {
const WorkChain& wc = statsLogEventWrapper.getWorkChains()[workChainIndex];
// chains are at field 1, level 2
int depth = 2;
for (int i = 0; i < (int)wc.uids.size(); i++) {
int pos[] = {1, i + 1, 1};
mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(wc.uids[i])));
pos[2]++;
mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(wc.tags[i])));
mValues.back().mField.decorateLastPos(2);
}
mValues.back().mField.decorateLastPos(1);
workChainPosOffset = 1;
}
for (int i = 0; i < (int)statsLogEventWrapper.getElements().size(); i++) {
Field field(statsLogEventWrapper.getTagId(), getSimpleField(i + 1));
Field field(statsLogEventWrapper.getTagId(), getSimpleField(i + 1 + workChainPosOffset));
switch (statsLogEventWrapper.getElements()[i].type) {
case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::INT:
mValues.push_back(
@@ -79,6 +94,17 @@ LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper) {
}
}
void LogEvent::createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper,
std::vector<std::shared_ptr<LogEvent>>& logEvents) {
if (statsLogEventWrapper.getWorkChains().size() == 0) {
logEvents.push_back(std::make_shared<LogEvent>(statsLogEventWrapper, -1));
} else {
for (size_t i = 0; i < statsLogEventWrapper.getWorkChains().size(); i++) {
logEvents.push_back(std::make_shared<LogEvent>(statsLogEventWrapper, i));
}
}
}
LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
mLogdTimestampNs = wallClockTimestampNs;
mTagId = tagId;

View File

@@ -65,7 +65,16 @@ public:
*/
explicit LogEvent(log_msg& msg);
explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper);
/**
* Creates LogEvent from StatsLogEventWrapper.
*/
static void createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper,
std::vector<std::shared_ptr<LogEvent>>& logEvents);
/**
* Construct one LogEvent from a StatsLogEventWrapper with the i-th work chain. -1 if no chain.
*/
explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex);
/**
* Constructs a LogEvent with synthetic data for testing. Must call init() before reading.

View File

@@ -165,7 +165,7 @@ private:
const bool mSkipZeroDiffOutput;
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);

View File

@@ -454,6 +454,16 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
if (!metric.has_value_field()) {
ALOGW("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
std::vector<Matcher> fieldMatchers;
translateFieldMatcher(metric.value_field(), &fieldMatchers);
if (fieldMatchers.size() < 1) {
ALOGW("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
metricMap.insert({metric.id(), metricIndex});

View File

@@ -394,6 +394,167 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {
EXPECT_EQ(1.1f, item16.mValue.float_value);
}
TEST(LogEventTest, TestStatsLogEventWrapperNoChain) {
Parcel parcel;
// tag id
parcel.writeInt32(1);
// elapsed realtime
parcel.writeInt64(1111L);
// wallclock time
parcel.writeInt64(2222L);
// no chain
parcel.writeInt32(0);
// 2 data
parcel.writeInt32(2);
// int 6
parcel.writeInt32(1);
parcel.writeInt32(6);
// long 10
parcel.writeInt32(2);
parcel.writeInt64(10);
parcel.setDataPosition(0);
StatsLogEventWrapper statsLogEventWrapper;
EXPECT_EQ(NO_ERROR, statsLogEventWrapper.readFromParcel(&parcel));
EXPECT_EQ(1, statsLogEventWrapper.getTagId());
EXPECT_EQ(1111L, statsLogEventWrapper.getElapsedRealTimeNs());
EXPECT_EQ(2222L, statsLogEventWrapper.getWallClockTimeNs());
EXPECT_EQ(0, statsLogEventWrapper.getWorkChains().size());
EXPECT_EQ(2, statsLogEventWrapper.getElements().size());
EXPECT_EQ(6, statsLogEventWrapper.getElements()[0].int_value);
EXPECT_EQ(10L, statsLogEventWrapper.getElements()[1].long_value);
LogEvent event(statsLogEventWrapper, -1);
EXPECT_EQ(1, event.GetTagId());
EXPECT_EQ(1111L, event.GetElapsedTimestampNs());
EXPECT_EQ(2222L, event.GetLogdTimestampNs());
EXPECT_EQ(2, event.size());
EXPECT_EQ(6, event.getValues()[0].mValue.int_value);
EXPECT_EQ(10, event.getValues()[1].mValue.long_value);
}
TEST(LogEventTest, TestStatsLogEventWrapperWithChain) {
Parcel parcel;
// tag id
parcel.writeInt32(1);
// elapsed realtime
parcel.writeInt64(1111L);
// wallclock time
parcel.writeInt64(2222L);
// 3 chains
parcel.writeInt32(3);
// chain1, 2 nodes (1, "tag1") (2, "tag2")
parcel.writeInt32(2);
parcel.writeInt32(1);
parcel.writeString16(String16("tag1"));
parcel.writeInt32(2);
parcel.writeString16(String16("tag2"));
// chain2, 1 node (3, "tag3")
parcel.writeInt32(1);
parcel.writeInt32(3);
parcel.writeString16(String16("tag3"));
// chain3, 2 nodes (4, "") (5, "")
parcel.writeInt32(2);
parcel.writeInt32(4);
parcel.writeString16(String16(""));
parcel.writeInt32(5);
parcel.writeString16(String16(""));
// 2 data
parcel.writeInt32(2);
// int 6
parcel.writeInt32(1);
parcel.writeInt32(6);
// long 10
parcel.writeInt32(2);
parcel.writeInt64(10);
parcel.setDataPosition(0);
StatsLogEventWrapper statsLogEventWrapper;
EXPECT_EQ(NO_ERROR, statsLogEventWrapper.readFromParcel(&parcel));
EXPECT_EQ(1, statsLogEventWrapper.getTagId());
EXPECT_EQ(1111L, statsLogEventWrapper.getElapsedRealTimeNs());
EXPECT_EQ(2222L, statsLogEventWrapper.getWallClockTimeNs());
EXPECT_EQ(3, statsLogEventWrapper.getWorkChains().size());
EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].uids.size());
EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[0].uids[0]);
EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].uids[1]);
EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].tags.size());
EXPECT_EQ("tag1", statsLogEventWrapper.getWorkChains()[0].tags[0]);
EXPECT_EQ("tag2", statsLogEventWrapper.getWorkChains()[0].tags[1]);
EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[1].uids.size());
EXPECT_EQ(3, statsLogEventWrapper.getWorkChains()[1].uids[0]);
EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[1].tags.size());
EXPECT_EQ("tag3", statsLogEventWrapper.getWorkChains()[1].tags[0]);
EXPECT_EQ(2, statsLogEventWrapper.getElements().size());
EXPECT_EQ(6, statsLogEventWrapper.getElements()[0].int_value);
EXPECT_EQ(10L, statsLogEventWrapper.getElements()[1].long_value);
EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[2].uids.size());
EXPECT_EQ(4, statsLogEventWrapper.getWorkChains()[2].uids[0]);
EXPECT_EQ(5, statsLogEventWrapper.getWorkChains()[2].uids[1]);
EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[2].tags.size());
EXPECT_EQ("", statsLogEventWrapper.getWorkChains()[2].tags[0]);
EXPECT_EQ("", statsLogEventWrapper.getWorkChains()[2].tags[1]);
LogEvent event(statsLogEventWrapper, -1);
EXPECT_EQ(1, event.GetTagId());
EXPECT_EQ(1111L, event.GetElapsedTimestampNs());
EXPECT_EQ(2222L, event.GetLogdTimestampNs());
EXPECT_EQ(2, event.size());
EXPECT_EQ(6, event.getValues()[0].mValue.int_value);
EXPECT_EQ(10, event.getValues()[1].mValue.long_value);
LogEvent event1(statsLogEventWrapper, 0);
EXPECT_EQ(1, event1.GetTagId());
EXPECT_EQ(1111L, event1.GetElapsedTimestampNs());
EXPECT_EQ(2222L, event1.GetLogdTimestampNs());
EXPECT_EQ(6, event1.size());
EXPECT_EQ(1, event1.getValues()[0].mValue.int_value);
EXPECT_EQ(0x2010101, event1.getValues()[0].mField.getField());
EXPECT_EQ("tag1", event1.getValues()[1].mValue.str_value);
EXPECT_EQ(0x2010182, event1.getValues()[1].mField.getField());
EXPECT_EQ(2, event1.getValues()[2].mValue.int_value);
EXPECT_EQ(0x2010201, event1.getValues()[2].mField.getField());
EXPECT_EQ("tag2", event1.getValues()[3].mValue.str_value);
EXPECT_EQ(0x2018282, event1.getValues()[3].mField.getField());
EXPECT_EQ(6, event1.getValues()[4].mValue.int_value);
EXPECT_EQ(0x20000, event1.getValues()[4].mField.getField());
EXPECT_EQ(10, event1.getValues()[5].mValue.long_value);
EXPECT_EQ(0x30000, event1.getValues()[5].mField.getField());
LogEvent event2(statsLogEventWrapper, 1);
EXPECT_EQ(1, event2.GetTagId());
EXPECT_EQ(1111L, event2.GetElapsedTimestampNs());
EXPECT_EQ(2222L, event2.GetLogdTimestampNs());
EXPECT_EQ(4, event2.size());
EXPECT_EQ(3, event2.getValues()[0].mValue.int_value);
EXPECT_EQ(0x2010101, event2.getValues()[0].mField.getField());
EXPECT_EQ("tag3", event2.getValues()[1].mValue.str_value);
EXPECT_EQ(0x2018182, event2.getValues()[1].mField.getField());
EXPECT_EQ(6, event2.getValues()[2].mValue.int_value);
EXPECT_EQ(0x20000, event2.getValues()[2].mField.getField());
EXPECT_EQ(10, event2.getValues()[3].mValue.long_value);
EXPECT_EQ(0x30000, event2.getValues()[3].mField.getField());
LogEvent event3(statsLogEventWrapper, 2);
EXPECT_EQ(1, event3.GetTagId());
EXPECT_EQ(1111L, event3.GetElapsedTimestampNs());
EXPECT_EQ(2222L, event3.GetLogdTimestampNs());
EXPECT_EQ(6, event3.size());
EXPECT_EQ(4, event3.getValues()[0].mValue.int_value);
EXPECT_EQ(0x2010101, event3.getValues()[0].mField.getField());
EXPECT_EQ("", event3.getValues()[1].mValue.str_value);
EXPECT_EQ(0x2010182, event3.getValues()[1].mField.getField());
EXPECT_EQ(5, event3.getValues()[2].mValue.int_value);
EXPECT_EQ(0x2010201, event3.getValues()[2].mField.getField());
EXPECT_EQ("", event3.getValues()[3].mValue.str_value);
EXPECT_EQ(0x2018282, event3.getValues()[3].mField.getField());
EXPECT_EQ(6, event3.getValues()[4].mValue.int_value);
EXPECT_EQ(0x20000, event3.getValues()[4].mField.getField());
EXPECT_EQ(10, event3.getValues()[5].mValue.long_value);
EXPECT_EQ(0x30000, event3.getValues()[5].mField.getField());
}
TEST(LogEventTest, TestBinaryFieldAtom) {
Atom launcherAtom;

View File

@@ -80,7 +80,7 @@ TEST(puller_util, MergeNoDimension) {
.WillRepeatedly(Return(hostUid));
EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
.WillRepeatedly(ReturnArg<0>());
mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
vector<vector<int>> actual;
extractIntoVector(inputData, actual);
@@ -120,7 +120,7 @@ TEST(puller_util, MergeWithDimension) {
.WillRepeatedly(Return(hostUid));
EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
.WillRepeatedly(ReturnArg<0>());
mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
vector<vector<int>> actual;
extractIntoVector(inputData, actual);
@@ -154,7 +154,7 @@ TEST(puller_util, NoMergeHostUidOnly) {
.WillRepeatedly(Return(hostUid));
EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
.WillRepeatedly(ReturnArg<0>());
mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
// 20->32->31
// 20->22->21
@@ -190,7 +190,7 @@ TEST(puller_util, IsolatedUidOnly) {
.WillRepeatedly(Return(hostUid));
EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
.WillRepeatedly(ReturnArg<0>());
mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
// 20->32->31
// 20->22->21
@@ -231,7 +231,7 @@ TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
vector<vector<int>> actual;
extractIntoVector(inputData, actual);
@@ -256,7 +256,7 @@ TEST(puller_util, NoNeedToMerge) {
inputData.push_back(event);
sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
mergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId);
mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId);
EXPECT_EQ(2, (int)inputData.size());
}

View File

@@ -43,6 +43,7 @@ public final class StatsLogEventWrapper implements Parcelable {
int mTag;
long mElapsedTimeNs;
long mWallClockTimeNs;
WorkSource mWorkSource = null;
public StatsLogEventWrapper(int tag, long elapsedTimeNs, long wallClockTimeNs) {
this.mTag = tag;
@@ -70,6 +71,17 @@ public final class StatsLogEventWrapper implements Parcelable {
}
};
/**
* Set work source if any.
*/
public void setWorkSource(WorkSource ws) {
if (ws.getWorkChains() == null || ws.getWorkChains().size() == 0) {
Slog.w(TAG, "Empty worksource!");
return;
}
mWorkSource = ws;
}
/**
* Write a int value.
*/
@@ -119,11 +131,6 @@ public final class StatsLogEventWrapper implements Parcelable {
mValues.add(val ? 1 : 0);
}
/**
* Writes the stored fields to a byte array. Will first write a new-line character to denote
* END_LIST before writing contents to byte array.
*/
public void writeToParcel(Parcel out, int flags) {
if (DEBUG) {
Slog.d(TAG,
@@ -133,6 +140,34 @@ public final class StatsLogEventWrapper implements Parcelable {
out.writeInt(mTag);
out.writeLong(mElapsedTimeNs);
out.writeLong(mWallClockTimeNs);
if (mWorkSource != null) {
ArrayList<android.os.WorkSource.WorkChain> workChains = mWorkSource.getWorkChains();
// number of chains
out.writeInt(workChains.size());
for (int i = 0; i < workChains.size(); i++) {
android.os.WorkSource.WorkChain wc = workChains.get(i);
if (wc.getSize() == 0) {
Slog.w(TAG, "Empty work chain.");
out.writeInt(0);
continue;
}
if (wc.getUids().length != wc.getTags().length
|| wc.getUids().length != wc.getSize()) {
Slog.w(TAG, "Malformated work chain.");
out.writeInt(0);
continue;
}
// number of nodes
out.writeInt(wc.getSize());
for (int j = 0; j < wc.getSize(); j++) {
out.writeInt(wc.getUids()[j]);
out.writeString(wc.getTags()[j] == null ? "" : wc.getTags()[j]);
}
}
} else {
// no chains
out.writeInt(0);
}
out.writeInt(mTypes.size());
for (int i = 0; i < mTypes.size(); i++) {
out.writeInt(mTypes.get(i));

View File

@@ -82,6 +82,11 @@ struct StatsLogValue {
STATS_LOG_VALUE_TYPE type;
};
struct WorkChain {
std::vector<int32_t> uids;
std::vector<std::string> tags;
};
// Represents a parcelable object. Only used to send data from Android OS to statsd.
class StatsLogEventWrapper : public android::Parcelable {
public:
@@ -99,7 +104,9 @@ class StatsLogEventWrapper : public android::Parcelable {
int64_t getWallClockTimeNs() const { return mWallClockTimeNs; }
std::vector<StatsLogValue> getElements() const { return mElements; }
const std::vector<StatsLogValue>& getElements() const { return mElements; }
const std::vector<WorkChain>& getWorkChains() const { return mWorkChains; }
private:
int mTagId;
@@ -109,6 +116,8 @@ class StatsLogEventWrapper : public android::Parcelable {
int64_t mWallClockTimeNs;
std::vector<StatsLogValue> mElements;
std::vector<WorkChain> mWorkChains;
};
} // Namespace os
} // Namespace android

View File

@@ -58,6 +58,31 @@ status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) {
ALOGE("statsd could not read wall clock time from parcel");
return res;
}
int numWorkChain = 0;
if ((res = in->readInt32(&numWorkChain)) != OK) {
ALOGE("statsd could not read number of work chains from parcel");
return res;
}
if (numWorkChain > 0) {
for (int i = 0; i < numWorkChain; i++) {
int numNodes = 0;
if ((res = in->readInt32(&numNodes)) != OK) {
ALOGE(
"statsd could not read number of nodes in work chain from parcel");
return res;
}
if (numNodes == 0) {
ALOGE("empty work chain");
return BAD_VALUE;
}
WorkChain wc;
for (int j = 0; j < numNodes; j++) {
wc.uids.push_back(in->readInt32());
wc.tags.push_back(std::string(String8(in->readString16()).string()));
}
mWorkChains.push_back(wc);
}
}
int dataSize = 0;
if ((res = in->readInt32(&dataSize)) != OK) {
ALOGE("statsd could not read data size from parcel");