Add a comparison operator and .clear_X() to proto_to_cpp

R=primiano@google.com

Change-Id: I818e07fd065bd069bee489263b56574a43a861fd
diff --git a/include/perfetto/tracing/core/android_log_config.h b/include/perfetto/tracing/core/android_log_config.h
index 29d41f9..5eaa4ff 100644
--- a/include/perfetto/tracing/core/android_log_config.h
+++ b/include/perfetto/tracing/core/android_log_config.h
@@ -74,6 +74,10 @@
   AndroidLogConfig& operator=(AndroidLogConfig&&);
   AndroidLogConfig(const AndroidLogConfig&);
   AndroidLogConfig& operator=(const AndroidLogConfig&);
+  bool operator==(const AndroidLogConfig&) const;
+  bool operator!=(const AndroidLogConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::AndroidLogConfig&);
@@ -81,6 +85,8 @@
 
   int log_ids_size() const { return static_cast<int>(log_ids_.size()); }
   const std::vector<AndroidLogId>& log_ids() const { return log_ids_; }
+  std::vector<AndroidLogId>* mutable_log_ids() { return &log_ids_; }
+  void clear_log_ids() { log_ids_.clear(); }
   AndroidLogId* add_log_ids() {
     log_ids_.emplace_back();
     return &log_ids_.back();
@@ -91,6 +97,8 @@
 
   int filter_tags_size() const { return static_cast<int>(filter_tags_.size()); }
   const std::vector<std::string>& filter_tags() const { return filter_tags_; }
+  std::vector<std::string>* mutable_filter_tags() { return &filter_tags_; }
+  void clear_filter_tags() { filter_tags_.clear(); }
   std::string* add_filter_tags() {
     filter_tags_.emplace_back();
     return &filter_tags_.back();
diff --git a/include/perfetto/tracing/core/android_power_config.h b/include/perfetto/tracing/core/android_power_config.h
index 9b9220e..6776d1c 100644
--- a/include/perfetto/tracing/core/android_power_config.h
+++ b/include/perfetto/tracing/core/android_power_config.h
@@ -59,6 +59,10 @@
   AndroidPowerConfig& operator=(AndroidPowerConfig&&);
   AndroidPowerConfig(const AndroidPowerConfig&);
   AndroidPowerConfig& operator=(const AndroidPowerConfig&);
+  bool operator==(const AndroidPowerConfig&) const;
+  bool operator!=(const AndroidPowerConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::AndroidPowerConfig&);
@@ -73,6 +77,10 @@
   const std::vector<BatteryCounters>& battery_counters() const {
     return battery_counters_;
   }
+  std::vector<BatteryCounters>* mutable_battery_counters() {
+    return &battery_counters_;
+  }
+  void clear_battery_counters() { battery_counters_.clear(); }
   BatteryCounters* add_battery_counters() {
     battery_counters_.emplace_back();
     return &battery_counters_.back();
diff --git a/include/perfetto/tracing/core/chrome_config.h b/include/perfetto/tracing/core/chrome_config.h
index 2a73a55..1d6c5b7 100644
--- a/include/perfetto/tracing/core/chrome_config.h
+++ b/include/perfetto/tracing/core/chrome_config.h
@@ -52,6 +52,8 @@
   ChromeConfig& operator=(ChromeConfig&&);
   ChromeConfig(const ChromeConfig&);
   ChromeConfig& operator=(const ChromeConfig&);
+  bool operator==(const ChromeConfig&) const;
+  bool operator!=(const ChromeConfig& other) const { return !(*this == other); }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::ChromeConfig&);
diff --git a/include/perfetto/tracing/core/commit_data_request.h b/include/perfetto/tracing/core/commit_data_request.h
index 5adcb3e..7b6278e 100644
--- a/include/perfetto/tracing/core/commit_data_request.h
+++ b/include/perfetto/tracing/core/commit_data_request.h
@@ -57,6 +57,10 @@
     ChunksToMove& operator=(ChunksToMove&&);
     ChunksToMove(const ChunksToMove&);
     ChunksToMove& operator=(const ChunksToMove&);
+    bool operator==(const ChunksToMove&) const;
+    bool operator!=(const ChunksToMove& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::CommitDataRequest_ChunksToMove&);
@@ -91,6 +95,8 @@
       Patch& operator=(Patch&&);
       Patch(const Patch&);
       Patch& operator=(const Patch&);
+      bool operator==(const Patch&) const;
+      bool operator!=(const Patch& other) const { return !(*this == other); }
 
       // Conversion methods from/to the corresponding protobuf types.
       void FromProto(
@@ -122,6 +128,10 @@
     ChunkToPatch& operator=(ChunkToPatch&&);
     ChunkToPatch(const ChunkToPatch&);
     ChunkToPatch& operator=(const ChunkToPatch&);
+    bool operator==(const ChunkToPatch&) const;
+    bool operator!=(const ChunkToPatch& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::CommitDataRequest_ChunkToPatch&);
@@ -138,6 +148,8 @@
 
     int patches_size() const { return static_cast<int>(patches_.size()); }
     const std::vector<Patch>& patches() const { return patches_; }
+    std::vector<Patch>* mutable_patches() { return &patches_; }
+    void clear_patches() { patches_.clear(); }
     Patch* add_patches() {
       patches_.emplace_back();
       return &patches_.back();
@@ -164,6 +176,10 @@
   CommitDataRequest& operator=(CommitDataRequest&&);
   CommitDataRequest(const CommitDataRequest&);
   CommitDataRequest& operator=(const CommitDataRequest&);
+  bool operator==(const CommitDataRequest&) const;
+  bool operator!=(const CommitDataRequest& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::CommitDataRequest&);
@@ -175,6 +191,10 @@
   const std::vector<ChunksToMove>& chunks_to_move() const {
     return chunks_to_move_;
   }
+  std::vector<ChunksToMove>* mutable_chunks_to_move() {
+    return &chunks_to_move_;
+  }
+  void clear_chunks_to_move() { chunks_to_move_.clear(); }
   ChunksToMove* add_chunks_to_move() {
     chunks_to_move_.emplace_back();
     return &chunks_to_move_.back();
@@ -186,6 +206,10 @@
   const std::vector<ChunkToPatch>& chunks_to_patch() const {
     return chunks_to_patch_;
   }
+  std::vector<ChunkToPatch>* mutable_chunks_to_patch() {
+    return &chunks_to_patch_;
+  }
+  void clear_chunks_to_patch() { chunks_to_patch_.clear(); }
   ChunkToPatch* add_chunks_to_patch() {
     chunks_to_patch_.emplace_back();
     return &chunks_to_patch_.back();
diff --git a/include/perfetto/tracing/core/data_source_config.h b/include/perfetto/tracing/core/data_source_config.h
index d3a5ddd..a843f0f 100644
--- a/include/perfetto/tracing/core/data_source_config.h
+++ b/include/perfetto/tracing/core/data_source_config.h
@@ -74,6 +74,10 @@
   DataSourceConfig& operator=(DataSourceConfig&&);
   DataSourceConfig(const DataSourceConfig&);
   DataSourceConfig& operator=(const DataSourceConfig&);
+  bool operator==(const DataSourceConfig&) const;
+  bool operator!=(const DataSourceConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::DataSourceConfig&);
diff --git a/include/perfetto/tracing/core/data_source_descriptor.h b/include/perfetto/tracing/core/data_source_descriptor.h
index dc1e63b..4b9a19d 100644
--- a/include/perfetto/tracing/core/data_source_descriptor.h
+++ b/include/perfetto/tracing/core/data_source_descriptor.h
@@ -52,6 +52,10 @@
   DataSourceDescriptor& operator=(DataSourceDescriptor&&);
   DataSourceDescriptor(const DataSourceDescriptor&);
   DataSourceDescriptor& operator=(const DataSourceDescriptor&);
+  bool operator==(const DataSourceDescriptor&) const;
+  bool operator!=(const DataSourceDescriptor& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::DataSourceDescriptor&);
diff --git a/include/perfetto/tracing/core/ftrace_config.h b/include/perfetto/tracing/core/ftrace_config.h
index 860c168..1b6abb4 100644
--- a/include/perfetto/tracing/core/ftrace_config.h
+++ b/include/perfetto/tracing/core/ftrace_config.h
@@ -52,6 +52,8 @@
   FtraceConfig& operator=(FtraceConfig&&);
   FtraceConfig(const FtraceConfig&);
   FtraceConfig& operator=(const FtraceConfig&);
+  bool operator==(const FtraceConfig&) const;
+  bool operator!=(const FtraceConfig& other) const { return !(*this == other); }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::FtraceConfig&);
@@ -63,6 +65,8 @@
   const std::vector<std::string>& ftrace_events() const {
     return ftrace_events_;
   }
+  std::vector<std::string>* mutable_ftrace_events() { return &ftrace_events_; }
+  void clear_ftrace_events() { ftrace_events_.clear(); }
   std::string* add_ftrace_events() {
     ftrace_events_.emplace_back();
     return &ftrace_events_.back();
@@ -74,6 +78,10 @@
   const std::vector<std::string>& atrace_categories() const {
     return atrace_categories_;
   }
+  std::vector<std::string>* mutable_atrace_categories() {
+    return &atrace_categories_;
+  }
+  void clear_atrace_categories() { atrace_categories_.clear(); }
   std::string* add_atrace_categories() {
     atrace_categories_.emplace_back();
     return &atrace_categories_.back();
@@ -81,6 +89,8 @@
 
   int atrace_apps_size() const { return static_cast<int>(atrace_apps_.size()); }
   const std::vector<std::string>& atrace_apps() const { return atrace_apps_; }
+  std::vector<std::string>* mutable_atrace_apps() { return &atrace_apps_; }
+  void clear_atrace_apps() { atrace_apps_.clear(); }
   std::string* add_atrace_apps() {
     atrace_apps_.emplace_back();
     return &atrace_apps_.back();
diff --git a/include/perfetto/tracing/core/heapprofd_config.h b/include/perfetto/tracing/core/heapprofd_config.h
index 333bd5b..1d4f625 100644
--- a/include/perfetto/tracing/core/heapprofd_config.h
+++ b/include/perfetto/tracing/core/heapprofd_config.h
@@ -55,6 +55,10 @@
     ContinuousDumpConfig& operator=(ContinuousDumpConfig&&);
     ContinuousDumpConfig(const ContinuousDumpConfig&);
     ContinuousDumpConfig& operator=(const ContinuousDumpConfig&);
+    bool operator==(const ContinuousDumpConfig&) const;
+    bool operator!=(const ContinuousDumpConfig& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(
@@ -82,6 +86,10 @@
   HeapprofdConfig& operator=(HeapprofdConfig&&);
   HeapprofdConfig(const HeapprofdConfig&);
   HeapprofdConfig& operator=(const HeapprofdConfig&);
+  bool operator==(const HeapprofdConfig&) const;
+  bool operator!=(const HeapprofdConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::HeapprofdConfig&);
@@ -98,6 +106,10 @@
   const std::vector<std::string>& process_cmdline() const {
     return process_cmdline_;
   }
+  std::vector<std::string>* mutable_process_cmdline() {
+    return &process_cmdline_;
+  }
+  void clear_process_cmdline() { process_cmdline_.clear(); }
   std::string* add_process_cmdline() {
     process_cmdline_.emplace_back();
     return &process_cmdline_.back();
@@ -105,6 +117,8 @@
 
   int pid_size() const { return static_cast<int>(pid_.size()); }
   const std::vector<uint64_t>& pid() const { return pid_; }
+  std::vector<uint64_t>* mutable_pid() { return &pid_; }
+  void clear_pid() { pid_.clear(); }
   uint64_t* add_pid() {
     pid_.emplace_back();
     return &pid_.back();
diff --git a/include/perfetto/tracing/core/inode_file_config.h b/include/perfetto/tracing/core/inode_file_config.h
index 69187b7..ea93568 100644
--- a/include/perfetto/tracing/core/inode_file_config.h
+++ b/include/perfetto/tracing/core/inode_file_config.h
@@ -55,6 +55,10 @@
     MountPointMappingEntry& operator=(MountPointMappingEntry&&);
     MountPointMappingEntry(const MountPointMappingEntry&);
     MountPointMappingEntry& operator=(const MountPointMappingEntry&);
+    bool operator==(const MountPointMappingEntry&) const;
+    bool operator!=(const MountPointMappingEntry& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(
@@ -67,6 +71,8 @@
 
     int scan_roots_size() const { return static_cast<int>(scan_roots_.size()); }
     const std::vector<std::string>& scan_roots() const { return scan_roots_; }
+    std::vector<std::string>* mutable_scan_roots() { return &scan_roots_; }
+    void clear_scan_roots() { scan_roots_.clear(); }
     std::string* add_scan_roots() {
       scan_roots_.emplace_back();
       return &scan_roots_.back();
@@ -87,6 +93,10 @@
   InodeFileConfig& operator=(InodeFileConfig&&);
   InodeFileConfig(const InodeFileConfig&);
   InodeFileConfig& operator=(const InodeFileConfig&);
+  bool operator==(const InodeFileConfig&) const;
+  bool operator!=(const InodeFileConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::InodeFileConfig&);
@@ -110,6 +120,10 @@
   const std::vector<std::string>& scan_mount_points() const {
     return scan_mount_points_;
   }
+  std::vector<std::string>* mutable_scan_mount_points() {
+    return &scan_mount_points_;
+  }
+  void clear_scan_mount_points() { scan_mount_points_.clear(); }
   std::string* add_scan_mount_points() {
     scan_mount_points_.emplace_back();
     return &scan_mount_points_.back();
@@ -121,6 +135,10 @@
   const std::vector<MountPointMappingEntry>& mount_point_mapping() const {
     return mount_point_mapping_;
   }
+  std::vector<MountPointMappingEntry>* mutable_mount_point_mapping() {
+    return &mount_point_mapping_;
+  }
+  void clear_mount_point_mapping() { mount_point_mapping_.clear(); }
   MountPointMappingEntry* add_mount_point_mapping() {
     mount_point_mapping_.emplace_back();
     return &mount_point_mapping_.back();
diff --git a/include/perfetto/tracing/core/process_stats_config.h b/include/perfetto/tracing/core/process_stats_config.h
index 85ff64b..5223b54 100644
--- a/include/perfetto/tracing/core/process_stats_config.h
+++ b/include/perfetto/tracing/core/process_stats_config.h
@@ -57,6 +57,10 @@
   ProcessStatsConfig& operator=(ProcessStatsConfig&&);
   ProcessStatsConfig(const ProcessStatsConfig&);
   ProcessStatsConfig& operator=(const ProcessStatsConfig&);
+  bool operator==(const ProcessStatsConfig&) const;
+  bool operator!=(const ProcessStatsConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::ProcessStatsConfig&);
@@ -64,6 +68,8 @@
 
   int quirks_size() const { return static_cast<int>(quirks_.size()); }
   const std::vector<Quirks>& quirks() const { return quirks_; }
+  std::vector<Quirks>* mutable_quirks() { return &quirks_; }
+  void clear_quirks() { quirks_.clear(); }
   Quirks* add_quirks() {
     quirks_.emplace_back();
     return &quirks_.back();
diff --git a/include/perfetto/tracing/core/sys_stats_config.h b/include/perfetto/tracing/core/sys_stats_config.h
index 700bca0..5e1b0da 100644
--- a/include/perfetto/tracing/core/sys_stats_config.h
+++ b/include/perfetto/tracing/core/sys_stats_config.h
@@ -192,6 +192,10 @@
   SysStatsConfig& operator=(SysStatsConfig&&);
   SysStatsConfig(const SysStatsConfig&);
   SysStatsConfig& operator=(const SysStatsConfig&);
+  bool operator==(const SysStatsConfig&) const;
+  bool operator!=(const SysStatsConfig& other) const {
+    return !(*this == other);
+  }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::SysStatsConfig&);
@@ -206,6 +210,10 @@
   const std::vector<MeminfoCounters>& meminfo_counters() const {
     return meminfo_counters_;
   }
+  std::vector<MeminfoCounters>* mutable_meminfo_counters() {
+    return &meminfo_counters_;
+  }
+  void clear_meminfo_counters() { meminfo_counters_.clear(); }
   MeminfoCounters* add_meminfo_counters() {
     meminfo_counters_.emplace_back();
     return &meminfo_counters_.back();
@@ -220,6 +228,10 @@
   const std::vector<VmstatCounters>& vmstat_counters() const {
     return vmstat_counters_;
   }
+  std::vector<VmstatCounters>* mutable_vmstat_counters() {
+    return &vmstat_counters_;
+  }
+  void clear_vmstat_counters() { vmstat_counters_.clear(); }
   VmstatCounters* add_vmstat_counters() {
     vmstat_counters_.emplace_back();
     return &vmstat_counters_.back();
@@ -234,6 +246,8 @@
   const std::vector<StatCounters>& stat_counters() const {
     return stat_counters_;
   }
+  std::vector<StatCounters>* mutable_stat_counters() { return &stat_counters_; }
+  void clear_stat_counters() { stat_counters_.clear(); }
   StatCounters* add_stat_counters() {
     stat_counters_.emplace_back();
     return &stat_counters_.back();
diff --git a/include/perfetto/tracing/core/test_config.h b/include/perfetto/tracing/core/test_config.h
index c109991..51e02d1 100644
--- a/include/perfetto/tracing/core/test_config.h
+++ b/include/perfetto/tracing/core/test_config.h
@@ -55,6 +55,10 @@
     DummyFields& operator=(DummyFields&&);
     DummyFields(const DummyFields&);
     DummyFields& operator=(const DummyFields&);
+    bool operator==(const DummyFields&) const;
+    bool operator!=(const DummyFields& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TestConfig_DummyFields&);
@@ -132,6 +136,8 @@
   TestConfig& operator=(TestConfig&&);
   TestConfig(const TestConfig&);
   TestConfig& operator=(const TestConfig&);
+  bool operator==(const TestConfig&) const;
+  bool operator!=(const TestConfig& other) const { return !(*this == other); }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::TestConfig&);
diff --git a/include/perfetto/tracing/core/trace_config.h b/include/perfetto/tracing/core/trace_config.h
index 818e026..d730534 100644
--- a/include/perfetto/tracing/core/trace_config.h
+++ b/include/perfetto/tracing/core/trace_config.h
@@ -79,6 +79,10 @@
     BufferConfig& operator=(BufferConfig&&);
     BufferConfig(const BufferConfig&);
     BufferConfig& operator=(const BufferConfig&);
+    bool operator==(const BufferConfig&) const;
+    bool operator!=(const BufferConfig& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TraceConfig_BufferConfig&);
@@ -107,6 +111,8 @@
     DataSource& operator=(DataSource&&);
     DataSource(const DataSource&);
     DataSource& operator=(const DataSource&);
+    bool operator==(const DataSource&) const;
+    bool operator!=(const DataSource& other) const { return !(*this == other); }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TraceConfig_DataSource&);
@@ -121,6 +127,10 @@
     const std::vector<std::string>& producer_name_filter() const {
       return producer_name_filter_;
     }
+    std::vector<std::string>* mutable_producer_name_filter() {
+      return &producer_name_filter_;
+    }
+    void clear_producer_name_filter() { producer_name_filter_.clear(); }
     std::string* add_producer_name_filter() {
       producer_name_filter_.emplace_back();
       return &producer_name_filter_.back();
@@ -149,6 +159,10 @@
     ProducerConfig& operator=(ProducerConfig&&);
     ProducerConfig(const ProducerConfig&);
     ProducerConfig& operator=(const ProducerConfig&);
+    bool operator==(const ProducerConfig&) const;
+    bool operator!=(const ProducerConfig& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TraceConfig_ProducerConfig&);
@@ -181,6 +195,10 @@
     StatsdMetadata& operator=(StatsdMetadata&&);
     StatsdMetadata(const StatsdMetadata&);
     StatsdMetadata& operator=(const StatsdMetadata&);
+    bool operator==(const StatsdMetadata&) const;
+    bool operator!=(const StatsdMetadata& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TraceConfig_StatsdMetadata&);
@@ -227,6 +245,10 @@
     GuardrailOverrides& operator=(GuardrailOverrides&&);
     GuardrailOverrides(const GuardrailOverrides&);
     GuardrailOverrides& operator=(const GuardrailOverrides&);
+    bool operator==(const GuardrailOverrides&) const;
+    bool operator!=(const GuardrailOverrides& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TraceConfig_GuardrailOverrides&);
@@ -253,6 +275,8 @@
   TraceConfig& operator=(TraceConfig&&);
   TraceConfig(const TraceConfig&);
   TraceConfig& operator=(const TraceConfig&);
+  bool operator==(const TraceConfig&) const;
+  bool operator!=(const TraceConfig& other) const { return !(*this == other); }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::TraceConfig&);
@@ -260,6 +284,8 @@
 
   int buffers_size() const { return static_cast<int>(buffers_.size()); }
   const std::vector<BufferConfig>& buffers() const { return buffers_; }
+  std::vector<BufferConfig>* mutable_buffers() { return &buffers_; }
+  void clear_buffers() { buffers_.clear(); }
   BufferConfig* add_buffers() {
     buffers_.emplace_back();
     return &buffers_.back();
@@ -269,6 +295,8 @@
     return static_cast<int>(data_sources_.size());
   }
   const std::vector<DataSource>& data_sources() const { return data_sources_; }
+  std::vector<DataSource>* mutable_data_sources() { return &data_sources_; }
+  void clear_data_sources() { data_sources_.clear(); }
   DataSource* add_data_sources() {
     data_sources_.emplace_back();
     return &data_sources_.back();
@@ -289,6 +317,8 @@
 
   int producers_size() const { return static_cast<int>(producers_.size()); }
   const std::vector<ProducerConfig>& producers() const { return producers_; }
+  std::vector<ProducerConfig>* mutable_producers() { return &producers_; }
+  void clear_producers() { producers_.clear(); }
   ProducerConfig* add_producers() {
     producers_.emplace_back();
     return &producers_.back();
diff --git a/include/perfetto/tracing/core/trace_stats.h b/include/perfetto/tracing/core/trace_stats.h
index a2d897b..8e5949c 100644
--- a/include/perfetto/tracing/core/trace_stats.h
+++ b/include/perfetto/tracing/core/trace_stats.h
@@ -55,6 +55,10 @@
     BufferStats& operator=(BufferStats&&);
     BufferStats(const BufferStats&);
     BufferStats& operator=(const BufferStats&);
+    bool operator==(const BufferStats&) const;
+    bool operator!=(const BufferStats& other) const {
+      return !(*this == other);
+    }
 
     // Conversion methods from/to the corresponding protobuf types.
     void FromProto(const perfetto::protos::TraceStats_BufferStats&);
@@ -155,6 +159,8 @@
   TraceStats& operator=(TraceStats&&);
   TraceStats(const TraceStats&);
   TraceStats& operator=(const TraceStats&);
+  bool operator==(const TraceStats&) const;
+  bool operator!=(const TraceStats& other) const { return !(*this == other); }
 
   // Conversion methods from/to the corresponding protobuf types.
   void FromProto(const perfetto::protos::TraceStats&);
@@ -164,6 +170,8 @@
     return static_cast<int>(buffer_stats_.size());
   }
   const std::vector<BufferStats>& buffer_stats() const { return buffer_stats_; }
+  std::vector<BufferStats>* mutable_buffer_stats() { return &buffer_stats_; }
+  void clear_buffer_stats() { buffer_stats_.clear(); }
   BufferStats* add_buffer_stats() {
     buffer_stats_.emplace_back();
     return &buffer_stats_.back();
diff --git a/src/tracing/core/android_log_config.cc b/src/tracing/core/android_log_config.cc
index 9fa773e..2a4fc63 100644
--- a/src/tracing/core/android_log_config.cc
+++ b/src/tracing/core/android_log_config.cc
@@ -40,6 +40,14 @@
 AndroidLogConfig::AndroidLogConfig(AndroidLogConfig&&) noexcept = default;
 AndroidLogConfig& AndroidLogConfig::operator=(AndroidLogConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool AndroidLogConfig::operator==(const AndroidLogConfig& other) const {
+  return (log_ids_ == other.log_ids_) && (min_prio_ == other.min_prio_) &&
+         (filter_tags_ == other.filter_tags_);
+}
+#pragma GCC diagnostic pop
+
 void AndroidLogConfig::FromProto(
     const perfetto::protos::AndroidLogConfig& proto) {
   log_ids_.clear();
diff --git a/src/tracing/core/android_power_config.cc b/src/tracing/core/android_power_config.cc
index 7368469..c9723da 100644
--- a/src/tracing/core/android_power_config.cc
+++ b/src/tracing/core/android_power_config.cc
@@ -40,6 +40,15 @@
 AndroidPowerConfig& AndroidPowerConfig::operator=(AndroidPowerConfig&&) =
     default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool AndroidPowerConfig::operator==(const AndroidPowerConfig& other) const {
+  return (battery_poll_ms_ == other.battery_poll_ms_) &&
+         (battery_counters_ == other.battery_counters_) &&
+         (collect_power_rails_ == other.collect_power_rails_);
+}
+#pragma GCC diagnostic pop
+
 void AndroidPowerConfig::FromProto(
     const perfetto::protos::AndroidPowerConfig& proto) {
   static_assert(sizeof(battery_poll_ms_) == sizeof(proto.battery_poll_ms()),
diff --git a/src/tracing/core/chrome_config.cc b/src/tracing/core/chrome_config.cc
index 529f861..d6d47fc 100644
--- a/src/tracing/core/chrome_config.cc
+++ b/src/tracing/core/chrome_config.cc
@@ -38,6 +38,13 @@
 ChromeConfig::ChromeConfig(ChromeConfig&&) noexcept = default;
 ChromeConfig& ChromeConfig::operator=(ChromeConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool ChromeConfig::operator==(const ChromeConfig& other) const {
+  return (trace_config_ == other.trace_config_);
+}
+#pragma GCC diagnostic pop
+
 void ChromeConfig::FromProto(const perfetto::protos::ChromeConfig& proto) {
   static_assert(sizeof(trace_config_) == sizeof(proto.trace_config()),
                 "size mismatch");
diff --git a/src/tracing/core/commit_data_request.cc b/src/tracing/core/commit_data_request.cc
index 7a14fdc..9899585 100644
--- a/src/tracing/core/commit_data_request.cc
+++ b/src/tracing/core/commit_data_request.cc
@@ -39,6 +39,15 @@
 CommitDataRequest::CommitDataRequest(CommitDataRequest&&) noexcept = default;
 CommitDataRequest& CommitDataRequest::operator=(CommitDataRequest&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool CommitDataRequest::operator==(const CommitDataRequest& other) const {
+  return (chunks_to_move_ == other.chunks_to_move_) &&
+         (chunks_to_patch_ == other.chunks_to_patch_) &&
+         (flush_request_id_ == other.flush_request_id_);
+}
+#pragma GCC diagnostic pop
+
 void CommitDataRequest::FromProto(
     const perfetto::protos::CommitDataRequest& proto) {
   chunks_to_move_.clear();
@@ -92,6 +101,15 @@
 CommitDataRequest::ChunksToMove& CommitDataRequest::ChunksToMove::operator=(
     CommitDataRequest::ChunksToMove&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool CommitDataRequest::ChunksToMove::operator==(
+    const CommitDataRequest::ChunksToMove& other) const {
+  return (page_ == other.page_) && (chunk_ == other.chunk_) &&
+         (target_buffer_ == other.target_buffer_);
+}
+#pragma GCC diagnostic pop
+
 void CommitDataRequest::ChunksToMove::FromProto(
     const perfetto::protos::CommitDataRequest_ChunksToMove& proto) {
   static_assert(sizeof(page_) == sizeof(proto.page()), "size mismatch");
@@ -134,6 +152,17 @@
 CommitDataRequest::ChunkToPatch& CommitDataRequest::ChunkToPatch::operator=(
     CommitDataRequest::ChunkToPatch&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool CommitDataRequest::ChunkToPatch::operator==(
+    const CommitDataRequest::ChunkToPatch& other) const {
+  return (target_buffer_ == other.target_buffer_) &&
+         (writer_id_ == other.writer_id_) && (chunk_id_ == other.chunk_id_) &&
+         (patches_ == other.patches_) &&
+         (has_more_patches_ == other.has_more_patches_);
+}
+#pragma GCC diagnostic pop
+
 void CommitDataRequest::ChunkToPatch::FromProto(
     const perfetto::protos::CommitDataRequest_ChunkToPatch& proto) {
   static_assert(sizeof(target_buffer_) == sizeof(proto.target_buffer()),
@@ -200,6 +229,14 @@
 CommitDataRequest::ChunkToPatch::Patch& CommitDataRequest::ChunkToPatch::Patch::
 operator=(CommitDataRequest::ChunkToPatch::Patch&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool CommitDataRequest::ChunkToPatch::Patch::operator==(
+    const CommitDataRequest::ChunkToPatch::Patch& other) const {
+  return (offset_ == other.offset_) && (data_ == other.data_);
+}
+#pragma GCC diagnostic pop
+
 void CommitDataRequest::ChunkToPatch::Patch::FromProto(
     const perfetto::protos::CommitDataRequest_ChunkToPatch_Patch& proto) {
   static_assert(sizeof(offset_) == sizeof(proto.offset()), "size mismatch");
diff --git a/src/tracing/core/data_source_config.cc b/src/tracing/core/data_source_config.cc
index b5eee78..2990aec 100644
--- a/src/tracing/core/data_source_config.cc
+++ b/src/tracing/core/data_source_config.cc
@@ -48,6 +48,25 @@
 DataSourceConfig::DataSourceConfig(DataSourceConfig&&) noexcept = default;
 DataSourceConfig& DataSourceConfig::operator=(DataSourceConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool DataSourceConfig::operator==(const DataSourceConfig& other) const {
+  return (name_ == other.name_) && (target_buffer_ == other.target_buffer_) &&
+         (trace_duration_ms_ == other.trace_duration_ms_) &&
+         (tracing_session_id_ == other.tracing_session_id_) &&
+         (ftrace_config_ == other.ftrace_config_) &&
+         (chrome_config_ == other.chrome_config_) &&
+         (inode_file_config_ == other.inode_file_config_) &&
+         (process_stats_config_ == other.process_stats_config_) &&
+         (sys_stats_config_ == other.sys_stats_config_) &&
+         (heapprofd_config_ == other.heapprofd_config_) &&
+         (android_power_config_ == other.android_power_config_) &&
+         (android_log_config_ == other.android_log_config_) &&
+         (legacy_config_ == other.legacy_config_) &&
+         (for_testing_ == other.for_testing_);
+}
+#pragma GCC diagnostic pop
+
 void DataSourceConfig::FromProto(
     const perfetto::protos::DataSourceConfig& proto) {
   static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
diff --git a/src/tracing/core/data_source_descriptor.cc b/src/tracing/core/data_source_descriptor.cc
index ebb2737..945df83 100644
--- a/src/tracing/core/data_source_descriptor.cc
+++ b/src/tracing/core/data_source_descriptor.cc
@@ -42,6 +42,14 @@
 DataSourceDescriptor& DataSourceDescriptor::operator=(DataSourceDescriptor&&) =
     default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool DataSourceDescriptor::operator==(const DataSourceDescriptor& other) const {
+  return (name_ == other.name_) &&
+         (will_notify_on_stop_ == other.will_notify_on_stop_);
+}
+#pragma GCC diagnostic pop
+
 void DataSourceDescriptor::FromProto(
     const perfetto::protos::DataSourceDescriptor& proto) {
   static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
diff --git a/src/tracing/core/ftrace_config.cc b/src/tracing/core/ftrace_config.cc
index d7e5f03..532f2f3 100644
--- a/src/tracing/core/ftrace_config.cc
+++ b/src/tracing/core/ftrace_config.cc
@@ -38,6 +38,17 @@
 FtraceConfig::FtraceConfig(FtraceConfig&&) noexcept = default;
 FtraceConfig& FtraceConfig::operator=(FtraceConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool FtraceConfig::operator==(const FtraceConfig& other) const {
+  return (ftrace_events_ == other.ftrace_events_) &&
+         (atrace_categories_ == other.atrace_categories_) &&
+         (atrace_apps_ == other.atrace_apps_) &&
+         (buffer_size_kb_ == other.buffer_size_kb_) &&
+         (drain_period_ms_ == other.drain_period_ms_);
+}
+#pragma GCC diagnostic pop
+
 void FtraceConfig::FromProto(const perfetto::protos::FtraceConfig& proto) {
   ftrace_events_.clear();
   for (const auto& field : proto.ftrace_events()) {
diff --git a/src/tracing/core/heapprofd_config.cc b/src/tracing/core/heapprofd_config.cc
index 0a57482..e85bfdc 100644
--- a/src/tracing/core/heapprofd_config.cc
+++ b/src/tracing/core/heapprofd_config.cc
@@ -38,6 +38,16 @@
 HeapprofdConfig::HeapprofdConfig(HeapprofdConfig&&) noexcept = default;
 HeapprofdConfig& HeapprofdConfig::operator=(HeapprofdConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool HeapprofdConfig::operator==(const HeapprofdConfig& other) const {
+  return (sampling_interval_bytes_ == other.sampling_interval_bytes_) &&
+         (process_cmdline_ == other.process_cmdline_) && (pid_ == other.pid_) &&
+         (all_ == other.all_) &&
+         (continuous_dump_config_ == other.continuous_dump_config_);
+}
+#pragma GCC diagnostic pop
+
 void HeapprofdConfig::FromProto(
     const perfetto::protos::HeapprofdConfig& proto) {
   static_assert(sizeof(sampling_interval_bytes_) ==
@@ -110,6 +120,15 @@
 HeapprofdConfig::ContinuousDumpConfig& HeapprofdConfig::ContinuousDumpConfig::
 operator=(HeapprofdConfig::ContinuousDumpConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool HeapprofdConfig::ContinuousDumpConfig::operator==(
+    const HeapprofdConfig::ContinuousDumpConfig& other) const {
+  return (dump_phase_ms_ == other.dump_phase_ms_) &&
+         (dump_interval_ms_ == other.dump_interval_ms_);
+}
+#pragma GCC diagnostic pop
+
 void HeapprofdConfig::ContinuousDumpConfig::FromProto(
     const perfetto::protos::HeapprofdConfig_ContinuousDumpConfig& proto) {
   static_assert(sizeof(dump_phase_ms_) == sizeof(proto.dump_phase_ms()),
diff --git a/src/tracing/core/inode_file_config.cc b/src/tracing/core/inode_file_config.cc
index 44f65b1..44e3439 100644
--- a/src/tracing/core/inode_file_config.cc
+++ b/src/tracing/core/inode_file_config.cc
@@ -38,6 +38,18 @@
 InodeFileConfig::InodeFileConfig(InodeFileConfig&&) noexcept = default;
 InodeFileConfig& InodeFileConfig::operator=(InodeFileConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool InodeFileConfig::operator==(const InodeFileConfig& other) const {
+  return (scan_interval_ms_ == other.scan_interval_ms_) &&
+         (scan_delay_ms_ == other.scan_delay_ms_) &&
+         (scan_batch_size_ == other.scan_batch_size_) &&
+         (do_not_scan_ == other.do_not_scan_) &&
+         (scan_mount_points_ == other.scan_mount_points_) &&
+         (mount_point_mapping_ == other.mount_point_mapping_);
+}
+#pragma GCC diagnostic pop
+
 void InodeFileConfig::FromProto(
     const perfetto::protos::InodeFileConfig& proto) {
   static_assert(sizeof(scan_interval_ms_) == sizeof(proto.scan_interval_ms()),
@@ -126,6 +138,15 @@
 InodeFileConfig::MountPointMappingEntry::operator=(
     InodeFileConfig::MountPointMappingEntry&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool InodeFileConfig::MountPointMappingEntry::operator==(
+    const InodeFileConfig::MountPointMappingEntry& other) const {
+  return (mountpoint_ == other.mountpoint_) &&
+         (scan_roots_ == other.scan_roots_);
+}
+#pragma GCC diagnostic pop
+
 void InodeFileConfig::MountPointMappingEntry::FromProto(
     const perfetto::protos::InodeFileConfig_MountPointMappingEntry& proto) {
   static_assert(sizeof(mountpoint_) == sizeof(proto.mountpoint()),
diff --git a/src/tracing/core/process_stats_config.cc b/src/tracing/core/process_stats_config.cc
index 4904f33..be66e07 100644
--- a/src/tracing/core/process_stats_config.cc
+++ b/src/tracing/core/process_stats_config.cc
@@ -40,6 +40,16 @@
 ProcessStatsConfig& ProcessStatsConfig::operator=(ProcessStatsConfig&&) =
     default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool ProcessStatsConfig::operator==(const ProcessStatsConfig& other) const {
+  return (quirks_ == other.quirks_) &&
+         (scan_all_processes_on_start_ == other.scan_all_processes_on_start_) &&
+         (record_thread_names_ == other.record_thread_names_) &&
+         (proc_stats_poll_ms_ == other.proc_stats_poll_ms_);
+}
+#pragma GCC diagnostic pop
+
 void ProcessStatsConfig::FromProto(
     const perfetto::protos::ProcessStatsConfig& proto) {
   quirks_.clear();
diff --git a/src/tracing/core/sys_stats_config.cc b/src/tracing/core/sys_stats_config.cc
index 3027409..700fdcf 100644
--- a/src/tracing/core/sys_stats_config.cc
+++ b/src/tracing/core/sys_stats_config.cc
@@ -39,6 +39,18 @@
 SysStatsConfig::SysStatsConfig(SysStatsConfig&&) noexcept = default;
 SysStatsConfig& SysStatsConfig::operator=(SysStatsConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool SysStatsConfig::operator==(const SysStatsConfig& other) const {
+  return (meminfo_period_ms_ == other.meminfo_period_ms_) &&
+         (meminfo_counters_ == other.meminfo_counters_) &&
+         (vmstat_period_ms_ == other.vmstat_period_ms_) &&
+         (vmstat_counters_ == other.vmstat_counters_) &&
+         (stat_period_ms_ == other.stat_period_ms_) &&
+         (stat_counters_ == other.stat_counters_);
+}
+#pragma GCC diagnostic pop
+
 void SysStatsConfig::FromProto(const perfetto::protos::SysStatsConfig& proto) {
   static_assert(sizeof(meminfo_period_ms_) == sizeof(proto.meminfo_period_ms()),
                 "size mismatch");
diff --git a/src/tracing/core/test_config.cc b/src/tracing/core/test_config.cc
index 8797261..582128a 100644
--- a/src/tracing/core/test_config.cc
+++ b/src/tracing/core/test_config.cc
@@ -38,6 +38,17 @@
 TestConfig::TestConfig(TestConfig&&) noexcept = default;
 TestConfig& TestConfig::operator=(TestConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TestConfig::operator==(const TestConfig& other) const {
+  return (message_count_ == other.message_count_) &&
+         (max_messages_per_second_ == other.max_messages_per_second_) &&
+         (seed_ == other.seed_) && (message_size_ == other.message_size_) &&
+         (send_batch_on_register_ == other.send_batch_on_register_) &&
+         (dummy_fields_ == other.dummy_fields_);
+}
+#pragma GCC diagnostic pop
+
 void TestConfig::FromProto(const perfetto::protos::TestConfig& proto) {
   static_assert(sizeof(message_count_) == sizeof(proto.message_count()),
                 "size mismatch");
@@ -110,6 +121,27 @@
 TestConfig::DummyFields& TestConfig::DummyFields::operator=(
     TestConfig::DummyFields&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TestConfig::DummyFields::operator==(
+    const TestConfig::DummyFields& other) const {
+  return (field_uint32_ == other.field_uint32_) &&
+         (field_int32_ == other.field_int32_) &&
+         (field_uint64_ == other.field_uint64_) &&
+         (field_int64_ == other.field_int64_) &&
+         (field_fixed64_ == other.field_fixed64_) &&
+         (field_sfixed64_ == other.field_sfixed64_) &&
+         (field_fixed32_ == other.field_fixed32_) &&
+         (field_sfixed32_ == other.field_sfixed32_) &&
+         (field_double_ == other.field_double_) &&
+         (field_float_ == other.field_float_) &&
+         (field_sint64_ == other.field_sint64_) &&
+         (field_sint32_ == other.field_sint32_) &&
+         (field_string_ == other.field_string_) &&
+         (field_bytes_ == other.field_bytes_);
+}
+#pragma GCC diagnostic pop
+
 void TestConfig::DummyFields::FromProto(
     const perfetto::protos::TestConfig_DummyFields& proto) {
   static_assert(sizeof(field_uint32_) == sizeof(proto.field_uint32()),
diff --git a/src/tracing/core/trace_config.cc b/src/tracing/core/trace_config.cc
index 3f1d5f6..3d8c8f2 100644
--- a/src/tracing/core/trace_config.cc
+++ b/src/tracing/core/trace_config.cc
@@ -39,6 +39,28 @@
 TraceConfig::TraceConfig(TraceConfig&&) noexcept = default;
 TraceConfig& TraceConfig::operator=(TraceConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceConfig::operator==(const TraceConfig& other) const {
+  return (buffers_ == other.buffers_) &&
+         (data_sources_ == other.data_sources_) &&
+         (duration_ms_ == other.duration_ms_) &&
+         (enable_extra_guardrails_ == other.enable_extra_guardrails_) &&
+         (lockdown_mode_ == other.lockdown_mode_) &&
+         (producers_ == other.producers_) &&
+         (statsd_metadata_ == other.statsd_metadata_) &&
+         (write_into_file_ == other.write_into_file_) &&
+         (file_write_period_ms_ == other.file_write_period_ms_) &&
+         (max_file_size_bytes_ == other.max_file_size_bytes_) &&
+         (guardrail_overrides_ == other.guardrail_overrides_) &&
+         (deferred_start_ == other.deferred_start_) &&
+         (flush_period_ms_ == other.flush_period_ms_) &&
+         (flush_timeout_ms_ == other.flush_timeout_ms_) &&
+         (disable_clock_snapshotting_ == other.disable_clock_snapshotting_) &&
+         (notify_traceur_ == other.notify_traceur_);
+}
+#pragma GCC diagnostic pop
+
 void TraceConfig::FromProto(const perfetto::protos::TraceConfig& proto) {
   buffers_.clear();
   for (const auto& field : proto.buffers()) {
@@ -220,6 +242,14 @@
 TraceConfig::BufferConfig& TraceConfig::BufferConfig::operator=(
     TraceConfig::BufferConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceConfig::BufferConfig::operator==(
+    const TraceConfig::BufferConfig& other) const {
+  return (size_kb_ == other.size_kb_) && (fill_policy_ == other.fill_policy_);
+}
+#pragma GCC diagnostic pop
+
 void TraceConfig::BufferConfig::FromProto(
     const perfetto::protos::TraceConfig_BufferConfig& proto) {
   static_assert(sizeof(size_kb_) == sizeof(proto.size_kb()), "size mismatch");
@@ -255,6 +285,15 @@
 TraceConfig::DataSource& TraceConfig::DataSource::operator=(
     TraceConfig::DataSource&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceConfig::DataSource::operator==(
+    const TraceConfig::DataSource& other) const {
+  return (config_ == other.config_) &&
+         (producer_name_filter_ == other.producer_name_filter_);
+}
+#pragma GCC diagnostic pop
+
 void TraceConfig::DataSource::FromProto(
     const perfetto::protos::TraceConfig_DataSource& proto) {
   config_.FromProto(proto.config());
@@ -297,6 +336,16 @@
 TraceConfig::ProducerConfig& TraceConfig::ProducerConfig::operator=(
     TraceConfig::ProducerConfig&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceConfig::ProducerConfig::operator==(
+    const TraceConfig::ProducerConfig& other) const {
+  return (producer_name_ == other.producer_name_) &&
+         (shm_size_kb_ == other.shm_size_kb_) &&
+         (page_size_kb_ == other.page_size_kb_);
+}
+#pragma GCC diagnostic pop
+
 void TraceConfig::ProducerConfig::FromProto(
     const perfetto::protos::TraceConfig_ProducerConfig& proto) {
   static_assert(sizeof(producer_name_) == sizeof(proto.producer_name()),
@@ -345,6 +394,17 @@
 TraceConfig::StatsdMetadata& TraceConfig::StatsdMetadata::operator=(
     TraceConfig::StatsdMetadata&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceConfig::StatsdMetadata::operator==(
+    const TraceConfig::StatsdMetadata& other) const {
+  return (triggering_alert_id_ == other.triggering_alert_id_) &&
+         (triggering_config_uid_ == other.triggering_config_uid_) &&
+         (triggering_config_id_ == other.triggering_config_id_) &&
+         (triggering_subscription_id_ == other.triggering_subscription_id_);
+}
+#pragma GCC diagnostic pop
+
 void TraceConfig::StatsdMetadata::FromProto(
     const perfetto::protos::TraceConfig_StatsdMetadata& proto) {
   static_assert(
@@ -419,6 +479,14 @@
 TraceConfig::GuardrailOverrides& TraceConfig::GuardrailOverrides::operator=(
     TraceConfig::GuardrailOverrides&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceConfig::GuardrailOverrides::operator==(
+    const TraceConfig::GuardrailOverrides& other) const {
+  return (max_upload_per_day_bytes_ == other.max_upload_per_day_bytes_);
+}
+#pragma GCC diagnostic pop
+
 void TraceConfig::GuardrailOverrides::FromProto(
     const perfetto::protos::TraceConfig_GuardrailOverrides& proto) {
   static_assert(sizeof(max_upload_per_day_bytes_) ==
diff --git a/src/tracing/core/trace_stats.cc b/src/tracing/core/trace_stats.cc
index f71d217..74de5b5 100644
--- a/src/tracing/core/trace_stats.cc
+++ b/src/tracing/core/trace_stats.cc
@@ -38,6 +38,21 @@
 TraceStats::TraceStats(TraceStats&&) noexcept = default;
 TraceStats& TraceStats::operator=(TraceStats&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceStats::operator==(const TraceStats& other) const {
+  return (buffer_stats_ == other.buffer_stats_) &&
+         (producers_connected_ == other.producers_connected_) &&
+         (producers_seen_ == other.producers_seen_) &&
+         (data_sources_registered_ == other.data_sources_registered_) &&
+         (data_sources_seen_ == other.data_sources_seen_) &&
+         (tracing_sessions_ == other.tracing_sessions_) &&
+         (total_buffers_ == other.total_buffers_) &&
+         (chunks_discarded_ == other.chunks_discarded_) &&
+         (patches_discarded_ == other.patches_discarded_);
+}
+#pragma GCC diagnostic pop
+
 void TraceStats::FromProto(const perfetto::protos::TraceStats& proto) {
   buffer_stats_.clear();
   for (const auto& field : proto.buffer_stats()) {
@@ -154,6 +169,32 @@
 TraceStats::BufferStats& TraceStats::BufferStats::operator=(
     TraceStats::BufferStats&&) = default;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TraceStats::BufferStats::operator==(
+    const TraceStats::BufferStats& other) const {
+  return (buffer_size_ == other.buffer_size_) &&
+         (bytes_written_ == other.bytes_written_) &&
+         (bytes_overwritten_ == other.bytes_overwritten_) &&
+         (bytes_read_ == other.bytes_read_) &&
+         (padding_bytes_written_ == other.padding_bytes_written_) &&
+         (padding_bytes_cleared_ == other.padding_bytes_cleared_) &&
+         (chunks_written_ == other.chunks_written_) &&
+         (chunks_rewritten_ == other.chunks_rewritten_) &&
+         (chunks_overwritten_ == other.chunks_overwritten_) &&
+         (chunks_discarded_ == other.chunks_discarded_) &&
+         (chunks_read_ == other.chunks_read_) &&
+         (chunks_committed_out_of_order_ ==
+          other.chunks_committed_out_of_order_) &&
+         (write_wrap_count_ == other.write_wrap_count_) &&
+         (patches_succeeded_ == other.patches_succeeded_) &&
+         (patches_failed_ == other.patches_failed_) &&
+         (readaheads_succeeded_ == other.readaheads_succeeded_) &&
+         (readaheads_failed_ == other.readaheads_failed_) &&
+         (abi_violations_ == other.abi_violations_);
+}
+#pragma GCC diagnostic pop
+
 void TraceStats::BufferStats::FromProto(
     const perfetto::protos::TraceStats_BufferStats& proto) {
   static_assert(sizeof(buffer_size_) == sizeof(proto.buffer_size()),
diff --git a/tools/proto_to_cpp/proto_to_cpp.cc b/tools/proto_to_cpp/proto_to_cpp.cc
index 1dcc75c..52e85c3 100644
--- a/tools/proto_to_cpp/proto_to_cpp.cc
+++ b/tools/proto_to_cpp/proto_to_cpp.cc
@@ -309,6 +309,10 @@
   p->Print("$n$& operator=($n$&&);\n", "n", msg->name());
   p->Print("$n$(const $n$&);\n", "n", msg->name());
   p->Print("$n$& operator=(const $n$&);\n", "n", msg->name());
+  p->Print("bool operator==(const $n$&) const;\n", "n", msg->name());
+  p->Print(
+      "bool operator!=(const $n$& other) const { return !(*this == other); }\n",
+      "n", msg->name());
   p->Print("\n");
 
   std::string proto_type = GetFwdDeclType(msg, true);
@@ -342,6 +346,10 @@
           "t", GetCppType(field, false), "n", field->lowercase_name());
       p->Print("const std::vector<$t$>& $n$() const { return $n$_; }\n", "t",
                GetCppType(field, false), "n", field->lowercase_name());
+      p->Print("std::vector<$t$>* mutable_$n$() { return &$n$_; }\n", "t",
+               GetCppType(field, false), "n", field->lowercase_name());
+      p->Print("void clear_$n$() { $n$_.clear(); }\n", "n",
+               field->lowercase_name());
       p->Print("$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); }\n",
                "t", GetCppType(field, false), "n", field->lowercase_name());
     }
@@ -385,6 +393,25 @@
 
   p->Print("\n");
 
+  // Comparison operator
+  p->Print("#pragma GCC diagnostic push\n");
+  p->Print("#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n");
+  p->Print("bool $f$::operator==(const $f$& other) const {\n", "f", full_name,
+           "n", msg->name());
+  p->Indent();
+
+  p->Print("return ");
+  for (int i = 0; i < msg->field_count(); i++) {
+    if (i > 0)
+      p->Print("\n && ");
+    const FieldDescriptor* field = msg->field(i);
+    p->Print("($n$_ == other.$n$_)", "n", field->name());
+  }
+  p->Print(";");
+  p->Outdent();
+  p->Print("}\n");
+  p->Print("#pragma GCC diagnostic pop\n\n");
+
   std::string proto_type = GetFwdDeclType(msg, true);
 
   // Genrate the FromProto() method definition.