Merge "traced_probes: Bump atrace timeout"
diff --git a/include/perfetto/protozero/message.h b/include/perfetto/protozero/message.h
index c3fdfd6..b53dcda 100644
--- a/include/perfetto/protozero/message.h
+++ b/include/perfetto/protozero/message.h
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <string.h>
 
+#include <string>
 #include <type_traits>
 
 #include "perfetto/base/export.h"
@@ -142,6 +143,11 @@
   }
 
   void AppendString(uint32_t field_id, const char* str);
+
+  void AppendString(uint32_t field_id, const std::string& str) {
+    AppendBytes(field_id, str.data(), str.size());
+  }
+
   void AppendBytes(uint32_t field_id, const void* value, size_t size);
 
   // Append raw bytes for a field, using the supplied |ranges| to
diff --git a/include/perfetto/trace_processor/basic_types.h b/include/perfetto/trace_processor/basic_types.h
index ca540d2..541f265 100644
--- a/include/perfetto/trace_processor/basic_types.h
+++ b/include/perfetto/trace_processor/basic_types.h
@@ -35,6 +35,10 @@
   // When set to true, this option forces trace processor to perform a full
   // sort ignoring any internal heureustics to skip sorting parts of the data.
   bool force_full_sort = false;
+
+  // When set to a non-zero value, this overrides the default block size used
+  // by the StringPool. For defaults, see kDefaultBlockSize in string_pool.h.
+  size_t string_pool_block_size_bytes = 0;
 };
 
 // Represents a dynamically typed value returned by SQL.
diff --git a/src/protozero/protoc_plugin/cppgen_plugin.cc b/src/protozero/protoc_plugin/cppgen_plugin.cc
index 51fb707..78ac16a 100644
--- a/src/protozero/protoc_plugin/cppgen_plugin.cc
+++ b/src/protozero/protoc_plugin/cppgen_plugin.cc
@@ -47,7 +47,6 @@
 using perfetto::base::ToUpper;
 
 static constexpr auto TYPE_MESSAGE = FieldDescriptor::TYPE_MESSAGE;
-static constexpr auto TYPE_ENUM = FieldDescriptor::TYPE_ENUM;
 static constexpr auto TYPE_SINT32 = FieldDescriptor::TYPE_SINT32;
 static constexpr auto TYPE_SINT64 = FieldDescriptor::TYPE_SINT64;
 
@@ -96,9 +95,10 @@
                 std::string* error) const override;
 
  private:
-  std::string GetCppType(const FieldDescriptor* field, bool constref) const;
-  std::string GetPackedBuffer(const FieldDescriptor* field) const;
-  std::string GetPackedWireType(const FieldDescriptor* field) const;
+  static std::string GetCppType(const FieldDescriptor* field, bool constref);
+  static std::string GetProtozeroSetter(const FieldDescriptor* field);
+  static std::string GetPackedBuffer(const FieldDescriptor* field);
+  static std::string GetPackedWireType(const FieldDescriptor* field);
 
   void GenEnum(const EnumDescriptor*, Printer*) const;
   void GenEnumAliases(const EnumDescriptor*, Printer*) const;
@@ -140,6 +140,10 @@
   h_printer.Print("#include \"perfetto/protozero/copyable_ptr.h\"\n");
   h_printer.Print("#include \"perfetto/base/export.h\"\n\n");
 
+  cc_printer.Print("#include \"perfetto/protozero/message.h\"\n");
+  cc_printer.Print(
+      "#include \"perfetto/protozero/packed_repeated_fields.h\"\n");
+  cc_printer.Print("#include \"perfetto/protozero/proto_decoder.h\"\n");
   cc_printer.Print("#include \"perfetto/protozero/scattered_heap_buffer.h\"\n");
   cc_printer.Print(kHeader);
   cc_printer.Print("#pragma GCC diagnostic push\n");
@@ -165,10 +169,6 @@
     }
   }
 
-  // Include the .pbzero.h for the current file.
-  std::string inc_base_name = StripSuffix(file->name(), ".proto");
-  cc_printer.Print("\n#include \"$f$.pbzero.h\"\n", "f", inc_base_name);
-
   // Recursively traverse all imports and turn them into #include(s).
   std::vector<const FileDescriptor*> imports_to_visit;
   std::set<const FileDescriptor*> imports_visited;
@@ -180,7 +180,6 @@
     imports_visited.insert(cur);
     std::string base_name = StripSuffix(cur->name(), ".proto");
     cc_printer.Print("#include \"$f$.gen.h\"\n", "f", base_name);
-    cc_printer.Print("#include \"$f$.pbzero.h\"\n", "f", base_name);
     for (int i = 0; i < cur->dependency_count(); i++) {
       const FileDescriptor* dep = cur->dependency(i);
       if (imports_visited.count(dep) || lazy_imports.count(dep->name()))
@@ -277,9 +276,9 @@
     }
   };
 
+  add_fwd_decl(kClass, "protozero::Message");
   for (const Descriptor* msg : all_types) {
     add_fwd_decl(kClass, GetFullName(msg, true));
-    add_fwd_decl(kClass, GetFullName(msg, true, ".pbzero"));
   }
   for (const EnumDescriptor* enm : all_enums) {
     add_fwd_decl(kEnum, GetFullName(enm, true));
@@ -335,7 +334,7 @@
 }
 
 std::string CppObjGenerator::GetCppType(const FieldDescriptor* field,
-                                        bool constref) const {
+                                        bool constref) {
   switch (field->type()) {
     case FieldDescriptor::TYPE_DOUBLE:
       return "double";
@@ -372,8 +371,37 @@
   abort();  // for gcc
 }
 
-std::string CppObjGenerator::GetPackedBuffer(
-    const FieldDescriptor* field) const {
+std::string CppObjGenerator::GetProtozeroSetter(const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_BOOL:
+      return "AppendTinyVarInt";
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_ENUM:
+      return "AppendVarInt";
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SINT64:
+      return "AppendSignedVarInt";
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "AppendFixed";
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      return "AppendString";
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      abort();
+  }
+  abort();
+}
+
+std::string CppObjGenerator::GetPackedBuffer(const FieldDescriptor* field) {
   switch (field->type()) {
     case FieldDescriptor::TYPE_FIXED32:
       return "::protozero::PackedFixedSizeInt<uint32_t>";
@@ -405,8 +433,7 @@
   abort();
 }
 
-std::string CppObjGenerator::GetPackedWireType(
-    const FieldDescriptor* field) const {
+std::string CppObjGenerator::GetPackedWireType(const FieldDescriptor* field) {
   switch (field->type()) {
     case FieldDescriptor::TYPE_FIXED32:
     case FieldDescriptor::TYPE_SFIXED32:
@@ -523,8 +550,7 @@
 
   p->Print("std::string SerializeAsString() const;\n");
   p->Print("std::vector<uint8_t> SerializeAsArray() const;\n");
-  p->Print("void Serialize($p$*) const;\n", "p",
-           GetFullName(msg, true, ".pbzero"));
+  p->Print("void Serialize(::protozero::Message*) const;\n");
 
   p->Print("// (DEPRECATED) Conversion methods from/to libprotobuf types.\n");
   p->Print("// These two will go away soon, see go/perfetto-libprotobuf.\n");
@@ -733,8 +759,7 @@
   // Generate the SerializeAsString() method definition.
   p->Print("std::string $f$::SerializeAsString() const {\n", "f", full_name);
   p->Indent();
-  p->Print("::protozero::HeapBuffered<$p$> msg;\n", "p",
-           GetFullName(msg, true, ".pbzero"));
+  p->Print("::protozero::HeapBuffered<::protozero::Message> msg;\n");
   p->Print("Serialize(msg.get());\n");
   p->Print("return msg.SerializeAsString();\n");
   p->Outdent();
@@ -744,62 +769,59 @@
   p->Print("std::vector<uint8_t> $f$::SerializeAsArray() const {\n", "f",
            full_name);
   p->Indent();
-  p->Print("::protozero::HeapBuffered<$p$> msg;\n", "p",
-           GetFullName(msg, true, ".pbzero"));
+  p->Print("::protozero::HeapBuffered<::protozero::Message> msg;\n");
   p->Print("Serialize(msg.get());\n");
   p->Print("return msg.SerializeAsArray();\n");
   p->Outdent();
   p->Print("}\n\n");
 
-  // Generaate the Serialize() method that writes the fields into the passed
+  // Generate the Serialize() method that writes the fields into the passed
   // protozero |msg| write-only interface |msg|.
-  p->Print("void $f$::Serialize($p$* msg) const {\n", "f", full_name, "p",
-           GetFullName(msg, true, ".pbzero"));
+  p->Print("void $f$::Serialize(::protozero::Message* msg) const {\n", "f",
+           full_name);
   p->Indent();
   for (int i = 0; i < msg->field_count(); i++) {
     const FieldDescriptor* field = msg->field(i);
-    std::string fld_name = field->lowercase_name();
-    if (field->options().lazy()) {
-      p->Print("msg->set_$n$_raw($n$_);\n", "n", fld_name);
+    std::map<std::string, std::string> args;
+    args["id"] = std::to_string(field->number());
+    args["n"] = field->lowercase_name();
+    p->Print(args, "// Field $id$: $n$\n");
+    if (field->is_packed()) {
+      PERFETTO_CHECK(field->is_repeated());
+      p->Print("{\n");
+      p->Indent();
+      p->Print("$p$ pack;\n", "p", GetPackedBuffer(field));
+      p->Print(args, "for (auto& it : $n$_)\n");
+      p->Print(args, "  pack.Append(it);\n");
+      p->Print(args, "msg->AppendBytes($id$, pack.data(), pack.size());\n");
+      p->Outdent();
+      p->Print("}\n");
     } else {
-      std::string enum_type;
-      if (field->type() == TYPE_ENUM)
-        enum_type = GetFullName(field->enum_type(), true, ".pbzero");
-      if (field->is_packed()) {
-        PERFETTO_CHECK(field->is_repeated());
-        p->Print("{\n");
-        p->Indent();
-        p->Print("$p$ pack;\n", "p", GetPackedBuffer(field));
-        p->Print("for (auto& it : $n$_)\n", "n", fld_name);
-        p->Print("  pack.Append(it);\n");
-        p->Print("msg->set_$n$(pack);\n", "n", fld_name);
-        p->Outdent();
-        p->Print("}\n");
-      } else if (field->is_repeated()) {
-        p->Print("for (auto& it : $n$_) {\n", "n", fld_name);
-        if (field->type() == TYPE_MESSAGE) {
-          p->Print("  it.Serialize(msg->add_$n$());\n", "n", fld_name);
-        } else if (field->type() == TYPE_ENUM) {
-          p->Print("  msg->add_$n$(static_cast<::$e$>(it));\n", "n", fld_name,
-                   "e", enum_type);
-        } else {
-          p->Print("  msg->add_$n$(it);\n", "n", fld_name);
-        }
-        p->Print("}\n");
-      } else {  // repeated = false
-        p->Print("if (_has_field_[$id$]) { ", "id",
-                 std::to_string(field->number()));
-        if (field->type() == TYPE_MESSAGE) {
-          p->Print("$n$_->Serialize(msg->set_$n$());", "n", fld_name);
-        } else if (field->type() == TYPE_ENUM) {
-          p->Print("msg->set_$n$(static_cast<::$e$>($n$_));", "n", fld_name,
-                   "e", enum_type);
-        } else {
-          p->Print("msg->set_$n$($n$_);", "n", fld_name);
-        }
-        p->Print(" }\n");
+      if (field->is_repeated()) {
+        p->Print(args, "for (auto& it : $n$_) {\n");
+        args["lvalue"] = "it";
+        args["rvalue"] = "it";
+      } else {
+        p->Print(args, "if (_has_field_[$id$]) {\n");
+        args["lvalue"] = "(*" + field->lowercase_name() + "_)";
+        args["rvalue"] = field->lowercase_name() + "_";
       }
+      p->Indent();
+      if (field->options().lazy()) {
+        p->Print(args, "msg->AppendString($id$, $rvalue$);\n");
+      } else if (field->type() == TYPE_MESSAGE) {
+        p->Print(args,
+                 "$lvalue$.Serialize("
+                 "msg->BeginNestedMessage<::protozero::Message>($id$));\n");
+      } else {
+        args["setter"] = GetProtozeroSetter(field);
+        p->Print(args, "msg->$setter$($id$, $rvalue$);\n");
+      }
+      p->Outdent();
+      p->Print("}\n");
     }
+
+    p->Print("\n");
   }  // for (field)
   p->Print(
       "msg->AppendRawProtoBytes(unknown_fields_.data(), "
diff --git a/src/trace_processor/string_pool.cc b/src/trace_processor/string_pool.cc
index 6574e36..1a45e27 100644
--- a/src/trace_processor/string_pool.cc
+++ b/src/trace_processor/string_pool.cc
@@ -16,14 +16,18 @@
 
 #include "src/trace_processor/string_pool.h"
 
+#include <limits>
+
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/utils.h"
 
 namespace perfetto {
 namespace trace_processor {
 
-StringPool::StringPool() {
-  blocks_.emplace_back(kDefaultBlockSize);
+StringPool::StringPool(size_t block_size_bytes)
+    : block_size_bytes_(block_size_bytes > 0 ? block_size_bytes
+                                             : kDefaultBlockSize) {
+  blocks_.emplace_back(block_size_bytes_);
 
   // Reserve a slot for the null string.
   PERFETTO_CHECK(blocks_.back().TryInsert(NullTermStringView()));
@@ -40,16 +44,16 @@
   const uint8_t* ptr = blocks_.back().TryInsert(str);
   if (PERFETTO_UNLIKELY(!ptr)) {
     // This means the block did not have enough space. This should only happen
-    // on 32-bit platforms as we allocate a 4GB mmap on 64 bit.
-    PERFETTO_CHECK(sizeof(uint8_t*) == 4);
+    // if the block size is small.
+    PERFETTO_CHECK(block_size_bytes_ <= std::numeric_limits<uint32_t>::max());
 
     // Add a new block to store the data. If the string is larger that the
     // default block size, add a bigger block exlusively for this string.
-    if (str.size() + kMaxMetadataSize > kDefaultBlockSize) {
+    if (str.size() + kMaxMetadataSize > block_size_bytes_) {
       blocks_.emplace_back(str.size() +
                            base::AlignUp<base::kPageSize>(kMaxMetadataSize));
     } else {
-      blocks_.emplace_back(kDefaultBlockSize);
+      blocks_.emplace_back(block_size_bytes_);
     }
 
     // Try and reserve space again - this time we should definitely succeed.
diff --git a/src/trace_processor/string_pool.h b/src/trace_processor/string_pool.h
index 3724d5e..d632764 100644
--- a/src/trace_processor/string_pool.h
+++ b/src/trace_processor/string_pool.h
@@ -17,14 +17,17 @@
 #ifndef SRC_TRACE_PROCESSOR_STRING_POOL_H_
 #define SRC_TRACE_PROCESSOR_STRING_POOL_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
+#include <unordered_map>
+#include <vector>
+
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/paged_memory.h"
 #include "perfetto/protozero/proto_utils.h"
 #include "src/trace_processor/null_term_string_view.h"
 
-#include <unordered_map>
-#include <vector>
-
 namespace perfetto {
 namespace trace_processor {
 
@@ -71,7 +74,7 @@
     uint32_t block_offset_ = 0;
   };
 
-  StringPool();
+  StringPool(size_t block_size_bytes = kDefaultBlockSize);
   ~StringPool();
 
   // Allow std::move().
@@ -217,6 +220,10 @@
     return NullTermStringView(reinterpret_cast<const char*>(str_ptr), size);
   }
 
+  // The minimum size of a new block. A larger block may be created if a string
+  // is added that is larger than this size.
+  size_t block_size_bytes_;
+
   // The actual memory storing the strings.
   std::vector<Block> blocks_;
 
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index 1b9f256..85e464b 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -61,7 +61,8 @@
   return map.ref();
 }
 
-TraceStorage::TraceStorage() {
+TraceStorage::TraceStorage(const Config& config)
+    : string_pool_(config.string_pool_block_size_bytes) {
   // Upid/utid 0 is reserved for idle processes/threads.
   unique_processes_.emplace_back(0);
   unique_threads_.emplace_back(0);
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index fbae94b..bfb7ae5 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -31,6 +31,7 @@
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/string_view.h"
 #include "perfetto/ext/base/utils.h"
+#include "perfetto/trace_processor/basic_types.h"
 #include "src/trace_processor/ftrace_utils.h"
 #include "src/trace_processor/metadata.h"
 #include "src/trace_processor/stats.h"
@@ -103,7 +104,7 @@
 // names for a given CPU).
 class TraceStorage {
  public:
-  TraceStorage();
+  TraceStorage(const Config& = Config());
 
   virtual ~TraceStorage();
 
diff --git a/tools/trace_processor b/tools/trace_processor
index e85568e..44e9946 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -31,8 +31,8 @@
 import urllib
 
 TRACE_PROCESSOR_SHELL_SHAS = {
-    'linux': 'dc506737a39264232609261f235caecf7e1cb4e6',
-    'mac': '54c84c12d15a89e2b83a2be6e25d1d799f4ed93b',
+    'linux': 'a4852390aa8e02089d125be0cbfea9f2ada7fded',
+    'mac': '52710df7fad736a45dc118b3feec3959d6ff3d91',
 }
 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 6cfe78a..ac79196 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -33,8 +33,8 @@
 # Keep this in sync with the SHAs in catapult file
 # systrace/systrace/tracing_agents/atrace_from_file_agent.py.
 TRACE_TO_TEXT_SHAS = {
-    'linux': '46ce31e5bf41aa872bb27b2694d912ddce03b87b',
-    'mac': 'ca6d3f969282e323fc8cc3dc73ba9722df1f2649',
+    'linux': '09b96a4458337df9ba30e49f422685ea1bceedfb',
+    'mac': '7696aa6785703f304447d6575aa4934684260985',
 }
 TRACE_TO_TEXT_PATH = tempfile.gettempdir()
 TRACE_TO_TEXT_BASE_URL = ('https://storage.googleapis.com/perfetto/')