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