| /* |
| * Copyright (C) 2021 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_INTERNED_MESSAGE_VIEW_H_ |
| #define SRC_TRACE_PROCESSOR_UTIL_INTERNED_MESSAGE_VIEW_H_ |
| |
| #include "perfetto/ext/base/flat_hash_map.h" |
| #include "perfetto/trace_processor/trace_blob_view.h" |
| |
| namespace perfetto { |
| namespace trace_processor { |
| |
| #if PERFETTO_DCHECK_IS_ON() |
| // When called from GetOrCreateDecoder(), should include the stringified name of |
| // the MessageType. |
| #define PERFETTO_TYPE_IDENTIFIER PERFETTO_DEBUG_FUNCTION_IDENTIFIER() |
| #else // PERFETTO_DCHECK_IS_ON() |
| #define PERFETTO_TYPE_IDENTIFIER nullptr |
| #endif // PERFETTO_DCHECK_IS_ON() |
| |
| // Entry in an interning index, refers to the interned message. |
| class InternedMessageView { |
| public: |
| explicit InternedMessageView(TraceBlobView msg) : message_(std::move(msg)) {} |
| |
| InternedMessageView(InternedMessageView&&) = default; |
| InternedMessageView& operator=(InternedMessageView&&) = default; |
| |
| // Allow copy by cloning the TraceBlobView. This is required for |
| // UpdateTracePacketDefaults(). |
| InternedMessageView(const InternedMessageView& view) |
| : message_(view.message_.copy()) {} |
| |
| InternedMessageView& operator=(const InternedMessageView& view) { |
| this->message_ = view.message_.copy(); |
| this->decoder_ = nullptr; |
| this->decoder_type_ = nullptr; |
| this->submessages_.Clear(); |
| return *this; |
| } |
| |
| // Lazily initializes and returns the decoder object for the message. The |
| // decoder is stored in the InternedMessageView to avoid having to parse the |
| // message multiple times. |
| template <typename MessageType> |
| typename MessageType::Decoder* GetOrCreateDecoder() { |
| if (!decoder_) { |
| // Lazy init the decoder and save it away, so that we don't have to |
| // reparse the message every time we access the interning entry. |
| decoder_ = std::unique_ptr<void, std::function<void(void*)>>( |
| new typename MessageType::Decoder(message_.data(), message_.length()), |
| [](void* obj) { |
| delete reinterpret_cast<typename MessageType::Decoder*>(obj); |
| }); |
| decoder_type_ = PERFETTO_TYPE_IDENTIFIER; |
| } |
| // Verify that the type of the decoder didn't change. |
| if (PERFETTO_TYPE_IDENTIFIER && |
| strcmp(decoder_type_, |
| // GCC complains if this arg can be null. |
| static_cast<bool>(PERFETTO_TYPE_IDENTIFIER) |
| ? PERFETTO_TYPE_IDENTIFIER |
| : "") != 0) { |
| PERFETTO_FATAL( |
| "Interning entry accessed under different types! previous type: " |
| "%s. new type: %s.", |
| decoder_type_, PERFETTO_DEBUG_FUNCTION_IDENTIFIER()); |
| } |
| return reinterpret_cast<typename MessageType::Decoder*>(decoder_.get()); |
| } |
| |
| // Lookup a submessage of the interned message, which is then itself stored |
| // as InternedMessageView, so that we only need to parse it once. Returns |
| // nullptr if the field isn't set. |
| // TODO(eseckler): Support repeated fields. |
| template <typename MessageType, uint32_t FieldId> |
| InternedMessageView* GetOrCreateSubmessageView() { |
| auto it_and_ins = submessages_.Insert(FieldId, nullptr); |
| if (!it_and_ins.second) |
| return it_and_ins.first->get(); |
| auto* decoder = GetOrCreateDecoder<MessageType>(); |
| // Calls the at() template method on the decoder. |
| auto field = decoder->template at<FieldId>().as_bytes(); |
| if (!field.data) |
| return nullptr; |
| TraceBlobView submessage = message_.slice(field.data, field.size); |
| InternedMessageView* submessage_view = |
| new InternedMessageView(std::move(submessage)); |
| it_and_ins.first->reset(submessage_view); |
| return submessage_view; |
| } |
| |
| const TraceBlobView& message() { return message_; } |
| |
| private: |
| using SubMessageViewMap = |
| base::FlatHashMap<uint32_t /*field_id*/, |
| std::unique_ptr<InternedMessageView>>; |
| |
| TraceBlobView message_; |
| |
| // Stores the decoder for the message_, so that the message does not have to |
| // be re-decoded every time the interned message is looked up. Lazily |
| // initialized in GetOrCreateDecoder(). Since we don't know the type of the |
| // decoder until GetOrCreateDecoder() is called, we store the decoder as a |
| // void* unique_pointer with a destructor function that's supplied in |
| // GetOrCreateDecoder() when the decoder is created. |
| std::unique_ptr<void, std::function<void(void*)>> decoder_; |
| |
| // Type identifier for the decoder. Only valid in debug builds and on |
| // supported platforms. Used to verify that GetOrCreateDecoder() is always |
| // called with the same template argument. |
| const char* decoder_type_ = nullptr; |
| |
| // Views of submessages of the interned message. Submessages are lazily |
| // added by GetOrCreateSubmessageView(). By storing submessages and their |
| // decoders, we avoid having to decode submessages multiple times if they |
| // looked up often. |
| SubMessageViewMap submessages_; |
| }; |
| |
| } // namespace trace_processor |
| } // namespace perfetto |
| |
| #endif // SRC_TRACE_PROCESSOR_UTIL_INTERNED_MESSAGE_VIEW_H_ |