Merge "tp: parse sched blocked reason from proto and systrace"
diff --git a/Android.bp b/Android.bp
index 8206d4c..8470f3c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6539,6 +6539,7 @@
srcs: [
"src/protozero/field.cc",
"src/protozero/message.cc",
+ "src/protozero/message_arena.cc",
"src/protozero/message_handle.cc",
"src/protozero/packed_repeated_fields.cc",
"src/protozero/proto_decoder.cc",
diff --git a/BUILD b/BUILD
index fd76439..309cbc8 100644
--- a/BUILD
+++ b/BUILD
@@ -413,10 +413,12 @@
"include/perfetto/protozero/cpp_message_obj.h",
"include/perfetto/protozero/field.h",
"include/perfetto/protozero/message.h",
+ "include/perfetto/protozero/message_arena.h",
"include/perfetto/protozero/message_handle.h",
"include/perfetto/protozero/packed_repeated_fields.h",
"include/perfetto/protozero/proto_decoder.h",
"include/perfetto/protozero/proto_utils.h",
+ "include/perfetto/protozero/root_message.h",
"include/perfetto/protozero/scattered_heap_buffer.h",
"include/perfetto/protozero/scattered_stream_null_delegate.h",
"include/perfetto/protozero/scattered_stream_writer.h",
@@ -665,6 +667,7 @@
srcs = [
"src/protozero/field.cc",
"src/protozero/message.cc",
+ "src/protozero/message_arena.cc",
"src/protozero/message_handle.cc",
"src/protozero/packed_repeated_fields.cc",
"src/protozero/proto_decoder.cc",
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index 334c3f9..b228411 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -66,6 +66,21 @@
#define PERFETTO_THREAD_LOCAL thread_local
#endif
+#if defined(__clang__)
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+extern "C" void __asan_poison_memory_region(void const volatile*, size_t);
+extern "C" void __asan_unpoison_memory_region(void const volatile*, size_t);
+#define PERFETTO_ASAN_POISON(a, s) __asan_poison_memory_region((a), (s))
+#define PERFETTO_ASAN_UNPOISON(a, s) __asan_unpoison_memory_region((a), (s))
+#else
+#define PERFETTO_ASAN_POISON(addr, size)
+#define PERFETTO_ASAN_UNPOISON(addr, size)
+#endif // __has_feature(address_sanitizer)
+#else
+#define PERFETTO_ASAN_POISON(addr, size)
+#define PERFETTO_ASAN_UNPOISON(addr, size)
+#endif // __clang__
+
namespace perfetto {
namespace base {
diff --git a/include/perfetto/protozero/BUILD.gn b/include/perfetto/protozero/BUILD.gn
index ee0f77a..93fdce4 100644
--- a/include/perfetto/protozero/BUILD.gn
+++ b/include/perfetto/protozero/BUILD.gn
@@ -20,10 +20,12 @@
"cpp_message_obj.h",
"field.h",
"message.h",
+ "message_arena.h",
"message_handle.h",
"packed_repeated_fields.h",
"proto_decoder.h",
"proto_utils.h",
+ "root_message.h",
"scattered_heap_buffer.h",
"scattered_stream_null_delegate.h",
"scattered_stream_writer.h",
diff --git a/include/perfetto/protozero/message.h b/include/perfetto/protozero/message.h
index b53dcda..a47db7e 100644
--- a/include/perfetto/protozero/message.h
+++ b/include/perfetto/protozero/message.h
@@ -38,30 +38,28 @@
namespace protozero {
+class MessageArena;
class MessageHandleBase;
// Base class extended by the proto C++ stubs generated by the ProtoZero
// compiler. This class provides the minimal runtime required to support
// append-only operations and is designed for performance. None of the methods
-// require any dynamic memory allocation.
+// require any dynamic memory allocation, unless more than 16 nested messages
+// are created via BeginNestedMessage() calls.
class PERFETTO_EXPORT Message {
public:
friend class MessageHandleBase;
- // Adjust the |nested_messages_arena_| size when changing this, or the
- // static_assert in the .cc file will bark.
- static constexpr uint32_t kMaxNestingDepth = 10;
-
- // Ctor and Dtor of Message are never called, with the exeception
- // of root (non-nested) messages. Nested messages are allocated via placement
- // new in the |nested_messages_arena_| and implictly destroyed when the arena
- // of the root message goes away. This is fine as long as all the fields are
- // PODs, which is checked by the static_assert in the ctor (see the Reset()
- // method in the .cc file).
+ // The ctor is deliberately a no-op to avoid forwarding args from all
+ // subclasses. The real initialization is performed by Reset().
+ // Nested messages are allocated via placement new by MessageArena and
+ // implictly destroyed when the RootMessage's arena goes away. This is
+ // fine as long as all the fields are PODs, which is checked by the
+ // static_assert()s in the Reset() method.
Message() = default;
// Clears up the state, allowing the message to be reused as a fresh one.
- void Reset(ScatteredStreamWriter*);
+ void Reset(ScatteredStreamWriter*, MessageArena*);
// Commits all the changes to the buffer (backfills the size field of this and
// all nested messages) and seals the message. Returns the size of the message
@@ -156,10 +154,9 @@
ContiguousMemoryRange* ranges,
size_t num_ranges);
- // Begins a nested message, using the static storage provided by the parent
- // class (see comment in |nested_messages_arena_|). The nested message ends
- // either when Finalize() is called or when any other Append* method is called
- // in the parent class.
+ // Begins a nested message. The returned object is owned by the MessageArena
+ // of the root message. The nested message ends either when Finalize() is
+ // called or when any other Append* method is called in the parent class.
// The template argument T is supposed to be a stub class auto generated from
// a .proto, hence a subclass of Message.
template <class T>
@@ -170,9 +167,7 @@
"T must be a subclass of Message");
static_assert(sizeof(T) == sizeof(Message),
"Message subclasses cannot introduce extra state.");
- T* message = reinterpret_cast<T*>(nested_messages_arena_);
- BeginNestedMessageInternal(field_id, message);
- return message;
+ return static_cast<T*>(BeginNestedMessageInternal(field_id));
}
ScatteredStreamWriter* stream_writer_for_testing() { return stream_writer_; }
@@ -191,7 +186,7 @@
Message(const Message&) = delete;
Message& operator=(const Message&) = delete;
- void BeginNestedMessageInternal(uint32_t field_id, Message*);
+ Message* BeginNestedMessageInternal(uint32_t field_id);
// Called by Finalize and Append* methods.
void EndNestedMessage();
@@ -210,6 +205,22 @@
// The stream writer interface used for the serialization.
ScatteredStreamWriter* stream_writer_;
+ // The storage used to allocate nested Message objects.
+ // This is owned by RootMessage<T>.
+ MessageArena* arena_;
+
+ // Pointer to the last child message created through BeginNestedMessage(), if
+ // any, nullptr otherwise. There is no need to keep track of more than one
+ // message per nesting level as the proto-zero API contract mandates that
+ // nested fields can be filled only in a stacked fashion. In other words,
+ // nested messages are finalized and sealed when any other field is set in the
+ // parent message (or the parent message itself is finalized) and cannot be
+ // accessed anymore afterwards.
+ Message* nested_message_;
+
+ // [optional] Pointer to a non-aligned pre-reserved var-int slot of
+ // kMessageLengthFieldSize bytes. When set, the Finalize() method will write
+ // the size of proto-encoded message in the pointed memory region.
uint8_t* size_field_;
// Keeps track of the size of the current message.
@@ -222,10 +233,6 @@
// attempts of writing to a message which has been Finalize()-d.
bool finalized_;
- // Used to detect attemps to create messages with a nesting level >
- // kMaxNestingDepth. |nesting_depth_| == 0 for root (non-nested) messages.
- uint8_t nesting_depth_;
-
#if PERFETTO_DCHECK_IS_ON()
// Current generation of message. Incremented on Reset.
// Used to detect stale handles.
@@ -233,28 +240,6 @@
MessageHandleBase* handle_;
#endif
-
- // Pointer to the last child message created through BeginNestedMessage(), if
- // any, nullptr otherwise. There is no need to keep track of more than one
- // message per nesting level as the proto-zero API contract mandates that
- // nested fields can be filled only in a stacked fashion. In other words,
- // nested messages are finalized and sealed when any other field is set in the
- // parent message (or the parent message itself is finalized) and cannot be
- // accessed anymore afterwards.
- // TODO(primiano): optimization: I think that nested_message_, when non-null.
- // will always be @ (this) + offsetof(nested_messages_arena_).
- Message* nested_message_;
-
- // The root message owns the storage for all its nested messages, up to a max
- // of kMaxNestingDepth levels (see the .cc file). Note that the boundaries of
- // the arena are meaningful only for the root message.
- // Unfortunately we cannot put the sizeof() math here because we cannot sizeof
- // the current class in a header. However the .cc file has a static_assert
- // that guarantees that (see the Reset() method in the .cc file).
- alignas(sizeof(void*)) uint8_t nested_messages_arena_[512];
-
- // DO NOT add any fields below |nested_messages_arena_|. The memory layout of
- // nested messages would overflow the storage allocated by the root message.
};
} // namespace protozero
diff --git a/include/perfetto/protozero/message_arena.h b/include/perfetto/protozero/message_arena.h
new file mode 100644
index 0000000..4905dae
--- /dev/null
+++ b/include/perfetto/protozero/message_arena.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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 INCLUDE_PERFETTO_PROTOZERO_MESSAGE_ARENA_H_
+#define INCLUDE_PERFETTO_PROTOZERO_MESSAGE_ARENA_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <type_traits>
+
+#include "perfetto/base/export.h"
+#include "perfetto/base/logging.h"
+#include "perfetto/protozero/message.h"
+
+namespace protozero {
+
+class Message;
+
+// Object allocator for fixed-sized protozero::Message objects.
+// It's a simple bump-pointer allocator which leverages the stack-alike
+// usage pattern of protozero nested messages. It avoids hitting the system
+// allocator in most cases, by reusing the same block, and falls back on
+// allocating new blocks only when using deeply nested messages (which are
+// extremely rare).
+// This is used by RootMessage<T> to handle the storage for root-level messages.
+class PERFETTO_EXPORT MessageArena {
+ public:
+ MessageArena();
+ ~MessageArena();
+
+ // Strictly no copies or moves as this is used to hand out pointers.
+ MessageArena(const MessageArena&) = delete;
+ MessageArena& operator=(const MessageArena&) = delete;
+ MessageArena(MessageArena&&) = delete;
+ MessageArena& operator=(MessageArena&&) = delete;
+
+ // Allocates a new Message object.
+ Message* NewMessage();
+
+ // Deletes the last message allocated. The |msg| argument is used only for
+ // DCHECKs, it MUST be the pointer obtained by the last NewMessage() call.
+ void DeleteLastMessage(Message* msg) {
+ PERFETTO_DCHECK(!blocks_.empty() && blocks_.back().entries > 0);
+ PERFETTO_DCHECK(&blocks_.back().storage[blocks_.back().entries - 1] ==
+ static_cast<void*>(msg));
+ DeleteLastMessageInternal();
+ }
+
+ // Resets the state of the arena, clearing up all but one block. This is used
+ // to avoid leaking outstanding unfinished sub-messages while recycling the
+ // RootMessage object (this is extremely rare due to the RAII scoped handles
+ // but could happen if some client does some overly clever std::move() trick).
+ void Reset() {
+ PERFETTO_DCHECK(!blocks_.empty());
+ blocks_.resize(1);
+ auto& block = blocks_.back();
+ block.entries = 0;
+ PERFETTO_ASAN_POISON(block.storage, sizeof(block.storage));
+ }
+
+ private:
+ void DeleteLastMessageInternal();
+
+ struct Block {
+ static constexpr size_t kCapacity = 16;
+
+ Block() { PERFETTO_ASAN_POISON(storage, sizeof(storage)); }
+
+ std::aligned_storage<sizeof(Message), alignof(Message)>::type
+ storage[kCapacity];
+ uint32_t entries = 0; // # Message entries used (<= kCapacity).
+ };
+
+ // blocks are used to hand out pointers and must not be moved. Hence why
+ // std::list rather than std::vector.
+ std::list<Block> blocks_;
+};
+
+} // namespace protozero
+
+#endif // INCLUDE_PERFETTO_PROTOZERO_MESSAGE_ARENA_H_
diff --git a/include/perfetto/protozero/root_message.h b/include/perfetto/protozero/root_message.h
new file mode 100644
index 0000000..40e2328
--- /dev/null
+++ b/include/perfetto/protozero/root_message.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 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 INCLUDE_PERFETTO_PROTOZERO_ROOT_MESSAGE_H_
+#define INCLUDE_PERFETTO_PROTOZERO_ROOT_MESSAGE_H_
+
+#include "perfetto/protozero/message.h"
+#include "perfetto/protozero/message_arena.h"
+
+namespace protozero {
+
+// Helper class to hand out messages using the default MessageArena.
+// Usage:
+// RootMessage<perfetto::protos::zero::MyMessage> msg;
+// msg.Reset(stream_writer);
+// msg.set_foo(...);
+// auto* nested = msg.set_nested();
+template <typename T = Message>
+class RootMessage : public T {
+ public:
+ RootMessage() { T::Reset(nullptr, &root_arena_); }
+
+ // Disallow copy and move.
+ RootMessage(const RootMessage&) = delete;
+ RootMessage& operator=(const RootMessage&) = delete;
+ RootMessage(RootMessage&&) = delete;
+ RootMessage& operator=(RootMessage&&) = delete;
+
+ void Reset(ScatteredStreamWriter* writer) {
+ root_arena_.Reset();
+ Message::Reset(writer, &root_arena_);
+ }
+
+ private:
+ MessageArena root_arena_;
+};
+
+} // namespace protozero
+
+#endif // INCLUDE_PERFETTO_PROTOZERO_ROOT_MESSAGE_H_
diff --git a/include/perfetto/protozero/scattered_heap_buffer.h b/include/perfetto/protozero/scattered_heap_buffer.h
index bc6a0d2..a42c977 100644
--- a/include/perfetto/protozero/scattered_heap_buffer.h
+++ b/include/perfetto/protozero/scattered_heap_buffer.h
@@ -23,6 +23,7 @@
#include "perfetto/base/export.h"
#include "perfetto/base/logging.h"
+#include "perfetto/protozero/root_message.h"
#include "perfetto/protozero/scattered_stream_writer.h"
namespace protozero {
@@ -165,7 +166,7 @@
private:
ScatteredHeapBuffer shb_;
ScatteredStreamWriter writer_;
- T msg_;
+ RootMessage<T> msg_;
};
} // namespace protozero
diff --git a/include/perfetto/protozero/static_buffer.h b/include/perfetto/protozero/static_buffer.h
index 6f5924f..3d7ec3d 100644
--- a/include/perfetto/protozero/static_buffer.h
+++ b/include/perfetto/protozero/static_buffer.h
@@ -22,6 +22,7 @@
#include <vector>
#include "perfetto/base/export.h"
+#include "perfetto/protozero/root_message.h"
#include "perfetto/protozero/scattered_stream_writer.h"
namespace protozero {
@@ -79,7 +80,7 @@
private:
StaticBufferDelegate delegate_;
ScatteredStreamWriter writer_;
- T msg_;
+ RootMessage<T> msg_;
};
// Helper function to create stack-based protozero messages in one line.
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index de6c11c..e1a9036 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -30,6 +30,7 @@
sources = [
"field.cc",
"message.cc",
+ "message_arena.cc",
"message_handle.cc",
"packed_repeated_fields.cc",
"proto_decoder.cc",
diff --git a/src/protozero/message.cc b/src/protozero/message.cc
index 419f7f1..cfc9b37 100644
--- a/src/protozero/message.cc
+++ b/src/protozero/message.cc
@@ -20,6 +20,7 @@
#include <type_traits>
#include "perfetto/base/logging.h"
+#include "perfetto/protozero/message_arena.h"
#include "perfetto/protozero/message_handle.h"
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
@@ -38,14 +39,11 @@
} // namespace
-// static
-constexpr uint32_t Message::kMaxNestingDepth;
-
// Do NOT put any code in the constructor or use default initialization.
-// Use the Reset() method below instead. See the header for the reason why.
+// Use the Reset() method below instead.
// This method is called to initialize both root and nested messages.
-void Message::Reset(ScatteredStreamWriter* stream_writer) {
+void Message::Reset(ScatteredStreamWriter* stream_writer, MessageArena* arena) {
// Older versions of libstdcxx don't have is_trivially_constructible.
#if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20170516
static_assert(std::is_trivially_constructible<Message>::value,
@@ -54,19 +52,12 @@
static_assert(std::is_trivially_destructible<Message>::value,
"Message must be trivially destructible");
-
- static_assert(
- sizeof(Message::nested_messages_arena_) >=
- kMaxNestingDepth *
- (sizeof(Message) - sizeof(Message::nested_messages_arena_)),
- "Message::nested_messages_arena_ is too small");
-
stream_writer_ = stream_writer;
+ arena_ = arena;
size_ = 0;
size_field_ = nullptr;
size_already_written_ = 0;
nested_message_ = nullptr;
- nesting_depth_ = 0;
finalized_ = false;
#if PERFETTO_DCHECK_IS_ON()
handle_ = nullptr;
@@ -147,7 +138,7 @@
return size_;
}
-void Message::BeginNestedMessageInternal(uint32_t field_id, Message* message) {
+Message* Message::BeginNestedMessageInternal(uint32_t field_id) {
if (nested_message_)
EndNestedMessage();
@@ -157,20 +148,22 @@
proto_utils::MakeTagLengthDelimited(field_id), data);
WriteToStream(data, data_end);
- message->Reset(stream_writer_);
- PERFETTO_CHECK(nesting_depth_ < kMaxNestingDepth);
- message->nesting_depth_ = nesting_depth_ + 1;
+ Message* message = arena_->NewMessage();
+ message->Reset(stream_writer_, arena_);
// The length of the nested message cannot be known upfront. So right now
// just reserve the bytes to encode the size after the nested message is done.
message->set_size_field(
stream_writer_->ReserveBytes(proto_utils::kMessageLengthFieldSize));
size_ += proto_utils::kMessageLengthFieldSize;
+
nested_message_ = message;
+ return message;
}
void Message::EndNestedMessage() {
size_ += nested_message_->Finalize();
+ arena_->DeleteLastMessage(nested_message_);
nested_message_ = nullptr;
}
diff --git a/src/protozero/message_arena.cc b/src/protozero/message_arena.cc
new file mode 100644
index 0000000..6e92cd0
--- /dev/null
+++ b/src/protozero/message_arena.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "perfetto/protozero/message_arena.h"
+
+#include <atomic>
+#include <type_traits>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/protozero/message_handle.h"
+
+namespace protozero {
+
+MessageArena::MessageArena() {
+ // The code below assumes that there is always at least one block.
+ blocks_.emplace_front();
+ static_assert(std::alignment_of<decltype(blocks_.back().storage[0])>::value >=
+ alignof(Message),
+ "MessageArea's storage is not properly aligned");
+}
+
+MessageArena::~MessageArena() = default;
+
+Message* MessageArena::NewMessage() {
+ PERFETTO_DCHECK(!blocks_.empty()); // Should never become empty.
+
+ Block* block = &blocks_.back();
+ if (PERFETTO_UNLIKELY(block->entries >= Block::kCapacity)) {
+ blocks_.emplace_back();
+ block = &blocks_.back();
+ }
+ const auto idx = block->entries++;
+ void* storage = &block->storage[idx];
+ PERFETTO_ASAN_UNPOISON(storage, sizeof(Message));
+ return new (storage) Message();
+}
+
+void MessageArena::DeleteLastMessageInternal() {
+ PERFETTO_DCHECK(!blocks_.empty()); // Should never be empty, see below.
+ Block* block = &blocks_.back();
+ PERFETTO_DCHECK(block->entries > 0);
+
+ // This is the reason why there is no ~Message() call here.
+ // MessageArea::Reset() (see header) also relies on dtor being trivial.
+ static_assert(std::is_trivially_destructible<Message>::value,
+ "Message must be trivially destructible");
+
+ --block->entries;
+ PERFETTO_ASAN_POISON(&block->storage[block->entries], sizeof(Message));
+
+ // Don't remove the first block to avoid malloc/free calls when the root
+ // message is reset. Hitting the allocator all the times is a waste of time.
+ if (block->entries == 0 && blocks_.size() > 1) {
+ blocks_.pop_back();
+ }
+}
+
+} // namespace protozero
diff --git a/src/protozero/message_handle_unittest.cc b/src/protozero/message_handle_unittest.cc
index 7f0ee08..96c8600 100644
--- a/src/protozero/message_handle_unittest.cc
+++ b/src/protozero/message_handle_unittest.cc
@@ -16,7 +16,7 @@
#include "perfetto/protozero/message_handle.h"
-#include "perfetto/protozero/message.h"
+#include "perfetto/protozero/root_message.h"
#include "test/gtest_and_gmock.h"
namespace protozero {
@@ -24,8 +24,7 @@
namespace {
TEST(MessageHandleTest, MoveHandleSharedMessageDoesntFinalize) {
- Message message;
- message.Reset(nullptr);
+ RootMessage<Message> message;
MessageHandle<Message> handle_1(&message);
handle_1 = MessageHandle<Message>(&message);
diff --git a/src/protozero/message_unittest.cc b/src/protozero/message_unittest.cc
index d75dcd0..a061ad9 100644
--- a/src/protozero/message_unittest.cc
+++ b/src/protozero/message_unittest.cc
@@ -15,7 +15,6 @@
*/
#include "perfetto/protozero/message.h"
-#include "perfetto/protozero/message_handle.h"
#include <limits>
#include <memory>
@@ -23,6 +22,8 @@
#include <vector>
#include "perfetto/base/logging.h"
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/root_message.h"
#include "src/base/test/utils.h"
#include "src/protozero/test/fake_scattered_buffer.h"
#include "test/gtest_and_gmock.h"
@@ -38,7 +39,7 @@
constexpr const char kEndWatermark[] = {'9', '8', '7', '6',
'z', 'w', 'y', '\0'};
-class FakeRootMessage : public Message {};
+class FakeRootMessage : public RootMessage<Message> {};
class FakeChildMessage : public Message {};
uint32_t SimpleHash(const std::string& str) {
@@ -63,7 +64,10 @@
EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
EXPECT_STREQ(kEndWatermark,
reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
- sizeof(Message)));
+ sizeof(FakeRootMessage)));
+ FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(
+ mem.get() + sizeof(kStartWatermark));
+ msg->~FakeRootMessage();
mem.reset();
}
messages_.clear();
@@ -83,7 +87,7 @@
memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
sizeof(kEndWatermark));
messages_.push_back(std::move(mem));
- FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(msg_start);
+ FakeRootMessage* msg = new (msg_start) FakeRootMessage();
msg->Reset(stream_writer_.get());
return msg;
}
@@ -101,14 +105,16 @@
return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
}
- static void BuildNestedMessages(Message* msg, uint32_t depth = 0) {
+ static void BuildNestedMessages(Message* msg,
+ uint32_t max_depth,
+ uint32_t depth = 0) {
for (uint32_t i = 1; i <= 128; ++i)
msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
- if (depth < Message::kMaxNestingDepth) {
+ if (depth < max_depth) {
auto* nested_msg =
msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
- BuildNestedMessages(nested_msg, depth + 1);
+ BuildNestedMessages(nested_msg, max_depth, depth + 1);
}
for (uint32_t i = 129; i <= 256; ++i)
@@ -279,7 +285,7 @@
std::vector<Message*> nested_msgs;
Message* root_msg = NewMessage();
- BuildNestedMessages(root_msg);
+ BuildNestedMessages(root_msg, /*max_depth=*/10);
root_msg->Finalize();
// The main point of this test is to stress the code paths and test for
@@ -291,13 +297,24 @@
EXPECT_EQ(0xf9e32b65, buf_hash);
}
+TEST_F(MessageTest, DeeplyNested) {
+ std::vector<Message*> nested_msgs;
+
+ Message* root_msg = NewMessage();
+ BuildNestedMessages(root_msg, /*max_depth=*/1000);
+ root_msg->Finalize();
+
+ std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
+ size_t buf_hash = SimpleHash(full_buf);
+ EXPECT_EQ(0xc0fde419, buf_hash);
+}
+
TEST_F(MessageTest, DestructInvalidMessageHandle) {
FakeRootMessage* msg = NewMessage();
- EXPECT_DCHECK_DEATH(
- {
- MessageHandle<FakeRootMessage> handle(msg);
- ResetMessage(msg);
- });
+ EXPECT_DCHECK_DEATH({
+ MessageHandle<FakeRootMessage> handle(msg);
+ ResetMessage(msg);
+ });
}
TEST_F(MessageTest, MessageHandle) {
diff --git a/src/traced/probes/ftrace/cpu_reader_benchmark.cc b/src/traced/probes/ftrace/cpu_reader_benchmark.cc
index ee6d246..063eefe 100644
--- a/src/traced/probes/ftrace/cpu_reader_benchmark.cc
+++ b/src/traced/probes/ftrace/cpu_reader_benchmark.cc
@@ -15,6 +15,7 @@
#include <benchmark/benchmark.h>
#include "perfetto/ext/base/utils.h"
+#include "perfetto/protozero/root_message.h"
#include "perfetto/protozero/scattered_stream_null_delegate.h"
#include "perfetto/protozero/scattered_stream_writer.h"
#include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
@@ -310,7 +311,7 @@
ScatteredStreamWriterNullDelegate delegate(perfetto::base::kPageSize);
ScatteredStreamWriter stream(&delegate);
- FtraceEventBundle writer;
+ protozero::RootMessage<FtraceEventBundle> writer;
ProtoTranslationTable* table = GetTable(test_case->name);
auto page = PageFromXxd(test_case->data);
diff --git a/src/tracing/core/null_trace_writer.cc b/src/tracing/core/null_trace_writer.cc
index 40fe9a5..784c2c1 100644
--- a/src/tracing/core/null_trace_writer.cc
+++ b/src/tracing/core/null_trace_writer.cc
@@ -18,7 +18,6 @@
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/utils.h"
-
#include "perfetto/protozero/message.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
@@ -27,7 +26,7 @@
NullTraceWriter::NullTraceWriter()
: delegate_(base::kPageSize), stream_(&delegate_) {
- cur_packet_.reset(new protos::pbzero::TracePacket());
+ cur_packet_.reset(new protozero::RootMessage<protos::pbzero::TracePacket>());
cur_packet_->Finalize(); // To avoid the DCHECK in NewTracePacket().
}
diff --git a/src/tracing/core/null_trace_writer.h b/src/tracing/core/null_trace_writer.h
index fabbca7..4f6c707 100644
--- a/src/tracing/core/null_trace_writer.h
+++ b/src/tracing/core/null_trace_writer.h
@@ -19,6 +19,7 @@
#include "perfetto/ext/tracing/core/trace_writer.h"
#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/root_message.h"
#include "perfetto/protozero/scattered_stream_null_delegate.h"
namespace perfetto {
@@ -47,7 +48,8 @@
// The packet returned via NewTracePacket(). Its owned by this class,
// TracePacketHandle has just a pointer to it.
- std::unique_ptr<protos::pbzero::TracePacket> cur_packet_;
+ std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>>
+ cur_packet_;
};
} // namespace perfetto
diff --git a/src/tracing/core/trace_writer_for_testing.cc b/src/tracing/core/trace_writer_for_testing.cc
index 838f93e..37357c7 100644
--- a/src/tracing/core/trace_writer_for_testing.cc
+++ b/src/tracing/core/trace_writer_for_testing.cc
@@ -29,7 +29,7 @@
static_cast<size_t>(base::kPageSize)),
stream_(&delegate_) {
delegate_.set_writer(&stream_);
- cur_packet_.reset(new protos::pbzero::TracePacket());
+ cur_packet_.reset(new protozero::RootMessage<protos::pbzero::TracePacket>());
cur_packet_->Finalize(); // To avoid the DCHECK in NewTracePacket().
}
diff --git a/src/tracing/core/trace_writer_for_testing.h b/src/tracing/core/trace_writer_for_testing.h
index f066fee..16c7c76 100644
--- a/src/tracing/core/trace_writer_for_testing.h
+++ b/src/tracing/core/trace_writer_for_testing.h
@@ -20,6 +20,7 @@
#include "perfetto/ext/tracing/core/trace_writer.h"
#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/root_message.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "protos/perfetto/trace/trace_packet.gen.h"
@@ -53,7 +54,8 @@
// The packet returned via NewTracePacket(). Its owned by this class,
// TracePacketHandle has just a pointer to it.
- std::unique_ptr<protos::pbzero::TracePacket> cur_packet_;
+ std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>>
+ cur_packet_;
};
} // namespace perfetto
diff --git a/src/tracing/core/trace_writer_impl.cc b/src/tracing/core/trace_writer_impl.cc
index f0705ae..dd0044b 100644
--- a/src/tracing/core/trace_writer_impl.cc
+++ b/src/tracing/core/trace_writer_impl.cc
@@ -24,7 +24,9 @@
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/thread_annotations.h"
+#include "perfetto/protozero/message.h"
#include "perfetto/protozero/proto_utils.h"
+#include "perfetto/protozero/root_message.h"
#include "src/tracing/core/shared_memory_arbiter_impl.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
@@ -54,7 +56,7 @@
// more gracefully and always return a no-op TracePacket in NewTracePacket().
PERFETTO_CHECK(id_ != 0);
- cur_packet_.reset(new protos::pbzero::TracePacket());
+ cur_packet_.reset(new protozero::RootMessage<protos::pbzero::TracePacket>());
cur_packet_->Finalize(); // To avoid the DCHECK in NewTracePacket().
}
diff --git a/src/tracing/core/trace_writer_impl.h b/src/tracing/core/trace_writer_impl.h
index be2daef..9f3b970 100644
--- a/src/tracing/core/trace_writer_impl.h
+++ b/src/tracing/core/trace_writer_impl.h
@@ -24,6 +24,7 @@
#include "perfetto/ext/tracing/core/trace_writer.h"
#include "perfetto/protozero/message_handle.h"
#include "perfetto/protozero/proto_utils.h"
+#include "perfetto/protozero/root_message.h"
#include "perfetto/protozero/scattered_stream_writer.h"
#include "perfetto/tracing/buffer_exhausted_policy.h"
#include "src/tracing/core/patch_list.h"
@@ -92,7 +93,8 @@
// The packet returned via NewTracePacket(). Its owned by this class,
// TracePacketHandle has just a pointer to it.
- std::unique_ptr<protos::pbzero::TracePacket> cur_packet_;
+ std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>>
+ cur_packet_;
// The start address of |cur_packet_| within |cur_chunk_|. Used to figure out
// fragments sizes when a TracePacket write is interrupted by GetNewBuffer().
diff --git a/tools/trace_processor b/tools/trace_processor
index 45edc6b..0ac3f19 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -31,8 +31,8 @@
import subprocess
TRACE_PROCESSOR_SHELL_SHAS = {
- 'linux': 'cf35126998a679d6858a535cf7cbbfad2f6fa162',
- 'mac': 'e2523e6a630cb46f9d49f2a0b1da7962ad4c6999',
+ 'linux': '4d8772482f49d3c34149e73fd7f4cd0c286652b0',
+ 'mac': '69f34336ead727bea5f3db83daee5b5d5f88bf6a',
}
TRACE_PROCESSOR_SHELL_PATH = tempfile.gettempdir()
TRACE_PROCESSOR_SHELL_BASE_URL = ('https://storage.googleapis.com/perfetto/')
diff --git a/tools/traceconv b/tools/traceconv
index 99086da..11c164d 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -32,8 +32,8 @@
TRACE_TO_TEXT_SHAS = {
- 'linux': '197897706cc2bf0039f6126c123021740bf7bc86',
- 'mac': '4cf16fda1c2ad6b829550fbb24ef22d15123ffdf',
+ 'linux': '9e8dee1170a983a34ddeaf3d7c5045843df4c671',
+ 'mac': 'ea93f3609e378168ef4b43744d6bbc99de6d1c47',
}
TRACE_TO_TEXT_PATH = tempfile.gettempdir()
TRACE_TO_TEXT_BASE_URL = ('https://storage.googleapis.com/perfetto/')