xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/global_args_tracker.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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     ArgSetHash digest = hash.digest();
149     auto it_and_inserted =
150         arg_row_for_hash_.Insert(digest, arg_table.row_count());
151     if (!it_and_inserted.second) {
152       // Already inserted.
153       return arg_table[*it_and_inserted.first].arg_set_id();
154     }
155 
156     // Taking size() after the Insert() ensures that nothing has an id == 0
157     // (0 == kInvalidArgSetId).
158     auto id = static_cast<uint32_t>(arg_row_for_hash_.size());
159     for (const CompactArg* ptr : valid) {
160       const auto& arg = *ptr;
161       tables::ArgTable::Row row;
162       row.arg_set_id = id;
163       row.flat_key = arg.flat_key;
164       row.key = arg.key;
165       switch (arg.value.type) {
166         case Variadic::Type::kInt:
167           row.int_value = arg.value.int_value;
168           break;
169         case Variadic::Type::kUint:
170           row.int_value = static_cast<int64_t>(arg.value.uint_value);
171           break;
172         case Variadic::Type::kString:
173           row.string_value = arg.value.string_value;
174           break;
175         case Variadic::Type::kReal:
176           row.real_value = arg.value.real_value;
177           break;
178         case Variadic::Type::kPointer:
179           row.int_value = static_cast<int64_t>(arg.value.pointer_value);
180           break;
181         case Variadic::Type::kBool:
182           row.int_value = arg.value.bool_value;
183           break;
184         case Variadic::Type::kJson:
185           row.string_value = arg.value.json_value;
186           break;
187         case Variadic::Type::kNull:
188           break;
189       }
190       row.value_type = storage_->GetIdForVariadicType(arg.value.type);
191       arg_table.Insert(row);
192     }
193     return id;
194   }
195 
196   base::FlatHashMap<ArgSetHash, uint32_t, base::AlreadyHashed<ArgSetHash>>
197       arg_row_for_hash_;
198 
199   TraceStorage* storage_;
200 };
201 
202 }  // namespace trace_processor
203 }  // namespace perfetto
204 
205 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_GLOBAL_ARGS_TRACKER_H_
206