tp: multi-machine: insert machine ID to storage tables

This CL retrieves machine_id from TraceProcessorContext for storage
table insertion by trackers (ProcessTracker, TrackTracker, etc.).

The ProcessTracker is updated to use the inserted row number as the
utid/upid of the swapper thread, as the assumption that swapper's
utid/upid is 0 will not hold in injesting a multi-machine trace data
file.

Bug: 284258446

Change-Id: I68e0989df9762dd6d2a4807a75b8b51b73e9f85c
diff --git a/Android.bp b/Android.bp
index 585df73..85ca01c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11410,6 +11410,7 @@
         "src/trace_processor/importers/common/flow_tracker.cc",
         "src/trace_processor/importers/common/global_args_tracker.cc",
         "src/trace_processor/importers/common/jit_cache.cc",
+        "src/trace_processor/importers/common/machine_tracker.cc",
         "src/trace_processor/importers/common/mapping_tracker.cc",
         "src/trace_processor/importers/common/metadata_tracker.cc",
         "src/trace_processor/importers/common/process_tracker.cc",
diff --git a/BUILD b/BUILD
index d678720..278a9a0 100644
--- a/BUILD
+++ b/BUILD
@@ -1477,6 +1477,8 @@
         "src/trace_processor/importers/common/global_args_tracker.h",
         "src/trace_processor/importers/common/jit_cache.cc",
         "src/trace_processor/importers/common/jit_cache.h",
+        "src/trace_processor/importers/common/machine_tracker.cc",
+        "src/trace_processor/importers/common/machine_tracker.h",
         "src/trace_processor/importers/common/mapping_tracker.cc",
         "src/trace_processor/importers/common/mapping_tracker.h",
         "src/trace_processor/importers/common/metadata_tracker.cc",
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index c3ba78a..43dfb23 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -39,6 +39,8 @@
     "global_args_tracker.h",
     "jit_cache.cc",
     "jit_cache.h",
+    "machine_tracker.cc",
+    "machine_tracker.h",
     "mapping_tracker.cc",
     "mapping_tracker.h",
     "metadata_tracker.cc",
diff --git a/src/trace_processor/importers/common/event_tracker.cc b/src/trace_processor/importers/common/event_tracker.cc
index 0ed799b..43cf710 100644
--- a/src/trace_processor/importers/common/event_tracker.cc
+++ b/src/trace_processor/importers/common/event_tracker.cc
@@ -65,7 +65,9 @@
   max_timestamp_ = timestamp;
 
   auto* counter_values = context_->storage->mutable_counter_table();
-  return counter_values->Insert({timestamp, track_id, value}).id;
+  return counter_values
+      ->Insert({timestamp, track_id, value, {}, context_->machine_id()})
+      .id;
 }
 
 std::optional<CounterId> EventTracker::PushCounter(
diff --git a/src/trace_processor/importers/common/machine_tracker.cc b/src/trace_processor/importers/common/machine_tracker.cc
new file mode 100644
index 0000000..26e8d4a
--- /dev/null
+++ b/src/trace_processor/importers/common/machine_tracker.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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 "src/trace_processor/importers/common/machine_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto::trace_processor {
+
+MachineTracker::MachineTracker(TraceProcessorContext* context,
+                               uint32_t raw_machine_id)
+    : context_(context) {
+  auto id =
+      context_->storage->mutable_machine_table()->Insert({raw_machine_id}).id;
+
+  if (raw_machine_id)
+    machine_id_ = id;
+}
+MachineTracker::~MachineTracker() = default;
+
+}  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/common/machine_tracker.h b/src/trace_processor/importers/common/machine_tracker.h
new file mode 100644
index 0000000..1909311
--- /dev/null
+++ b/src/trace_processor/importers/common/machine_tracker.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MACHINE_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MACHINE_TRACKER_H_
+
+#include <cstdint>
+
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto::trace_processor {
+
+// Tracks information in the machine table.
+class MachineTracker {
+ public:
+  MachineTracker(TraceProcessorContext* contex, uint32_t raw_machine_id);
+  ~MachineTracker();
+
+  std::optional<MachineId> machine_id() const { return machine_id_; }
+
+ private:
+  std::optional<MachineId> machine_id_;
+  TraceProcessorContext* const context_;
+};
+
+}  // namespace perfetto::trace_processor
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MACHINE_TRACKER_H_
diff --git a/src/trace_processor/importers/common/process_tracker.cc b/src/trace_processor/importers/common/process_tracker.cc
index 473c48e..910cc25 100644
--- a/src/trace_processor/importers/common/process_tracker.cc
+++ b/src/trace_processor/importers/common/process_tracker.cc
@@ -32,15 +32,25 @@
   // tid0/pid0 to utid0/upid0. If other types of traces refer to tid0/pid0,
   // then they will get their own non-zero utid/upid, so that those threads are
   // still surfaced in embedder UIs.
-  tables::ThreadTable::Row thread_row;
-  thread_row.tid = 0u;
-  thread_row.upid = 0u;
-  thread_row.is_main_thread = true;
-  context_->storage->mutable_thread_table()->Insert(thread_row);
-
+  //
+  // Note on multi-machine tracing: utid/upid of the swapper process of
+  // secondary machine will not be 0. The ProcessTracker needs to insert to the
+  // thread and process tables to reserve utid and upid.
   tables::ProcessTable::Row process_row;
   process_row.pid = 0u;
-  context_->storage->mutable_process_table()->Insert(process_row);
+  process_row.machine_id = context_->machine_id();
+  auto upid =
+      context_->storage->mutable_process_table()->Insert(process_row).row;
+
+  tables::ThreadTable::Row thread_row;
+  thread_row.tid = 0u;
+  thread_row.upid = upid;  // The swapper upid may be != 0 for remote machines.
+  thread_row.is_main_thread = true;
+  thread_row.machine_id = context_->machine_id();
+  auto utid = context_->storage->mutable_thread_table()->Insert(thread_row).row;
+
+  swapper_upid_ = upid;
+  swapper_utid_ = utid;
 
   // An element to match the reserved tid = 0.
   thread_name_priorities_.push_back(ThreadNamePriority::kOther);
@@ -53,12 +63,20 @@
   tables::ThreadTable::Row row;
   row.tid = tid;
   row.start_ts = timestamp;
+  row.machine_id = context_->machine_id();
 
   auto* thread_table = context_->storage->mutable_thread_table();
   UniqueTid new_utid = thread_table->Insert(row).row;
   tids_[tid].emplace_back(new_utid);
-  PERFETTO_DCHECK(thread_name_priorities_.size() == new_utid);
-  thread_name_priorities_.push_back(ThreadNamePriority::kOther);
+
+  if (PERFETTO_UNLIKELY(thread_name_priorities_.size() <= new_utid)) {
+    // This condition can happen in a multi-machine tracing session:
+    // Machine 1 gets utid 0, 1
+    // Machine 2 gets utid 2, 3
+    // Machine 1 gets utid 4: where thread_name_priorities_.size() == 2.
+    thread_name_priorities_.resize(new_utid + 1);
+  }
+  thread_name_priorities_[new_utid] = ThreadNamePriority::kOther;
   return new_utid;
 }
 
@@ -107,7 +125,8 @@
 
   // Ensure that the tid matches the tid we were looking for.
   PERFETTO_DCHECK(threads->tid()[utid] == tid);
-
+  // Ensure that the thread's machine ID matches the context's machine ID.
+  PERFETTO_DCHECK(threads->machine_id()[utid] == context_->machine_id());
   // If the thread is being tracked by the process tracker, it should not be
   // known to have ended.
   PERFETTO_DCHECK(!threads->end_ts()[utid].has_value());
@@ -135,6 +154,13 @@
     return;
 
   auto* thread_table = context_->storage->mutable_thread_table();
+  if (PERFETTO_UNLIKELY(thread_name_priorities_.size() <= utid)) {
+    // This condition can happen in a multi-machine tracing session:
+    // Machine 1 gets utid 0, 1
+    // Machine 2 gets utid 2, 3
+    // Machine 1 gets utid 4: where thread_name_priorities_.size() == 2.
+    thread_name_priorities_.resize(utid + 1);
+  }
   if (priority >= thread_name_priorities_[utid]) {
     thread_table->mutable_name()->Set(utid, thread_name_id);
     thread_name_priorities_[utid] = priority;
@@ -214,6 +240,8 @@
   // If no matching thread was found, create a new one.
   UniqueTid utid = opt_utid ? *opt_utid : StartNewThread(std::nullopt, tid);
   PERFETTO_DCHECK(thread_table->tid()[utid] == tid);
+  // Ensure that the thread's machine ID matches the context's machine ID.
+  PERFETTO_DCHECK(thread_table->machine_id()[utid] == context_->machine_id());
 
   // Find matching process or create new one.
   if (!thread_table->upid()[utid].has_value()) {
@@ -383,6 +411,7 @@
 
   tables::ProcessTable::Row row;
   row.pid = pid;
+  row.machine_id = context_->machine_id();
 
   UniquePid upid = process_table->Insert(row).row;
   *it_and_ins.first = upid;  // Update the newly inserted hashmap entry.
@@ -507,11 +536,13 @@
 }
 
 void ProcessTracker::SetPidZeroIsUpidZeroIdleProcess() {
-  // Create a mapping from (t|p)id 0 -> u(t|p)id 0 for the idle process.
-  tids_.Insert(0, std::vector<UniqueTid>{0});
-  pids_.Insert(0, UniquePid{0});
-
   auto swapper_id = context_->storage->InternString("swapper");
+
+  // Create a mapping from (t|p)id 0 -> u(t|p)id for the idle process.
+  tids_.Insert(0, std::vector<UniqueTid>{swapper_utid_});
+  pids_.Insert(0, swapper_upid_);
+
+  // Use null StringId for the swapper process/thread.
   UpdateThreadName(0, swapper_id, ThreadNamePriority::kTraceProcessorConstant);
 }
 
diff --git a/src/trace_processor/importers/common/process_tracker.h b/src/trace_processor/importers/common/process_tracker.h
index df648c2..3808f99 100644
--- a/src/trace_processor/importers/common/process_tracker.h
+++ b/src/trace_processor/importers/common/process_tracker.h
@@ -189,6 +189,10 @@
                               uint32_t tid,
                               std::vector<uint32_t> nstid);
 
+  // The UniqueTid of the swapper thread, is 0 for the default machine and is
+  // > 0 for remote machines.
+  UniqueTid swapper_utid() const { return swapper_utid_; }
+
  private:
   // Returns the utid of a thread having |tid| and |pid| as the parent process.
   // pid == std::nullopt matches all processes.
@@ -253,6 +257,9 @@
   // Keeps track pid-namespaced processes, keyed by root-level pids.
   std::unordered_map<uint32_t /* pid (aka tgid) */, NamespacedProcess>
       namespaced_processes_;
+
+  UniquePid swapper_upid_ = 0;
+  UniqueTid swapper_utid_ = 0;
 };
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/common/sched_event_tracker.h b/src/trace_processor/importers/common/sched_event_tracker.h
index 3eba6ae..12aa4c0 100644
--- a/src/trace_processor/importers/common/sched_event_tracker.h
+++ b/src/trace_processor/importers/common/sched_event_tracker.h
@@ -45,8 +45,9 @@
     // just switched to. Set the duration to -1, to indicate that the event is
     // not finished. Duration will be updated later after event finish.
     auto* sched = context_->storage->mutable_sched_slice_table();
-    auto row_and_id = sched->Insert(
-        {ts, /* duration */ -1, cpu, next_utid, kNullStringId, next_prio});
+    auto row_and_id =
+        sched->Insert({ts, /* duration */ -1, cpu, next_utid, kNullStringId,
+                       next_prio, context_->machine_id()});
     SchedId sched_id = row_and_id.id;
     return *sched->id().IndexOf(sched_id);
   }
diff --git a/src/trace_processor/importers/common/thread_state_tracker.cc b/src/trace_processor/importers/common/thread_state_tracker.cc
index 9c3ee3c..37d26d1 100644
--- a/src/trace_processor/importers/common/thread_state_tracker.cc
+++ b/src/trace_processor/importers/common/thread_state_tracker.cc
@@ -15,14 +15,17 @@
  */
 
 #include "src/trace_processor/importers/common/thread_state_tracker.h"
+#include <cstdint>
 #include <optional>
+#include "src/trace_processor/importers/common/process_tracker.h"
 
 namespace perfetto {
 namespace trace_processor {
-ThreadStateTracker::ThreadStateTracker(TraceStorage* storage)
-    : storage_(storage),
-      running_string_id_(storage->InternString("Running")),
-      runnable_string_id_(storage->InternString("R")) {}
+ThreadStateTracker::ThreadStateTracker(TraceProcessorContext* context)
+    : storage_(context->storage.get()),
+      context_(context),
+      running_string_id_(storage_->InternString("Running")),
+      runnable_string_id_(storage_->InternString("R")) {}
 ThreadStateTracker::~ThreadStateTracker() = default;
 
 void ThreadStateTracker::PushSchedSwitchEvent(int64_t event_ts,
@@ -124,9 +127,9 @@
                                       std::optional<uint16_t> cpu,
                                       std::optional<UniqueTid> waker_utid,
                                       std::optional<uint16_t> common_flags) {
-  // Ignore utid 0 because it corresponds to the swapper thread which doesn't
-  // make sense to insert.
-  if (utid == 0)
+  // Ignore the swapper utid because it corresponds to the swapper thread which
+  // doesn't make sense to insert.
+  if (utid == context_->process_tracker->swapper_utid())
     return;
 
   // Insert row with unfinished state
@@ -137,6 +140,7 @@
   row.dur = -1;
   row.utid = utid;
   row.state = state;
+  row.machine_id = context_->machine_id();
   if (common_flags.has_value()) {
     row.irq_context = CommonFlagsToIrqContext(*common_flags);
   }
diff --git a/src/trace_processor/importers/common/thread_state_tracker.h b/src/trace_processor/importers/common/thread_state_tracker.h
index 2b7206b..9a78ada 100644
--- a/src/trace_processor/importers/common/thread_state_tracker.h
+++ b/src/trace_processor/importers/common/thread_state_tracker.h
@@ -28,14 +28,13 @@
 // waking events and blocking reasons.
 class ThreadStateTracker : public Destructible {
  public:
-  explicit ThreadStateTracker(TraceStorage*);
+  explicit ThreadStateTracker(TraceProcessorContext*);
   ThreadStateTracker(const ThreadStateTracker&) = delete;
   ThreadStateTracker& operator=(const ThreadStateTracker&) = delete;
   ~ThreadStateTracker() override;
   static ThreadStateTracker* GetOrCreate(TraceProcessorContext* context) {
     if (!context->thread_state_tracker) {
-      context->thread_state_tracker.reset(
-          new ThreadStateTracker(context->storage.get()));
+      context->thread_state_tracker.reset(new ThreadStateTracker(context));
     }
     return static_cast<ThreadStateTracker*>(
         context->thread_state_tracker.get());
@@ -90,6 +89,7 @@
   }
 
   TraceStorage* const storage_;
+  TraceProcessorContext* const context_;
 
   // Strings
   StringId running_string_id_;
diff --git a/src/trace_processor/importers/common/thread_state_tracker_unittest.cc b/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
index ea6794a..153b02b 100644
--- a/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
+++ b/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
@@ -20,6 +20,7 @@
 
 #include "src/trace_processor/importers/common/args_tracker.h"
 #include "src/trace_processor/importers/common/global_args_tracker.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "test/gtest_and_gmock.h"
 
@@ -41,10 +42,11 @@
  public:
   ThreadStateTrackerUnittest() {
     context_.storage.reset(new TraceStorage());
+    context_.process_tracker.reset(new ProcessTracker(&context_));
     context_.global_args_tracker.reset(
         new GlobalArgsTracker(context_.storage.get()));
     context_.args_tracker.reset(new ArgsTracker(&context_));
-    tracker_.reset(new ThreadStateTracker(context_.storage.get()));
+    tracker_.reset(new ThreadStateTracker(&context_));
   }
 
   StringId StringIdOf(const char* s) {
diff --git a/src/trace_processor/importers/common/track_tracker.cc b/src/trace_processor/importers/common/track_tracker.cc
index 640647b..8d0d17d 100644
--- a/src/trace_processor/importers/common/track_tracker.cc
+++ b/src/trace_processor/importers/common/track_tracker.cc
@@ -71,6 +71,7 @@
 
   tables::ThreadTrackTable::Row row;
   row.utid = utid;
+  row.machine_id = context_->machine_id();
   auto id = context_->storage->mutable_thread_track_table()->Insert(row).id;
   thread_tracks_[utid] = id;
   return id;
@@ -83,6 +84,7 @@
 
   tables::ProcessTrackTable::Row row;
   row.upid = upid;
+  row.machine_id = context_->machine_id();
   auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
   process_tracks_[upid] = id;
   return id;
@@ -103,6 +105,7 @@
 
   tables::CpuTrackTable::Row row(name);
   row.cpu = cpu;
+  row.machine_id = context_->machine_id();
   auto id = context_->storage->mutable_cpu_track_table()->Insert(row).id;
   cpu_tracks_[std::make_pair(name, cpu)] = id;
 
@@ -116,7 +119,9 @@
   if (it != gpu_tracks_.end())
     return it->second;
 
-  auto id = context_->storage->mutable_gpu_track_table()->Insert(row).id;
+  auto row_copy = row;
+  row_copy.machine_id = context_->machine_id();
+  auto id = context_->storage->mutable_gpu_track_table()->Insert(row_copy).id;
   gpu_tracks_[tuple] = id;
   return id;
 }
@@ -164,6 +169,7 @@
   // the ID's scope is global.
   tables::ProcessTrackTable::Row track(name);
   track.upid = upid;
+  track.machine_id = context_->machine_id();
   TrackId id =
       context_->storage->mutable_process_track_table()->Insert(track).id;
   chrome_tracks_[tuple] = id;
@@ -180,6 +186,7 @@
 
 TrackId TrackTracker::CreateGlobalAsyncTrack(StringId name, StringId source) {
   tables::TrackTable::Row row(name);
+  row.machine_id = context_->machine_id();
   auto id = context_->storage->mutable_track_table()->Insert(row).id;
   if (!source.is_null()) {
     context_->args_tracker->AddArgsTo(id).AddArg(source_key_,
@@ -193,6 +200,7 @@
                                               StringId source) {
   tables::ProcessTrackTable::Row row(name);
   row.upid = upid;
+  row.machine_id = context_->machine_id();
   auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
   if (!source.is_null()) {
     context_->args_tracker->AddArgsTo(id).AddArg(source_key_,
@@ -208,6 +216,7 @@
 
   tables::ProcessTrackTable::Row row;
   row.upid = upid;
+  row.machine_id = context_->machine_id();
   auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
   chrome_process_instant_tracks_[upid] = id;
 
@@ -219,8 +228,10 @@
 
 TrackId TrackTracker::GetOrCreateLegacyChromeGlobalInstantTrack() {
   if (!chrome_global_instant_track_id_) {
+    tables::TrackTable::Row row;
+    row.machine_id = context_->machine_id();
     chrome_global_instant_track_id_ =
-        context_->storage->mutable_track_table()->Insert({}).id;
+        context_->storage->mutable_track_table()->Insert(row).id;
 
     context_->args_tracker->AddArgsTo(*chrome_global_instant_track_id_)
         .AddArg(source_key_, Variadic::String(chrome_source_));
@@ -234,6 +245,7 @@
   }
   tables::TrackTable::Row row;
   row.name = context_->storage->InternString("Trace Triggers");
+  row.machine_id = context_->machine_id();
   trigger_track_id_ = context_->storage->mutable_track_table()->Insert(row).id;
   return *trigger_track_id_;
 }
@@ -252,6 +264,7 @@
   row.parent_id = InternTrackForGroup(group);
   row.unit = unit;
   row.description = description;
+  row.machine_id = context_->machine_id();
   TrackId track =
       context_->storage->mutable_counter_track_table()->Insert(row).id;
   global_counter_tracks_by_name_[name] = track;
@@ -270,6 +283,7 @@
 
   tables::CpuCounterTrackTable::Row row(name);
   row.cpu = cpu;
+  row.machine_id = context_->machine_id();
 
   TrackId track =
       context_->storage->mutable_cpu_counter_track_table()->Insert(row).id;
@@ -285,6 +299,7 @@
 
   tables::ThreadCounterTrackTable::Row row(name);
   row.utid = utid;
+  row.machine_id = context_->machine_id();
 
   TrackId track =
       context_->storage->mutable_thread_counter_track_table()->Insert(row).id;
@@ -305,6 +320,7 @@
   row.upid = upid;
   row.unit = unit;
   row.description = description;
+  row.machine_id = context_->machine_id();
 
   TrackId track =
       context_->storage->mutable_process_counter_track_table()->Insert(row).id;
@@ -320,6 +336,7 @@
 
   tables::IrqCounterTrackTable::Row row(name);
   row.irq = irq;
+  row.machine_id = context_->machine_id();
 
   TrackId track =
       context_->storage->mutable_irq_counter_track_table()->Insert(row).id;
@@ -336,6 +353,7 @@
 
   tables::SoftirqCounterTrackTable::Row row(name);
   row.softirq = softirq;
+  row.machine_id = context_->machine_id();
 
   TrackId track =
       context_->storage->mutable_softirq_counter_track_table()->Insert(row).id;
@@ -365,6 +383,7 @@
   row.consumer_id = consumer_id;
   row.consumer_type = consumer_type;
   row.ordinal = ordinal;
+  row.machine_id = context_->machine_id();
   TrackId track =
       context_->storage->mutable_energy_counter_track_table()->Insert(row).id;
   energy_counter_tracks_[std::make_pair(name, consumer_id)] = track;
@@ -382,6 +401,7 @@
   tables::EnergyPerUidCounterTrackTable::Row row(name);
   row.consumer_id = consumer_id;
   row.uid = uid;
+  row.machine_id = context_->machine_id();
   TrackId track =
       context_->storage->mutable_energy_per_uid_counter_track_table()
           ->Insert(row)
@@ -411,6 +431,7 @@
   row.gpu_id = gpu_id;
   row.description = description;
   row.unit = unit;
+  row.machine_id = context_->machine_id();
 
   return context_->storage->mutable_gpu_counter_track_table()->Insert(row).id;
 }
@@ -423,6 +444,7 @@
   row.perf_session_id = perf_session_id;
   row.cpu = cpu;
   row.is_timebase = is_timebase;
+  row.machine_id = context_->machine_id();
   return context_->storage->mutable_perf_counter_track_table()->Insert(row).id;
 }
 
@@ -434,7 +456,9 @@
   }
 
   StringId id = context_->storage->InternString(GetNameForGroup(group));
-  TrackId track_id = context_->storage->mutable_track_table()->Insert({id}).id;
+  tables::TrackTable::Row row{id};
+  row.machine_id = context_->machine_id();
+  TrackId track_id = context_->storage->mutable_track_table()->Insert(row).id;
   group_track_ids_[group_idx] = track_id;
   return track_id;
 }
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 6e1e1bb..b1e3468 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -1259,9 +1259,10 @@
   protos::pbzero::GenericFtraceEvent::Decoder evt(blob.data, blob.size);
   StringId event_id = context_->storage->InternString(evt.event_name());
   UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
-  RawId id = context_->storage->mutable_ftrace_event_table()
-                 ->Insert({ts, event_id, cpu, utid})
-                 .id;
+  RawId id =
+      context_->storage->mutable_ftrace_event_table()
+          ->Insert({ts, event_id, cpu, utid, {}, {}, context_->machine_id()})
+          .id;
   auto inserter = context_->args_tracker->AddArgsTo(id);
 
   for (auto it = evt.field(); it; ++it) {
@@ -1300,10 +1301,15 @@
   FtraceMessageDescriptor* m = GetMessageDescriptorForId(ftrace_id);
   const auto& message_strings = ftrace_message_strings_[ftrace_id];
   UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
-  RawId id =
-      context_->storage->mutable_ftrace_event_table()
-          ->Insert({timestamp, message_strings.message_name_id, cpu, utid})
-          .id;
+  RawId id = context_->storage->mutable_ftrace_event_table()
+                 ->Insert({timestamp,
+                           message_strings.message_name_id,
+                           cpu,
+                           utid,
+                           {},
+                           {},
+                           context_->machine_id()})
+                 .id;
   auto inserter = context_->args_tracker->AddArgsTo(id);
 
   for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
diff --git a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc b/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
index 1a4f5d7..2c0a962 100644
--- a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
@@ -241,6 +241,7 @@
     row.cpu = cpu;
     row.utid = curr_utid;
     row.common_flags = common_flags;
+    row.machine_id = context_->machine_id();
 
     // Add an entry to the raw table.
     RawId id = context_->storage->mutable_ftrace_event_table()->Insert(row).id;
@@ -281,7 +282,13 @@
     // Push the raw event - this is done as the raw ftrace event codepath does
     // not insert sched_switch.
     RawId id = context_->storage->mutable_ftrace_event_table()
-                   ->Insert({ts, sched_switch_id_, cpu, prev_utid})
+                   ->Insert({ts,
+                             sched_switch_id_,
+                             cpu,
+                             prev_utid,
+                             {},
+                             {},
+                             context_->machine_id()})
                    .id;
 
     // Note: this ordering is important. The events should be pushed in the same
diff --git a/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc b/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc
index 07e60a4..86db07b 100644
--- a/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc
+++ b/src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc
@@ -40,6 +40,7 @@
   tables::GpuWorkPeriodTrackTable::Row track(gpu_work_period_id_);
   track.uid = static_cast<int32_t>(evt.uid());
   track.gpu_id = evt.gpu_id();
+  track.machine_id = context_->machine_id();
   TrackId track_id = context_->track_tracker->InternGpuWorkPeriodTrack(track);
 
   const int64_t duration =
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index b23a513..4043ec6 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -30,6 +30,7 @@
 
 #include "src/trace_processor/importers/common/args_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/parser_types.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
@@ -255,7 +256,8 @@
   ArgsTracker args(context_);
   if (bundle.has_metadata()) {
     RawId id = storage->mutable_raw_table()
-                   ->Insert({ts, raw_chrome_metadata_event_id_, 0, 0})
+                   ->Insert({ts, raw_chrome_metadata_event_id_, 0, 0, 0, 0,
+                             context_->machine_id()})
                    .id;
     auto inserter = args.AddArgsTo(id);
 
@@ -301,10 +303,10 @@
   }
 
   if (bundle.has_legacy_ftrace_output()) {
-    RawId id =
-        storage->mutable_raw_table()
-            ->Insert({ts, raw_chrome_legacy_system_trace_event_id_, 0, 0})
-            .id;
+    RawId id = storage->mutable_raw_table()
+                   ->Insert({ts, raw_chrome_legacy_system_trace_event_id_, 0, 0,
+                             0, 0, context_->machine_id()})
+                   .id;
 
     std::string data;
     for (auto it = bundle.legacy_ftrace_output(); it; ++it) {
@@ -322,10 +324,10 @@
           protos::pbzero::ChromeLegacyJsonTrace::USER_TRACE) {
         continue;
       }
-      RawId id =
-          storage->mutable_raw_table()
-              ->Insert({ts, raw_chrome_legacy_user_trace_event_id_, 0, 0})
-              .id;
+      RawId id = storage->mutable_raw_table()
+                     ->Insert({ts, raw_chrome_legacy_user_trace_event_id_, 0, 0,
+                               0, 0, context_->machine_id()})
+                     .id;
       Variadic value =
           Variadic::String(storage->InternString(legacy_trace.data()));
       args.AddArgsTo(id).AddArg(data_name_id_, value);
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 12e044b..3f049c5 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -28,6 +28,7 @@
 #include "perfetto/trace_processor/status.h"
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/ftrace/ftrace_module.h"
@@ -407,6 +408,7 @@
         clock_timestamp.timestamp * clock_timestamp.clock.unit_multiplier_ns;
     row.clock_name = GetBuiltinClockNameOrNull(clock_timestamp.clock.id);
     row.snapshot_id = *snapshot_id;
+    row.machine_id = context_->machine_id();
 
     context_->storage->mutable_clock_snapshot_table()->Insert(row);
   }
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 8812674..5b878ed 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -761,6 +761,7 @@
       cluster_id++;
     }
     cpu_row.cluster_id = cluster_id;
+    cpu_row.machine_id = context_->machine_id();
 
     last_cpu_freqs = freqs;
     tables::CpuTable::Id cpu_row_id =
@@ -771,6 +772,7 @@
       tables::CpuFreqTable::Row cpu_freq_row;
       cpu_freq_row.cpu_id = cpu_row_id;
       cpu_freq_row.freq = freq;
+      cpu_freq_row.machine_id = context_->machine_id();
       context_->storage->mutable_cpu_freq_table()->Insert(cpu_freq_row);
     }
   }
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index cdf2c45..cb80844 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -28,6 +28,7 @@
 #include "src/trace_processor/importers/common/args_translation_table.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
 #include "src/trace_processor/importers/json/json_utils.h"
@@ -1122,7 +1123,8 @@
       return util::ErrStatus("raw legacy event without thread association");
 
     RawId id = storage_->mutable_raw_table()
-                   ->Insert({ts_, parser_->raw_legacy_event_id_, 0, *utid_})
+                   ->Insert({ts_, parser_->raw_legacy_event_id_, 0, *utid_, 0,
+                             0, context_->machine_id()})
                    .id;
 
     auto inserter = context_->args_tracker->AddArgsTo(id);
diff --git a/src/trace_processor/importers/proto/track_event_tracker.cc b/src/trace_processor/importers/proto/track_event_tracker.cc
index ad78346..56e081d 100644
--- a/src/trace_processor/importers/proto/track_event_tracker.cc
+++ b/src/trace_processor/importers/proto/track_event_tracker.cc
@@ -20,6 +20,7 @@
 #include "src/trace_processor/importers/common/args_translation_table.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/tables/track_tables_py.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -163,6 +164,7 @@
 TrackId TrackEventTracker::InsertThreadTrack(UniqueTid utid) {
   tables::ThreadTrackTable::Row row;
   row.utid = utid;
+  row.machine_id = context_->machine_id();
   auto* thread_tracks = context_->storage->mutable_thread_track_table();
   return thread_tracks->Insert(row).id;
 }
@@ -283,6 +285,7 @@
       if (track.is_counter()) {
         tables::ThreadCounterTrackTable::Row row;
         row.utid = track.utid();
+        row.machine_id = context_->machine_id();
 
         auto* thread_counter_tracks =
             context_->storage->mutable_thread_counter_track_table();
@@ -295,6 +298,7 @@
       if (track.is_counter()) {
         tables::ProcessCounterTrackTable::Row row;
         row.upid = track.upid();
+        row.machine_id = context_->machine_id();
 
         auto* process_counter_tracks =
             context_->storage->mutable_process_counter_track_table();
@@ -303,14 +307,20 @@
 
       tables::ProcessTrackTable::Row row;
       row.upid = track.upid();
+      row.machine_id = context_->machine_id();
 
       auto* process_tracks = context_->storage->mutable_process_track_table();
       return process_tracks->Insert(row).id;
     }
     case ResolvedDescriptorTrack::Scope::kGlobal: {
-      if (track.is_counter())
-        return context_->storage->mutable_counter_track_table()->Insert({}).id;
-      return context_->storage->mutable_track_table()->Insert({}).id;
+      if (track.is_counter()) {
+        tables::CounterTrackTable::Row row;
+        row.machine_id = context_->machine_id();
+        return context_->storage->mutable_counter_track_table()->Insert(row).id;
+      }
+      tables::TrackTable::Row row;
+      row.machine_id = context_->machine_id();
+      return context_->storage->mutable_track_table()->Insert(row).id;
     }
   }
   PERFETTO_FATAL("For GCC");
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index ec014d7..5f83c4b 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -541,6 +541,9 @@
     return &ftrace_event_table_;
   }
 
+  const tables::MachineTable& machine_table() const { return machine_table_; }
+  tables::MachineTable* mutable_machine_table() { return &machine_table_; }
+
   const tables::CpuTable& cpu_table() const { return cpu_table_; }
   tables::CpuTable* mutable_cpu_table() { return &cpu_table_; }
 
@@ -1022,6 +1025,8 @@
   tables::RawTable raw_table_{&string_pool_};
   tables::FtraceEventTable ftrace_event_table_{&string_pool_, &raw_table_};
 
+  tables::MachineTable machine_table_{&string_pool_};
+
   tables::CpuTable cpu_table_{&string_pool_};
 
   tables::CpuFreqTable cpu_freq_table_{&string_pool_};
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 16c2665..d98fd77 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -60,6 +60,7 @@
 ProcessTable::~ProcessTable() = default;
 FiledescriptorTable::~FiledescriptorTable() = default;
 ClockSnapshotTable::~ClockSnapshotTable() = default;
+MachineTable::~MachineTable() = default;
 
 // profiler_tables_py.h
 StackProfileMappingTable::~StackProfileMappingTable() = default;
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index 2ee7b3d..03bded3 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -15,6 +15,7 @@
  */
 
 #include "src/trace_processor/types/trace_processor_context.h"
+#include <optional>
 
 #include "src/trace_processor/forwarding_trace_parser.h"
 #include "src/trace_processor/importers/common/args_tracker.h"
@@ -27,6 +28,7 @@
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
 #include "src/trace_processor/importers/common/global_args_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
 #include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
@@ -49,5 +51,13 @@
 TraceProcessorContext::TraceProcessorContext() = default;
 TraceProcessorContext::~TraceProcessorContext() = default;
 
+std::optional<MachineId> TraceProcessorContext::machine_id() const {
+  if (!machine_tracker) {
+    // Doesn't require that |machine_tracker| is initialzed, e.g. in unit tests.
+    return std::nullopt;
+  }
+  return machine_tracker->machine_id();
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index b0c7a15..9fb6fe3 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -26,6 +26,7 @@
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
 #include "src/trace_processor/importers/common/flow_tracker.h"
+#include "src/trace_processor/importers/common/machine_tracker.h"
 #include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
@@ -49,8 +50,9 @@
 
 TraceProcessorStorageImpl::TraceProcessorStorageImpl(const Config& cfg) {
   context_.config = cfg;
-
   context_.storage.reset(new TraceStorage(context_.config));
+  context_.machine_tracker.reset(new MachineTracker(&context_,
+                                                    /*raw_machine_id=*/0));
   context_.track_tracker.reset(new TrackTracker(&context_));
   context_.async_track_set_tracker.reset(new AsyncTrackSetTracker(&context_));
   context_.args_tracker.reset(new ArgsTracker(&context_));
diff --git a/src/trace_processor/types/BUILD.gn b/src/trace_processor/types/BUILD.gn
index 0605ea1..6b66c53 100644
--- a/src/trace_processor/types/BUILD.gn
+++ b/src/trace_processor/types/BUILD.gn
@@ -31,6 +31,7 @@
     "../../../include/perfetto/ext/base",
     "../../../include/perfetto/trace_processor",
     "../containers",
+    "../tables:tables_python",
   ]
 }
 
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index 164df00..d5f5779 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/tables/metadata_tables_py.h"
 #include "src/trace_processor/types/destructible.h"
 
 namespace perfetto {
@@ -55,6 +56,7 @@
 class StackProfileTracker;
 class HeapGraphTracker;
 class PerfSampleTracker;
+class MachineTracker;
 class MappingTracker;
 class MetadataTracker;
 class PacketAnalyzer;
@@ -71,6 +73,8 @@
 class TrackTracker;
 class DescriptorPool;
 
+using MachineId = tables::MachineTable::Id;
+
 class TraceProcessorContext {
  public:
   TraceProcessorContext();
@@ -104,6 +108,7 @@
   std::unique_ptr<ClockTracker> clock_tracker;
   std::unique_ptr<ClockConverter> clock_converter;
   std::unique_ptr<MappingTracker> mapping_tracker;
+  std::unique_ptr<MachineTracker> machine_tracker;
   std::unique_ptr<PerfSampleTracker> perf_sample_tracker;
   std::unique_ptr<StackProfileTracker> stack_profile_tracker;
   std::unique_ptr<MetadataTracker> metadata_tracker;
@@ -171,6 +176,8 @@
   bool uuid_found_in_trace = false;
 
   TraceType trace_type = kUnknownTraceType;
+
+  std::optional<MachineId> machine_id() const;
 };
 
 }  // namespace trace_processor