1 /* 2 * Copyright (C) 2019 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 17 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_GLOBAL_ARGS_TRACKER_H_ 18 #define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_GLOBAL_ARGS_TRACKER_H_ 19 20 #include "perfetto/ext/base/flat_hash_map.h" 21 #include "perfetto/ext/base/hash.h" 22 #include "perfetto/ext/base/small_vector.h" 23 #include "src/trace_processor/storage/trace_storage.h" 24 #include "src/trace_processor/types/variadic.h" 25 26 namespace perfetto { 27 namespace trace_processor { 28 29 // Interns args into the storage from all ArgsTrackers across trace processor. 30 // Note: most users will want to use ArgsTracker to push args to the strorage 31 // and not this class. This class is really intended for ArgsTracker to use for 32 // that purpose. 33 class GlobalArgsTracker { 34 public: 35 // How to behave if two or more args with the same key were added into the 36 // same ArgSet. If |kSkipIfExists|, the arg will be ignored if another arg 37 // with the same key already exists. If |kAddOrUpdate|, any existing arg with 38 // the same key will be overridden. 39 enum class UpdatePolicy { kSkipIfExists, kAddOrUpdate }; 40 41 struct CompactArg { 42 StringId flat_key = kNullStringId; 43 StringId key = kNullStringId; 44 Variadic value = Variadic::Integer(0); 45 UpdatePolicy update_policy = UpdatePolicy::kAddOrUpdate; 46 }; 47 static_assert(std::is_trivially_destructible<CompactArg>::value, 48 "Args must be trivially destructible"); 49 50 struct Arg : public CompactArg { 51 Column* column; 52 uint32_t row; 53 54 // Object slices this Arg to become a CompactArg. ToCompactArgArg55 CompactArg ToCompactArg() const { return CompactArg(*this); } 56 }; 57 static_assert(std::is_trivially_destructible<Arg>::value, 58 "Args must be trivially destructible"); 59 60 struct ArgHasher { operatorArgHasher61 uint64_t operator()(const Arg& arg) const noexcept { 62 base::Hasher hash; 63 hash.Update(arg.key.raw_id()); 64 // We don't hash arg.flat_key because it's a subsequence of arg.key. 65 switch (arg.value.type) { 66 case Variadic::Type::kInt: 67 hash.Update(arg.value.int_value); 68 break; 69 case Variadic::Type::kUint: 70 hash.Update(arg.value.uint_value); 71 break; 72 case Variadic::Type::kString: 73 hash.Update(arg.value.string_value.raw_id()); 74 break; 75 case Variadic::Type::kReal: 76 hash.Update(arg.value.real_value); 77 break; 78 case Variadic::Type::kPointer: 79 hash.Update(arg.value.pointer_value); 80 break; 81 case Variadic::Type::kBool: 82 hash.Update(arg.value.bool_value); 83 break; 84 case Variadic::Type::kJson: 85 hash.Update(arg.value.json_value.raw_id()); 86 break; 87 case Variadic::Type::kNull: 88 hash.Update(0); 89 break; 90 } 91 return hash.digest(); 92 } 93 }; 94 95 explicit GlobalArgsTracker(TraceStorage* storage); 96 97 // Assumes that the interval [begin, end) of |args| is sorted by keys. AddArgSet(const Arg * args,uint32_t begin,uint32_t end)98 ArgSetId AddArgSet(const Arg* args, uint32_t begin, uint32_t end) { 99 base::SmallVector<uint32_t, 64> valid_indexes; 100 101 // TODO(eseckler): Also detect "invalid" key combinations in args sets (e.g. 102 // "foo" and "foo.bar" in the same arg set)? 103 for (uint32_t i = begin; i < end; i++) { 104 if (!valid_indexes.empty() && 105 args[valid_indexes.back()].key == args[i].key) { 106 // Last arg had the same key as this one. In case of kSkipIfExists, skip 107 // this arg. In case of kAddOrUpdate, remove the last arg and add this 108 // arg instead. 109 if (args[i].update_policy == UpdatePolicy::kSkipIfExists) { 110 continue; 111 } else { 112 PERFETTO_DCHECK(args[i].update_policy == UpdatePolicy::kAddOrUpdate); 113 valid_indexes.pop_back(); 114 } 115 } 116 117 valid_indexes.emplace_back(i); 118 } 119 120 base::Hasher hash; 121 for (uint32_t i : valid_indexes) { 122 hash.Update(ArgHasher()(args[i])); 123 } 124 125 auto* arg_table = storage_->mutable_arg_table(); 126 127 ArgSetHash digest = hash.digest(); 128 auto it_and_inserted = 129 arg_row_for_hash_.Insert(digest, arg_table->row_count()); 130 if (!it_and_inserted.second) { 131 // Already inserted. 132 return arg_table->arg_set_id()[*it_and_inserted.first]; 133 } 134 135 // Taking size() after the Insert() ensures that nothing has an id == 0 136 // (0 == kInvalidArgSetId). 137 ArgSetId id = static_cast<uint32_t>(arg_row_for_hash_.size()); 138 for (uint32_t i : valid_indexes) { 139 const auto& arg = args[i]; 140 141 tables::ArgTable::Row row; 142 row.arg_set_id = id; 143 row.flat_key = arg.flat_key; 144 row.key = arg.key; 145 switch (arg.value.type) { 146 case Variadic::Type::kInt: 147 row.int_value = arg.value.int_value; 148 break; 149 case Variadic::Type::kUint: 150 row.int_value = static_cast<int64_t>(arg.value.uint_value); 151 break; 152 case Variadic::Type::kString: 153 row.string_value = arg.value.string_value; 154 break; 155 case Variadic::Type::kReal: 156 row.real_value = arg.value.real_value; 157 break; 158 case Variadic::Type::kPointer: 159 row.int_value = static_cast<int64_t>(arg.value.pointer_value); 160 break; 161 case Variadic::Type::kBool: 162 row.int_value = arg.value.bool_value; 163 break; 164 case Variadic::Type::kJson: 165 row.string_value = arg.value.json_value; 166 break; 167 case Variadic::Type::kNull: 168 break; 169 } 170 row.value_type = storage_->GetIdForVariadicType(arg.value.type); 171 arg_table->Insert(row); 172 } 173 return id; 174 } 175 176 // Exposed for making tests easier to write. AddArgSet(const std::vector<Arg> & args,uint32_t begin,uint32_t end)177 ArgSetId AddArgSet(const std::vector<Arg>& args, 178 uint32_t begin, 179 uint32_t end) { 180 return AddArgSet(args.data(), begin, end); 181 } 182 183 private: 184 using ArgSetHash = uint64_t; 185 186 base::FlatHashMap<ArgSetHash, uint32_t, base::AlreadyHashed<ArgSetHash>> 187 arg_row_for_hash_; 188 189 TraceStorage* storage_; 190 }; 191 192 } // namespace trace_processor 193 } // namespace perfetto 194 195 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_GLOBAL_ARGS_TRACKER_H_ 196