blob: 3422b8bea80fb33e843cc83b181cbdd6e41468b9 [file] [log] [blame]
/*
* 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.
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_