summaryrefslogtreecommitdiff
path: root/cmds/statsd/src/external/puller_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/statsd/src/external/puller_util.cpp')
-rw-r--r--cmds/statsd/src/external/puller_util.cpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
new file mode 100644
index 000000000000..0b0c5c41bf9d
--- /dev/null
+++ b/cmds/statsd/src/external/puller_util.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018 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 "StatsPullerManagerImpl.h"
+#include "puller_util.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+using std::shared_ptr;
+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:
+ * NetworkBytesAtom {
+ * int uid = 1;
+ * State process_state = 2;
+ * int byte_send = 3;
+ * int byte_recv = 4;
+ * }
+ * additive fields are {3, 4}, non-additive field is {2}
+ * 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]
+ * [uid1, bg, 100, 200]
+ *
+ * We want to merge them and results should be:
+ * [uid1, fg, 200, 400]
+ * [uid1, bg, 100, 200]
+ */
+void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
+ int tagId) {
+ if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
+ StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
+ VLOG("Unknown pull atom id %d", tagId);
+ return;
+ }
+ if (android::util::kAtomsWithUidField.find(tagId) == android::util::kAtomsWithUidField.end()) {
+ VLOG("No uid to merge for atom %d", tagId);
+ return;
+ }
+ const vector<int>& additiveFields =
+ StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.additiveFields;
+ const vector<int>& nonAdditiveFields =
+ StatsPullerManagerImpl::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 err = 0;
+ int uid = data[i]->GetInt(1, &err);
+ if (err != 0) {
+ VLOG("Bad uid field for %s", data[i]->ToString().c_str());
+ 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);
+ } else {
+ if (tryMerge(data, i, hostPosition[hostUid], nonAdditiveFields, additiveFields)) {
+ toRemove[i] = true;
+ } else {
+ hostPosition[hostUid].push_back(i);
+ }
+ }
+ }
+
+ vector<shared_ptr<LogEvent>> mergedData;
+ for (size_t i = 0; i < toRemove.size(); i++) {
+ if (!toRemove[i]) {
+ mergedData.push_back(data[i]);
+ }
+ }
+ data.clear();
+ data = mergedData;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android