1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #define DEBUG false // STOPSHIP if true 17 #include "Log.h" 18 19 #include <mutex> 20 21 #include "HashableDimensionKey.h" 22 #include "FieldValue.h" 23 24 namespace android { 25 namespace os { 26 namespace statsd { 27 28 using std::string; 29 using std::vector; 30 31 android::hash_t hashDimension(const HashableDimensionKey& value) { 32 android::hash_t hash = 0; 33 for (const auto& fieldValue : value.getValues()) { 34 hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getField())); 35 hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getTag())); 36 hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mValue.getType())); 37 switch (fieldValue.mValue.getType()) { 38 case INT: 39 hash = android::JenkinsHashMix(hash, 40 android::hash_type(fieldValue.mValue.int_value)); 41 break; 42 case LONG: 43 hash = android::JenkinsHashMix(hash, 44 android::hash_type(fieldValue.mValue.long_value)); 45 break; 46 case STRING: 47 hash = android::JenkinsHashMix(hash, static_cast<uint32_t>(std::hash<std::string>()( 48 fieldValue.mValue.str_value))); 49 break; 50 case FLOAT: { 51 hash = android::JenkinsHashMix(hash, 52 android::hash_type(fieldValue.mValue.float_value)); 53 break; 54 } 55 default: 56 break; 57 } 58 } 59 return JenkinsHashWhiten(hash); 60 } 61 62 bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values, 63 HashableDimensionKey* output) { 64 size_t num_matches = 0; 65 for (const auto& value : values) { 66 for (size_t i = 0; i < matcherFields.size(); ++i) { 67 const auto& matcher = matcherFields[i]; 68 if (value.mField.matches(matcher)) { 69 output->addValue(value); 70 output->mutableValue(num_matches)->mField.setTag(value.mField.getTag()); 71 output->mutableValue(num_matches)->mField.setField( 72 value.mField.getField() & matcher.mMask); 73 num_matches++; 74 } 75 } 76 } 77 return num_matches > 0; 78 } 79 80 void filterGaugeValues(const std::vector<Matcher>& matcherFields, 81 const std::vector<FieldValue>& values, std::vector<FieldValue>* output) { 82 for (const auto& field : matcherFields) { 83 for (const auto& value : values) { 84 if (value.mField.matches(field)) { 85 output->push_back(value); 86 } 87 } 88 } 89 } 90 91 void getDimensionForCondition(const std::vector<FieldValue>& eventValues, 92 const Metric2Condition& links, 93 HashableDimensionKey* conditionDimension) { 94 // Get the dimension first by using dimension from what. 95 filterValues(links.metricFields, eventValues, conditionDimension); 96 97 size_t count = conditionDimension->getValues().size(); 98 if (count != links.conditionFields.size()) { 99 // ALOGE("WTF condition link is bad"); 100 return; 101 } 102 103 for (size_t i = 0; i < count; i++) { 104 conditionDimension->mutableValue(i)->mField.setField( 105 links.conditionFields[i].mMatcher.getField()); 106 conditionDimension->mutableValue(i)->mField.setTag( 107 links.conditionFields[i].mMatcher.getTag()); 108 } 109 } 110 111 bool LessThan(const vector<FieldValue>& s1, const vector<FieldValue>& s2) { 112 if (s1.size() != s2.size()) { 113 return s1.size() < s2.size(); 114 } 115 116 size_t count = s1.size(); 117 for (size_t i = 0; i < count; i++) { 118 if (s1[i] != s2[i]) { 119 return s1[i] < s2[i]; 120 } 121 } 122 return false; 123 } 124 125 bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const { 126 if (mValues.size() != that.getValues().size()) { 127 return false; 128 } 129 size_t count = mValues.size(); 130 for (size_t i = 0; i < count; i++) { 131 if (mValues[i] != (that.getValues())[i]) { 132 return false; 133 } 134 } 135 return true; 136 }; 137 138 bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const { 139 return LessThan(getValues(), that.getValues()); 140 }; 141 142 bool HashableDimensionKey::contains(const HashableDimensionKey& that) const { 143 if (mValues.size() < that.getValues().size()) { 144 return false; 145 } 146 147 if (mValues.size() == that.getValues().size()) { 148 return (*this) == that; 149 } 150 151 for (const auto& value : that.getValues()) { 152 bool found = false; 153 for (const auto& myValue : mValues) { 154 if (value.mField == myValue.mField && value.mValue == myValue.mValue) { 155 found = true; 156 break; 157 } 158 } 159 if (!found) { 160 return false; 161 } 162 } 163 164 return true; 165 } 166 167 string HashableDimensionKey::toString() const { 168 std::string output; 169 for (const auto& value : mValues) { 170 output += StringPrintf("(%d)%#x->%s ", value.mField.getTag(), value.mField.getField(), 171 value.mValue.toString().c_str()); 172 } 173 return output; 174 } 175 176 bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const { 177 return mDimensionKeyInWhat == that.getDimensionKeyInWhat() && 178 mDimensionKeyInCondition == that.getDimensionKeyInCondition(); 179 }; 180 181 string MetricDimensionKey::toString() const { 182 return mDimensionKeyInWhat.toString() + mDimensionKeyInCondition.toString(); 183 } 184 185 bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const { 186 if (mDimensionKeyInWhat < that.getDimensionKeyInWhat()) { 187 return true; 188 } else if (that.getDimensionKeyInWhat() < mDimensionKeyInWhat) { 189 return false; 190 } 191 192 return mDimensionKeyInCondition < that.getDimensionKeyInCondition(); 193 } 194 195 } // namespace statsd 196 } // namespace os 197 } // namespace android 198