1/ Support nested message and repeated fields in statsd.
2/ Filter gauge fields by FieldMatcher.
3/ Wire up wakelock attribution chain.
4/ e2e test: wakelock duration metric with aggregated predicate dimensions.
5/ e2e test: count metric with multiple metric condition links for 2 predicates and 1 non-sliced predicate.
Test: statsd unit test passed.
Change-Id: I89db31cb068184a54e0a892fad710966d3127bc9
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 0b6f8f2..6da1243 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -13,92 +13,104 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include "HashableDimensionKey.h"
+#include "dimension.h"
namespace android {
namespace os {
namespace statsd {
+android::hash_t hashDimensionsValue(const DimensionsValue& value) {
+ android::hash_t hash = 0;
+ hash = android::JenkinsHashMix(hash, android::hash_type(value.field()));
+
+ hash = android::JenkinsHashMix(hash, android::hash_type((int)value.value_case()));
+ switch (value.value_case()) {
+ case DimensionsValue::ValueCase::kValueStr:
+ hash = android::JenkinsHashMix(
+ hash,
+ static_cast<uint32_t>(std::hash<std::string>()(value.value_str())));
+ break;
+ case DimensionsValue::ValueCase::kValueInt:
+ hash = android::JenkinsHashMix(hash, android::hash_type(value.value_int()));
+ break;
+ case DimensionsValue::ValueCase::kValueLong:
+ hash = android::JenkinsHashMix(
+ hash, android::hash_type(static_cast<int64_t>(value.value_long())));
+ break;
+ case DimensionsValue::ValueCase::kValueBool:
+ hash = android::JenkinsHashMix(hash, android::hash_type(value.value_bool()));
+ break;
+ case DimensionsValue::ValueCase::kValueFloat: {
+ float floatVal = value.value_float();
+ hash = android::JenkinsHashMixBytes(hash, (uint8_t*)&floatVal, sizeof(float));
+ break;
+ }
+ case DimensionsValue::ValueCase::kValueTuple: {
+ hash = android::JenkinsHashMix(hash, android::hash_type(
+ value.value_tuple().dimensions_value_size()));
+ for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
+ hash = android::JenkinsHashMix(
+ hash,
+ hashDimensionsValue(value.value_tuple().dimensions_value(i)));
+ }
+ break;
+ }
+ case DimensionsValue::ValueCase::VALUE_NOT_SET:
+ break;
+ }
+ return JenkinsHashWhiten(hash);
+}
+
using std::string;
+
string HashableDimensionKey::toString() const {
string flattened;
- for (const auto& pair : mKeyValuePairs) {
- flattened += std::to_string(pair.key());
- flattened += ":";
- switch (pair.value_case()) {
- case KeyValuePair::ValueCase::kValueStr:
- flattened += pair.value_str();
- break;
- case KeyValuePair::ValueCase::kValueInt:
- flattened += std::to_string(pair.value_int());
- break;
- case KeyValuePair::ValueCase::kValueLong:
- flattened += std::to_string(pair.value_long());
- break;
- case KeyValuePair::ValueCase::kValueBool:
- flattened += std::to_string(pair.value_bool());
- break;
- case KeyValuePair::ValueCase::kValueFloat:
- flattened += std::to_string(pair.value_float());
- break;
- default:
- break;
- }
- flattened += "|";
- }
+ DimensionsValueToString(getDimensionsValue(), &flattened);
return flattened;
}
-bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
- const auto& keyValue2 = that.getKeyValuePairs();
- if (mKeyValuePairs.size() != keyValue2.size()) {
+bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2) {
+ if (s1.field() != s2.field()) {
return false;
}
-
- for (size_t i = 0; i < keyValue2.size(); i++) {
- const auto& kv1 = mKeyValuePairs[i];
- const auto& kv2 = keyValue2[i];
- if (kv1.key() != kv2.key()) {
- return false;
- }
-
- if (kv1.value_case() != kv2.value_case()) {
- return false;
- }
-
- switch (kv1.value_case()) {
- case KeyValuePair::ValueCase::kValueStr:
- if (kv1.value_str() != kv2.value_str()) {
- return false;
- }
- break;
- case KeyValuePair::ValueCase::kValueInt:
- if (kv1.value_int() != kv2.value_int()) {
- return false;
- }
- break;
- case KeyValuePair::ValueCase::kValueLong:
- if (kv1.value_long() != kv2.value_long()) {
- return false;
- }
- break;
- case KeyValuePair::ValueCase::kValueBool:
- if (kv1.value_bool() != kv2.value_bool()) {
- return false;
- }
- break;
- case KeyValuePair::ValueCase::kValueFloat: {
- if (kv1.value_float() != kv2.value_float()) {
- return false;
- }
- break;
- }
- case KeyValuePair::ValueCase::VALUE_NOT_SET:
- break;
- }
+ if (s1.value_case() != s1.value_case()) {
+ return false;
}
- return true;
+ switch (s1.value_case()) {
+ case DimensionsValue::ValueCase::kValueStr:
+ return (s1.value_str() == s2.value_str());
+ case DimensionsValue::ValueCase::kValueInt:
+ return s1.value_int() == s2.value_int();
+ case DimensionsValue::ValueCase::kValueLong:
+ return s1.value_long() == s2.value_long();
+ case DimensionsValue::ValueCase::kValueBool:
+ return s1.value_bool() == s2.value_bool();
+ case DimensionsValue::ValueCase::kValueFloat:
+ return s1.value_float() == s2.value_float();
+ case DimensionsValue::ValueCase::kValueTuple:
+ {
+ if (s1.value_tuple().dimensions_value_size() !=
+ s2.value_tuple().dimensions_value_size()) {
+ return false;
+ }
+ bool allMatched = true;
+ for (int i = 0; allMatched && i < s1.value_tuple().dimensions_value_size(); ++i) {
+ allMatched &= compareDimensionsValue(s1.value_tuple().dimensions_value(i),
+ s2.value_tuple().dimensions_value(i));
+ }
+ return allMatched;
+ }
+ case DimensionsValue::ValueCase::VALUE_NOT_SET:
+ default:
+ return true;
+ }
+}
+
+bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
+ return compareDimensionsValue(getDimensionsValue(), that.getDimensionsValue());
};
bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const {