|  | /* | 
|  | * Copyright (C) 2022 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef SRC_TRACE_PROCESSOR_UTIL_PROTO_PROFILER_H_ | 
|  | #define SRC_TRACE_PROCESSOR_UTIL_PROTO_PROFILER_H_ | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <vector> | 
|  |  | 
|  | #include "perfetto/ext/base/hash.h" | 
|  | #include "perfetto/protozero/field.h" | 
|  | #include "src/trace_processor/util/descriptors.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace trace_processor { | 
|  | namespace util { | 
|  |  | 
|  | class SizeProfileComputer { | 
|  | public: | 
|  | struct Field { | 
|  | Field(uint32_t field_idx_in, | 
|  | const FieldDescriptor* field_descriptor_in, | 
|  | uint32_t type_in, | 
|  | const ProtoDescriptor* proto_descriptor_in); | 
|  |  | 
|  | bool has_field_name() const { | 
|  | return field_descriptor || field_idx == static_cast<uint32_t>(-1); | 
|  | } | 
|  |  | 
|  | std::string field_name() const; | 
|  | std::string type_name() const; | 
|  |  | 
|  | bool operator==(const Field& other) const { | 
|  | return field_idx == other.field_idx && type == other.type; | 
|  | } | 
|  |  | 
|  | uint32_t field_idx; | 
|  | uint32_t type; | 
|  | const FieldDescriptor* field_descriptor; | 
|  | const ProtoDescriptor* proto_descriptor; | 
|  | }; | 
|  |  | 
|  | using FieldPath = std::vector<Field>; | 
|  | struct FieldPathHasher { | 
|  | using argument_type = FieldPath; | 
|  | using result_type = size_t; | 
|  |  | 
|  | result_type operator()(const argument_type& p) const { | 
|  | size_t h = 0u; | 
|  | for (auto v : p) { | 
|  | h += (std::hash<uint32_t>{}(v.field_idx) + | 
|  | std::hash<uint32_t>{}(v.type)); | 
|  | h = (h << 5) - h; | 
|  | } | 
|  | return h; | 
|  | } | 
|  | }; | 
|  |  | 
|  | explicit SizeProfileComputer(DescriptorPool* pool, | 
|  | const std::string& message_type); | 
|  |  | 
|  | // Re-initializes the computer to iterate over samples (i.e. all encountered | 
|  | // field sizes) for each field path in trace proto contained in the given | 
|  | // range. | 
|  | // TODO(kraskevich): consider switching to internal DescriptorPool. | 
|  | void Reset(const uint8_t* ptr, size_t size); | 
|  |  | 
|  | // Returns the next sample size, or std::nullopt if data is exhausted. The | 
|  | // associated path can be queried with GetPath(). | 
|  | std::optional<size_t> GetNext(); | 
|  |  | 
|  | // Returns the field path associated with the last sample returned by | 
|  | // GetNext(). | 
|  | const FieldPath& GetPath() const { return field_path_; } | 
|  |  | 
|  | operator bool() const; | 
|  |  | 
|  | private: | 
|  | size_t GetFieldSize(const protozero::Field& f); | 
|  |  | 
|  | DescriptorPool* pool_; | 
|  | uint32_t root_message_idx_; | 
|  | // The current 'stack' we're considering as we parse the protobuf. | 
|  | // For example if we're currently looking at the varint field baz which is | 
|  | // nested inside message Bar which is in turn a field named bar on the message | 
|  | // Foo. Then the stack would be: Foo, #bar, Bar, #baz, int | 
|  | // We keep track of both the field names (#bar, #baz) and the field types | 
|  | // (Foo, Bar, int) as sometimes we are intrested in which fields are big | 
|  | // and sometimes which types are big. | 
|  | FieldPath field_path_; | 
|  |  | 
|  | // Internal state used to iterate over field path. | 
|  | struct State { | 
|  | const ProtoDescriptor* descriptor; | 
|  | protozero::ProtoDecoder decoder; | 
|  | size_t overhead; | 
|  | size_t unknown; | 
|  | }; | 
|  | std::vector<State> state_stack_; | 
|  | }; | 
|  |  | 
|  | }  // namespace util | 
|  | }  // namespace trace_processor | 
|  | }  // namespace perfetto | 
|  |  | 
|  | #endif  // SRC_TRACE_PROCESSOR_UTIL_PROTO_PROFILER_H_ |