Merge "tp: partially revert aosp/2977479" into main
diff --git a/Android.bp b/Android.bp
index a0269f3..a991cc1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2378,7 +2378,6 @@
         ":perfetto_src_trace_processor_storage_storage",
         ":perfetto_src_trace_processor_tables_tables",
         ":perfetto_src_trace_processor_types_types",
-        ":perfetto_src_trace_processor_util_build_id",
         ":perfetto_src_trace_processor_util_bump_allocator",
         ":perfetto_src_trace_processor_util_descriptors",
         ":perfetto_src_trace_processor_util_glob",
@@ -2392,6 +2391,7 @@
         ":perfetto_src_trace_processor_util_protozero_to_text",
         ":perfetto_src_trace_processor_util_regex",
         ":perfetto_src_trace_processor_util_sql_argument",
+        ":perfetto_src_trace_processor_util_stack_traces_util",
         ":perfetto_src_trace_processor_util_stdlib",
         ":perfetto_src_trace_processor_util_util",
         ":perfetto_src_trace_processor_util_zip_reader",
@@ -11110,7 +11110,6 @@
         "src/trace_processor/importers/common/event_tracker.cc",
         "src/trace_processor/importers/common/flow_tracker.cc",
         "src/trace_processor/importers/common/global_args_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",
         "src/trace_processor/importers/common/sched_event_tracker.cc",
@@ -11121,7 +11120,6 @@
         "src/trace_processor/importers/common/thread_state_tracker.cc",
         "src/trace_processor/importers/common/trace_parser.cc",
         "src/trace_processor/importers/common/track_tracker.cc",
-        "src/trace_processor/importers/common/virtual_memory_mapping.cc",
     ],
 }
 
@@ -12066,6 +12064,7 @@
         "src/trace_processor/perfetto_sql/stdlib/sched/utilization/process.sql",
         "src/trace_processor/perfetto_sql/stdlib/sched/utilization/system.sql",
         "src/trace_processor/perfetto_sql/stdlib/sched/utilization/thread.sql",
+        "src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/flat_slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql",
@@ -12325,14 +12324,6 @@
     name: "perfetto_src_trace_processor_unittests",
 }
 
-// GN: //src/trace_processor/util:build_id
-filegroup {
-    name: "perfetto_src_trace_processor_util_build_id",
-    srcs: [
-        "src/trace_processor/util/build_id.cc",
-    ],
-}
-
 // GN: //src/trace_processor/util:bump_allocator
 filegroup {
     name: "perfetto_src_trace_processor_util_bump_allocator",
@@ -12433,6 +12424,14 @@
     ],
 }
 
+// GN: //src/trace_processor/util:stack_traces_util
+filegroup {
+    name: "perfetto_src_trace_processor_util_stack_traces_util",
+    srcs: [
+        "src/trace_processor/util/stack_traces_util.cc",
+    ],
+}
+
 // GN: //src/trace_processor/util:stdlib
 filegroup {
     name: "perfetto_src_trace_processor_util_stdlib",
@@ -13960,7 +13959,6 @@
         ":perfetto_src_trace_processor_types_types",
         ":perfetto_src_trace_processor_types_unittests",
         ":perfetto_src_trace_processor_unittests",
-        ":perfetto_src_trace_processor_util_build_id",
         ":perfetto_src_trace_processor_util_bump_allocator",
         ":perfetto_src_trace_processor_util_descriptors",
         ":perfetto_src_trace_processor_util_glob",
@@ -13974,6 +13972,7 @@
         ":perfetto_src_trace_processor_util_protozero_to_text",
         ":perfetto_src_trace_processor_util_regex",
         ":perfetto_src_trace_processor_util_sql_argument",
+        ":perfetto_src_trace_processor_util_stack_traces_util",
         ":perfetto_src_trace_processor_util_stdlib",
         ":perfetto_src_trace_processor_util_unittests",
         ":perfetto_src_trace_processor_util_util",
@@ -14663,7 +14662,6 @@
         ":perfetto_src_trace_processor_storage_storage",
         ":perfetto_src_trace_processor_tables_tables",
         ":perfetto_src_trace_processor_types_types",
-        ":perfetto_src_trace_processor_util_build_id",
         ":perfetto_src_trace_processor_util_bump_allocator",
         ":perfetto_src_trace_processor_util_descriptors",
         ":perfetto_src_trace_processor_util_glob",
@@ -14677,6 +14675,7 @@
         ":perfetto_src_trace_processor_util_protozero_to_text",
         ":perfetto_src_trace_processor_util_regex",
         ":perfetto_src_trace_processor_util_sql_argument",
+        ":perfetto_src_trace_processor_util_stack_traces_util",
         ":perfetto_src_trace_processor_util_stdlib",
         ":perfetto_src_trace_processor_util_util",
         ":perfetto_src_trace_processor_util_zip_reader",
@@ -14897,7 +14896,6 @@
         ":perfetto_src_trace_processor_storage_storage",
         ":perfetto_src_trace_processor_tables_tables",
         ":perfetto_src_trace_processor_types_types",
-        ":perfetto_src_trace_processor_util_build_id",
         ":perfetto_src_trace_processor_util_bump_allocator",
         ":perfetto_src_trace_processor_util_descriptors",
         ":perfetto_src_trace_processor_util_glob",
@@ -14911,6 +14909,7 @@
         ":perfetto_src_trace_processor_util_protozero_to_text",
         ":perfetto_src_trace_processor_util_regex",
         ":perfetto_src_trace_processor_util_sql_argument",
+        ":perfetto_src_trace_processor_util_stack_traces_util",
         ":perfetto_src_trace_processor_util_stdlib",
         ":perfetto_src_trace_processor_util_util",
         ":perfetto_src_trace_processor_util_zip_reader",
diff --git a/BUILD b/BUILD
index bd40277..ac30232 100644
--- a/BUILD
+++ b/BUILD
@@ -266,7 +266,6 @@
         ":src_trace_processor_tables_tables",
         ":src_trace_processor_tables_tables_python",
         ":src_trace_processor_types_types",
-        ":src_trace_processor_util_build_id",
         ":src_trace_processor_util_bump_allocator",
         ":src_trace_processor_util_descriptors",
         ":src_trace_processor_util_glob",
@@ -280,6 +279,7 @@
         ":src_trace_processor_util_protozero_to_text",
         ":src_trace_processor_util_regex",
         ":src_trace_processor_util_sql_argument",
+        ":src_trace_processor_util_stack_traces_util",
         ":src_trace_processor_util_stdlib",
         ":src_trace_processor_util_util",
         ":src_trace_processor_util_zip_reader",
@@ -1467,7 +1467,6 @@
         "src/trace_processor/importers/common/clock_converter.h",
         "src/trace_processor/importers/common/clock_tracker.cc",
         "src/trace_processor/importers/common/clock_tracker.h",
-        "src/trace_processor/importers/common/create_mapping_params.h",
         "src/trace_processor/importers/common/deobfuscation_mapping_table.cc",
         "src/trace_processor/importers/common/deobfuscation_mapping_table.h",
         "src/trace_processor/importers/common/event_tracker.cc",
@@ -1476,8 +1475,6 @@
         "src/trace_processor/importers/common/flow_tracker.h",
         "src/trace_processor/importers/common/global_args_tracker.cc",
         "src/trace_processor/importers/common/global_args_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",
         "src/trace_processor/importers/common/metadata_tracker.h",
         "src/trace_processor/importers/common/process_tracker.cc",
@@ -1498,8 +1495,6 @@
         "src/trace_processor/importers/common/trace_parser.cc",
         "src/trace_processor/importers/common/track_tracker.cc",
         "src/trace_processor/importers/common/track_tracker.h",
-        "src/trace_processor/importers/common/virtual_memory_mapping.cc",
-        "src/trace_processor/importers/common/virtual_memory_mapping.h",
     ],
 )
 
@@ -2518,6 +2513,7 @@
 perfetto_filegroup(
     name = "src_trace_processor_perfetto_sql_stdlib_slices_slices",
     srcs = [
+        "src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/flat_slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql",
@@ -2703,15 +2699,6 @@
     ],
 )
 
-# GN target: //src/trace_processor/util:build_id
-perfetto_filegroup(
-    name = "src_trace_processor_util_build_id",
-    srcs = [
-        "src/trace_processor/util/build_id.cc",
-        "src/trace_processor/util/build_id.h",
-    ],
-)
-
 # GN target: //src/trace_processor/util:bump_allocator
 perfetto_filegroup(
     name = "src_trace_processor_util_bump_allocator",
@@ -2831,6 +2818,15 @@
     ],
 )
 
+# GN target: //src/trace_processor/util:stack_traces_util
+perfetto_filegroup(
+    name = "src_trace_processor_util_stack_traces_util",
+    srcs = [
+        "src/trace_processor/util/stack_traces_util.cc",
+        "src/trace_processor/util/stack_traces_util.h",
+    ],
+)
+
 # GN target: //src/trace_processor/util:stdlib
 perfetto_filegroup(
     name = "src_trace_processor_util_stdlib",
@@ -5648,7 +5644,6 @@
         ":src_trace_processor_tables_tables",
         ":src_trace_processor_tables_tables_python",
         ":src_trace_processor_types_types",
-        ":src_trace_processor_util_build_id",
         ":src_trace_processor_util_bump_allocator",
         ":src_trace_processor_util_descriptors",
         ":src_trace_processor_util_glob",
@@ -5662,6 +5657,7 @@
         ":src_trace_processor_util_protozero_to_text",
         ":src_trace_processor_util_regex",
         ":src_trace_processor_util_sql_argument",
+        ":src_trace_processor_util_stack_traces_util",
         ":src_trace_processor_util_stdlib",
         ":src_trace_processor_util_util",
         ":src_trace_processor_util_zip_reader",
@@ -5819,7 +5815,6 @@
         ":src_trace_processor_tables_tables",
         ":src_trace_processor_tables_tables_python",
         ":src_trace_processor_types_types",
-        ":src_trace_processor_util_build_id",
         ":src_trace_processor_util_bump_allocator",
         ":src_trace_processor_util_descriptors",
         ":src_trace_processor_util_glob",
@@ -5833,6 +5828,7 @@
         ":src_trace_processor_util_protozero_to_text",
         ":src_trace_processor_util_regex",
         ":src_trace_processor_util_sql_argument",
+        ":src_trace_processor_util_stack_traces_util",
         ":src_trace_processor_util_stdlib",
         ":src_trace_processor_util_util",
         ":src_trace_processor_util_zip_reader",
@@ -5910,7 +5906,7 @@
         ":src_profiling_deobfuscator",
         ":src_profiling_symbolizer_symbolize_database",
         ":src_profiling_symbolizer_symbolizer",
-        ":src_trace_processor_util_build_id",
+        ":src_trace_processor_util_stack_traces_util",
         ":src_traceconv_pprofbuilder",
         ":src_traceconv_utils",
     ],
@@ -6042,7 +6038,6 @@
         ":src_trace_processor_tables_tables",
         ":src_trace_processor_tables_tables_python",
         ":src_trace_processor_types_types",
-        ":src_trace_processor_util_build_id",
         ":src_trace_processor_util_bump_allocator",
         ":src_trace_processor_util_descriptors",
         ":src_trace_processor_util_glob",
@@ -6056,6 +6051,7 @@
         ":src_trace_processor_util_protozero_to_text",
         ":src_trace_processor_util_regex",
         ":src_trace_processor_util_sql_argument",
+        ":src_trace_processor_util_stack_traces_util",
         ":src_trace_processor_util_stdlib",
         ":src_trace_processor_util_util",
         ":src_trace_processor_util_zip_reader",
diff --git a/gn/perfetto_unittests.gni b/gn/perfetto_unittests.gni
index 836ac9a..f1d46ba 100644
--- a/gn/perfetto_unittests.gni
+++ b/gn/perfetto_unittests.gni
@@ -86,6 +86,4 @@
   perfetto_unittests_targets += [ "src/traced_relay:unittests" ]
 }
 
-if (!is_win) {
-  perfetto_unittests_targets += [ "src/trace_redaction:unittests" ]
-}
+perfetto_unittests_targets += [ "src/trace_redaction:unittests" ]
diff --git a/python/generators/sql_processing/utils.py b/python/generators/sql_processing/utils.py
index ba14110..539115e 100644
--- a/python/generators/sql_processing/utils.py
+++ b/python/generators/sql_processing/utils.py
@@ -116,7 +116,8 @@
 
 # Allows for nonstandard object names.
 OBJECT_NAME_ALLOWLIST = {
-    'slices/with_context.sql': ['process_slice', 'thread_slice']
+    'slices/with_context.sql': ['process_slice', 'thread_slice'],
+    'slices/cpu_time.sql': ['thread_slice_cpu_time']
 }
 
 # Given a regex pattern and a string to match against, returns all the
diff --git a/src/profiling/symbolizer/BUILD.gn b/src/profiling/symbolizer/BUILD.gn
index 2eb2c93..722d1cf 100644
--- a/src/profiling/symbolizer/BUILD.gn
+++ b/src/profiling/symbolizer/BUILD.gn
@@ -49,7 +49,7 @@
       "../../../include/perfetto/trace_processor:trace_processor",
       "../../../protos/perfetto/trace:zero",
       "../../../protos/perfetto/trace/profiling:zero",
-      "../../trace_processor/util:build_id",
+      "../../trace_processor/util:stack_traces_util",
     ]
     sources = [
       "symbolize_database.cc",
diff --git a/src/profiling/symbolizer/symbolize_database.cc b/src/profiling/symbolizer/symbolize_database.cc
index a008e1a..224874b 100644
--- a/src/profiling/symbolizer/symbolize_database.cc
+++ b/src/profiling/symbolizer/symbolize_database.cc
@@ -28,7 +28,8 @@
 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
 #include "protos/perfetto/trace/trace.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
-#include "src/trace_processor/util/build_id.h"
+
+#include "src/trace_processor/util/stack_traces_util.h"
 
 namespace perfetto {
 namespace profiling {
@@ -55,6 +56,32 @@
   }
 };
 
+std::string FromHex(const char* str, size_t size) {
+  if (size % 2) {
+    PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
+    return "";
+  }
+  std::string result(size / 2, '\0');
+  for (size_t i = 0; i < size; i += 2) {
+    char hex_byte[3];
+    hex_byte[0] = str[i];
+    hex_byte[1] = str[i + 1];
+    hex_byte[2] = '\0';
+    char* end;
+    long int byte = strtol(hex_byte, &end, 16);
+    if (*end != '\0') {
+      PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
+      return "";
+    }
+    result[i / 2] = static_cast<char>(byte);
+  }
+  return result;
+}
+
+std::string FromHex(const std::string& str) {
+  return FromHex(str.c_str(), str.size());
+}
+
 std::map<UnsymbolizedMapping, std::vector<uint64_t>> GetUnsymbolizedFrames(
     trace_processor::TraceProcessor* tp) {
   std::map<UnsymbolizedMapping, std::vector<uint64_t>> res;
@@ -62,10 +89,17 @@
   while (it.Next()) {
     int64_t load_bias = it.Get(3).AsLong();
     PERFETTO_CHECK(load_bias >= 0);
-    trace_processor::BuildId build_id =
-        trace_processor::BuildId::FromHex(it.Get(1).AsString());
-    UnsymbolizedMapping unsymbolized_mapping{
-        it.Get(0).AsString(), build_id.raw(), static_cast<uint64_t>(load_bias)};
+    std::string build_id;
+    // TODO(b/148109467): Remove workaround once all active Chrome versions
+    // write raw bytes instead of a string as build_id.
+    std::string raw_build_id = it.Get(1).AsString();
+    if (!trace_processor::util::IsHexModuleId(base::StringView(raw_build_id))) {
+      build_id = FromHex(raw_build_id);
+    } else {
+      build_id = raw_build_id;
+    }
+    UnsymbolizedMapping unsymbolized_mapping{it.Get(0).AsString(), build_id,
+                                             static_cast<uint64_t>(load_bias)};
     int64_t rel_pc = it.Get(2).AsLong();
     res[unsymbolized_mapping].emplace_back(rel_pc);
   }
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index e37c9c6..e81b184 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -132,6 +132,7 @@
     "util:descriptors",
     "util:gzip",
     "util:proto_to_args_parser",
+    "util:stack_traces_util",
   ]
   public_deps = [ "../../include/perfetto/trace_processor:storage" ]
 }
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index 5108dca..466876a 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -28,7 +28,6 @@
     "clock_converter.h",
     "clock_tracker.cc",
     "clock_tracker.h",
-    "create_mapping_params.h",
     "deobfuscation_mapping_table.cc",
     "deobfuscation_mapping_table.h",
     "event_tracker.cc",
@@ -37,8 +36,6 @@
     "flow_tracker.h",
     "global_args_tracker.cc",
     "global_args_tracker.h",
-    "mapping_tracker.cc",
-    "mapping_tracker.h",
     "metadata_tracker.cc",
     "metadata_tracker.h",
     "process_tracker.cc",
@@ -59,8 +56,6 @@
     "trace_parser.cc",
     "track_tracker.cc",
     "track_tracker.h",
-    "virtual_memory_mapping.cc",
-    "virtual_memory_mapping.h",
   ]
   public_deps = [
     ":trace_parser_hdr",
@@ -80,8 +75,8 @@
     "../../storage",
     "../../tables:tables",
     "../../types",
-    "../../util:build_id",
     "../../util:profiler_util",
+    "../../util:stack_traces_util",
     "../fuchsia:fuchsia_record",
     "../systrace:systrace_line",
   ]
diff --git a/src/trace_processor/importers/common/create_mapping_params.h b/src/trace_processor/importers/common/create_mapping_params.h
deleted file mode 100644
index 7aba456..0000000
--- a/src/trace_processor/importers/common/create_mapping_params.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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_CREATE_MAPPING_PARAMS_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_CREATE_MAPPING_PARAMS_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <optional>
-#include <string>
-#include <tuple>
-
-#include "perfetto/ext/base/hash.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/util/build_id.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-struct CreateMappingParams {
-  AddressRange memory_range;
-  // This is the offset into the file that has been mapped at
-  // memory_range.start()
-  uint64_t exact_offset = 0;
-  // This is the offset into the file where the ELF header starts. We assume
-  // all file mappings are ELF files an thus this offset is 0.
-  uint64_t start_offset = 0;
-  // This can only be read out of the actual ELF file.
-  uint64_t load_bias = 0;
-  std::string name;
-  std::optional<BuildId> build_id;
-
-  auto ToTuple() const {
-    return std::tie(memory_range, exact_offset, start_offset, load_bias, name,
-                    build_id);
-  }
-
-  bool operator==(const CreateMappingParams& o) const {
-    return ToTuple() == o.ToTuple();
-  }
-
-  struct Hasher {
-    size_t operator()(const CreateMappingParams& p) const {
-      base::Hasher h;
-      h.UpdateAll(p.memory_range.start(), p.memory_range.end(), p.exact_offset,
-                  p.start_offset, p.load_bias, p.name);
-      if (p.build_id) {
-        h.Update(*p.build_id);
-      }
-      return static_cast<size_t>(h.digest());
-    }
-  };
-};
-
-}  // namespace trace_processor
-}  // namespace perfetto
-
-#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_CREATE_MAPPING_PARAMS_H_
diff --git a/src/trace_processor/importers/common/mapping_tracker.cc b/src/trace_processor/importers/common/mapping_tracker.cc
deleted file mode 100644
index 13b8274..0000000
--- a/src/trace_processor/importers/common/mapping_tracker.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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/mapping_tracker.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <utility>
-
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-
-bool IsKernelModule(base::StringView name) {
-  return !name.StartsWith("[kernel.kallsyms]");
-}
-
-}  // namespace
-
-JitDelegate::~JitDelegate() = default;
-
-template <typename MappingImpl>
-MappingImpl& MappingTracker::AddMapping(std::unique_ptr<MappingImpl> mapping) {
-  auto ptr = mapping.get();
-  PERFETTO_CHECK(
-      mappings_by_id_.Insert(ptr->mapping_id(), std::move(mapping)).second);
-
-  mappings_by_name_and_build_id_[NameAndBuildId{base::StringView(ptr->name()),
-                                                ptr->build_id()}]
-      .push_back(ptr);
-
-  return *ptr;
-}
-
-KernelMemoryMapping& MappingTracker::CreateKernelMemoryMapping(
-    CreateMappingParams params) {
-  // TODO(carlscab): Guess build_id if not provided. Some tools like simpleperf
-  // add a mapping file_name ->build_id that we could use here
-
-  const bool is_module = IsKernelModule(base::StringView(params.name));
-
-  if (!is_module && kernel_ != nullptr) {
-    PERFETTO_CHECK(params.memory_range == kernel_->memory_range());
-    return *kernel_;
-  }
-
-  std::unique_ptr<KernelMemoryMapping> mapping(
-      new KernelMemoryMapping(context_, std::move(params)));
-
-  if (is_module) {
-    // TODO(carlscab): Overlaps not supported (for now?). Should be fine for
-    // kernel.
-    PERFETTO_CHECK(
-        kernel_modules_.Emplace(mapping->memory_range(), mapping.get()));
-  } else {
-    kernel_ = mapping.get();
-  }
-
-  return AddMapping(std::move(mapping));
-}
-
-UserMemoryMapping& MappingTracker::CreateUserMemoryMapping(
-    UniquePid upid,
-    CreateMappingParams params) {
-  // TODO(carlscab): Guess build_id if not provided. Some tools like simpleperf
-  // add a mapping file_name ->build_id that we could use here
-
-  const AddressRange mapping_range = params.memory_range;
-  std::unique_ptr<UserMemoryMapping> mapping(
-      new UserMemoryMapping(context_, upid, std::move(params)));
-  // TODO(carlscab): Overlaps not supported (for now?).
-  PERFETTO_CHECK(user_memory_[upid].Emplace(mapping_range, mapping.get()));
-
-  jit_delegates_[upid].ForOverlaps(
-      mapping_range, [&](std::pair<const AddressRange, JitDelegate*>& entry) {
-        const auto& jit_range = entry.first;
-        JitDelegate* jit_delegate = entry.second;
-        PERFETTO_CHECK(jit_range.Contains(mapping_range));
-        mapping->SetJitDelegate(jit_delegate);
-      });
-
-  return AddMapping(std::move(mapping));
-}
-
-KernelMemoryMapping* MappingTracker::FindKernelMappingForAddress(
-    uint64_t address) const {
-  if (auto it = kernel_modules_.Find(address); it != kernel_modules_.end()) {
-    return it->second;
-  }
-  if (kernel_ && kernel_->memory_range().Contains(address)) {
-    return kernel_;
-  }
-  return nullptr;
-}
-
-UserMemoryMapping* MappingTracker::FindUserMappingForAddress(
-    UniquePid upid,
-    uint64_t address) const {
-  if (auto* vm = user_memory_.Find(upid); vm) {
-    if (auto it = vm->Find(address); it != vm->end()) {
-      return it->second;
-    }
-  }
-
-  if (auto* delegates = jit_delegates_.Find(upid); delegates) {
-    if (auto it = delegates->Find(address); it != delegates->end()) {
-      return it->second->CreateMapping();
-    }
-  }
-
-  return nullptr;
-}
-
-std::vector<VirtualMemoryMapping*> MappingTracker::FindMappings(
-    base::StringView name,
-    const BuildId& build_id) const {
-  if (auto res = mappings_by_name_and_build_id_.Find({name, build_id});
-      res != nullptr) {
-    return *res;
-  }
-  return {};
-}
-
-VirtualMemoryMapping& MappingTracker::InternMemoryMapping(
-    CreateMappingParams params) {
-  if (auto* mapping = interned_mappings_.Find(params); mapping) {
-    return **mapping;
-  }
-
-  std::unique_ptr<VirtualMemoryMapping> mapping(
-      new VirtualMemoryMapping(context_, params));
-  interned_mappings_.Insert(std::move(params), mapping.get());
-  return AddMapping(std::move(mapping));
-}
-
-void MappingTracker::AddJitRange(UniquePid upid,
-                                 AddressRange jit_range,
-                                 JitDelegate* delegate) {
-  // TODO(carlscab): Deal with overlaps
-  jit_delegates_[upid].DeleteOverlapsAndEmplace(jit_range, delegate);
-  user_memory_[upid].ForOverlaps(
-      jit_range, [&](std::pair<const AddressRange, UserMemoryMapping*>& entry) {
-        PERFETTO_CHECK(jit_range.Contains(entry.first));
-        entry.second->SetJitDelegate(delegate);
-      });
-}
-
-}  // namespace trace_processor
-}  // namespace perfetto
diff --git a/src/trace_processor/importers/common/mapping_tracker.h b/src/trace_processor/importers/common/mapping_tracker.h
deleted file mode 100644
index 95dc355..0000000
--- a/src/trace_processor/importers/common/mapping_tracker.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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_MAPPING_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MAPPING_TRACKER_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <optional>
-#include <vector>
-
-#include "perfetto/ext/base/flat_hash_map.h"
-#include "perfetto/ext/base/hash.h"
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/virtual_memory_mapping.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Api used to forward frame interning requests for frames that fall in a
-// jitted memory region.
-// MappingTracker allows other trackers to register ranges of memory for
-// which they need to control when a new frame is created. Jitted code can
-// move in memory over time, so the same program counter might refer to
-// different functions at different point in time. MappingTracker does
-// not keep track of such moves but instead delegates the creation of jitted
-// frames to a delegate.
-class JitDelegate {
- public:
-  virtual ~JitDelegate();
-  // Forward frame interning request.
-  // Implementations are free to intern the frame as needed.
-  // Returns frame_id, and whether a new row as created or not.
-  virtual std::pair<FrameId, bool> InternFrame(
-      VirtualMemoryMapping* mapping,
-      uint64_t rel_pc,
-      base::StringView function_name) = 0;
-
-  // Simpleperf does not emit mmap events for jitted ranges (actually for non
-  // file backed executable mappings). So have a way to generate a mapping on
-  // the fly for FindMapping requests in a jitted region with no associated
-  // mapping.
-  virtual UserMemoryMapping* CreateMapping() = 0;
-};
-
-// Keeps track of all aspects relative to memory mappings.
-// This class keeps track of 3 types of mappings: UserMemoryMapping,
-// KernelMemoryMapping and others. The others are used to represent mapping
-// where we do not have enough information to determine what type of
-// mapping (user, kernel) we are dealing with. This is usually the case with
-// data sources that do not provide enough information about the mappings.
-//
-// TODO(carlscab): Hopefully we can slowly get rid of cases where these other
-// mappings are needed. The biggest blocker right now is determining the upid.
-// we could infer this from the actual samples that use said mapping (those
-// usually have a pid attached). So we would need to have a "fake" mapping that
-// actually materializes when we see a sample with a pid.
-//
-// ATTENTION: No overlaps allowed (for now). Eventually the order in which
-// mappings are create will matter as newer mappings will delete old ones.
-// This is how tools like linux perf behave, mmap event have a timestamp
-// associated and there are no "delete events" just new mmap events that
-// overlap (to be deleted) mappings.
-class MappingTracker {
- public:
-  explicit MappingTracker(TraceProcessorContext* context) : context_(context) {}
-
-  // Create a new kernel space mapping. Returned reference will be valid for the
-  // duration of this instance.
-  KernelMemoryMapping& CreateKernelMemoryMapping(CreateMappingParams params);
-
-  // Create a new user space mapping. Returned reference will be valid for the
-  // duration of this instance.
-  UserMemoryMapping& CreateUserMemoryMapping(UniquePid upid,
-                                             CreateMappingParams params);
-
-  // Create an "other" mapping. Returned reference will be valid for the
-  // duration of this instance.
-  VirtualMemoryMapping& InternMemoryMapping(CreateMappingParams params);
-
-  // Given an absolute address find the kernel mapping where this address
-  // belongs to. Returns `nullptr` if none is found.
-  KernelMemoryMapping* FindKernelMappingForAddress(uint64_t address) const;
-
-  // Given an absolute address find the user mapping where this address
-  // belongs to. Returns `nullptr` if none is found.
-  UserMemoryMapping* FindUserMappingForAddress(UniquePid upid,
-                                               uint64_t address) const;
-
-  std::vector<VirtualMemoryMapping*> FindMappings(
-      base::StringView name,
-      const BuildId& build_id) const;
-
-  // Marks a range of memory as containing jitted code.
-  // If the added region overlaps with other existing ranges the latter are all
-  // deleted.
-  // Jitted ranges will only be applied to UserMemoryMappings
-  void AddJitRange(UniquePid upid, AddressRange range, JitDelegate* delegate);
-
- private:
-  template <typename MappingImpl>
-  MappingImpl& AddMapping(std::unique_ptr<MappingImpl> mapping);
-
-  TraceProcessorContext* const context_;
-  base::FlatHashMap<MappingId, std::unique_ptr<VirtualMemoryMapping>>
-      mappings_by_id_;
-
-  base::FlatHashMap<CreateMappingParams,
-                    VirtualMemoryMapping*,
-                    CreateMappingParams::Hasher>
-      interned_mappings_;
-
-  struct NameAndBuildId {
-    base::StringView name;
-    std::optional<BuildId> build_id;
-
-    bool operator==(const NameAndBuildId& o) const {
-      return name == o.name && build_id == o.build_id;
-    }
-
-    bool operator!=(const NameAndBuildId& o) const { return !(*this == o); }
-
-    struct Hasher {
-      size_t operator()(const NameAndBuildId& o) const {
-        base::Hasher hasher;
-        hasher.Update(o.name);
-        if (o.build_id) {
-          hasher.Update(*o.build_id);
-        }
-        return static_cast<size_t>(hasher.digest());
-      }
-    };
-  };
-  base::FlatHashMap<NameAndBuildId,
-                    std::vector<VirtualMemoryMapping*>,
-                    NameAndBuildId::Hasher>
-      mappings_by_name_and_build_id_;
-
-  base::FlatHashMap<UniquePid, AddressRangeMap<UserMemoryMapping*>>
-      user_memory_;
-  AddressRangeMap<KernelMemoryMapping*> kernel_modules_;
-  KernelMemoryMapping* kernel_ = nullptr;
-
-  base::FlatHashMap<UniquePid, AddressRangeMap<JitDelegate*>> jit_delegates_;
-};
-
-}  // namespace trace_processor
-}  // namespace perfetto
-
-#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_MAPPING_TRACKER_H_
diff --git a/src/trace_processor/importers/common/stack_profile_tracker.cc b/src/trace_processor/importers/common/stack_profile_tracker.cc
index 799dc29..ad57523 100644
--- a/src/trace_processor/importers/common/stack_profile_tracker.cc
+++ b/src/trace_processor/importers/common/stack_profile_tracker.cc
@@ -16,18 +16,35 @@
 
 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
 
-#include <cstddef>
-#include <cstdint>
-
+#include "perfetto/ext/base/string_utils.h"
 #include "perfetto/ext/base/string_view.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/tables/profiler_tables_py.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "src/trace_processor/util/profiler_util.h"
+#include "src/trace_processor/util/stack_traces_util.h"
 
 namespace perfetto {
 namespace trace_processor {
 
+namespace {
+std::string CleanBuildId(base::StringView build_id) {
+  if (build_id.empty()) {
+    return build_id.ToStdString();
+  }
+  // If the build_id is 33 characters long, we assume it's a Breakpad debug
+  // identifier which is already in Hex and doesn't need conversion.
+  // TODO(b/148109467): Remove workaround once all active Chrome versions
+  // write raw bytes instead of a string as build_id.
+  if (util::IsHexModuleId(build_id)) {
+    return build_id.ToStdString();
+  }
+
+  return base::ToHex(build_id.data(), build_id.size());
+}
+
+}  // namespace
+
 std::vector<FrameId> StackProfileTracker::JavaFramesForName(
     NameInPackage name) const {
   if (const auto* frames = java_frames_for_name_.Find(name); frames) {
@@ -36,6 +53,50 @@
   return {};
 }
 
+std::vector<MappingId> StackProfileTracker::FindMappingRow(
+    StringId name,
+    StringId build_id) const {
+  if (const auto* mappings =
+          mappings_by_name_and_build_id_.Find(std::make_pair(name, build_id));
+      mappings) {
+    return *mappings;
+  }
+  return {};
+}
+
+std::vector<FrameId> StackProfileTracker::FindFrameIds(MappingId mapping_id,
+                                                       uint64_t rel_pc) const {
+  if (const auto* frames =
+          frame_by_mapping_and_rel_pc_.Find(std::make_pair(mapping_id, rel_pc));
+      frames) {
+    return *frames;
+  }
+  return {};
+}
+
+MappingId StackProfileTracker::InternMapping(
+    const CreateMappingParams& params) {
+  tables::StackProfileMappingTable::Row row;
+  row.build_id = InternBuildId(params.build_id);
+  row.exact_offset = static_cast<int64_t>(params.exact_offset);
+  row.start_offset = static_cast<int64_t>(params.start_offset);
+  row.start = static_cast<int64_t>(params.start);
+  row.end = static_cast<int64_t>(params.end);
+  row.load_bias = static_cast<int64_t>(params.load_bias);
+  row.name = context_->storage->InternString(params.name);
+
+  if (MappingId* id = mapping_unique_row_index_.Find(row); id) {
+    return *id;
+  }
+
+  MappingId mapping_id =
+      context_->storage->mutable_stack_profile_mapping_table()->Insert(row).id;
+  mapping_unique_row_index_.Insert(row, mapping_id);
+  mappings_by_name_and_build_id_[{row.name, row.build_id}].push_back(
+      mapping_id);
+  return mapping_id;
+}
+
 CallsiteId StackProfileTracker::InternCallsite(
     std::optional<CallsiteId> parent_callsite_id,
     FrameId frame_id,
@@ -52,12 +113,22 @@
   return callsite_id;
 }
 
-void StackProfileTracker::OnFrameCreated(FrameId frame_id) {
-  auto frame =
-      *context_->storage->stack_profile_frame_table().FindById(frame_id);
-  const MappingId mapping_id = frame.mapping();
-  const StringId name_id = frame.name();
-  const auto function_name = context_->storage->GetString(name_id);
+FrameId StackProfileTracker::InternFrame(MappingId mapping_id,
+                                         uint64_t rel_pc,
+                                         base::StringView function_name) {
+  tables::StackProfileFrameTable::Row row;
+  row.mapping = mapping_id;
+  row.rel_pc = static_cast<int64_t>(rel_pc);
+  row.name = context_->storage->InternString(function_name);
+
+  if (FrameId* id = frame_unique_row_index_.Find(row); id) {
+    return *id;
+  }
+
+  FrameId frame_id =
+      context_->storage->mutable_stack_profile_frame_table()->Insert(row).id;
+  frame_unique_row_index_.Insert(row, frame_id);
+  frame_by_mapping_and_rel_pc_[{mapping_id, rel_pc}].push_back(frame_id);
 
   if (function_name.find('.') != base::StringView::npos) {
     // Java frames always contain a '.'
@@ -68,14 +139,21 @@
     std::optional<std::string> package =
         PackageFromLocation(context_->storage.get(), mapping_name);
     if (package) {
-      NameInPackage nip{
-          name_id, context_->storage->InternString(base::StringView(*package))};
+      NameInPackage nip{row.name, context_->storage->InternString(
+                                      base::StringView(*package))};
       java_frames_for_name_[nip].push_back(frame_id);
     } else if (mapping_name.find("/memfd:") == 0) {
-      NameInPackage nip{name_id, context_->storage->InternString("memfd")};
+      NameInPackage nip{row.name, context_->storage->InternString("memfd")};
       java_frames_for_name_[nip].push_back(frame_id);
     }
   }
+
+  return frame_id;
+}
+
+StringId StackProfileTracker::InternBuildId(base::StringView build_id) {
+  return context_->storage->InternString(
+      base::StringView(CleanBuildId(build_id)));
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/common/stack_profile_tracker.h b/src/trace_processor/importers/common/stack_profile_tracker.h
index b018f74..a1067b8 100644
--- a/src/trace_processor/importers/common/stack_profile_tracker.h
+++ b/src/trace_processor/importers/common/stack_profile_tracker.h
@@ -20,11 +20,12 @@
 #include <cstdint>
 #include <optional>
 #include <tuple>
+#include <utility>
 #include <vector>
 
 #include "perfetto/ext/base/flat_hash_map.h"
 #include "perfetto/ext/base/hash.h"
-
+#include "perfetto/ext/base/string_view.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/tables/profiler_tables_py.h"
 
@@ -51,39 +52,64 @@
 
 class StackProfileTracker {
  public:
+  struct CreateMappingParams {
+    base::StringView build_id;
+    uint64_t exact_offset;
+    uint64_t start_offset;
+    uint64_t start;
+    uint64_t end;
+    uint64_t load_bias;
+    base::StringView name;
+  };
+
   explicit StackProfileTracker(TraceProcessorContext* context)
       : context_(context) {}
 
   std::vector<FrameId> JavaFramesForName(NameInPackage name) const;
+  std::vector<MappingId> FindMappingRow(StringId name, StringId build_id) const;
+  std::vector<FrameId> FindFrameIds(MappingId mapping_id,
+                                    uint64_t rel_pc) const;
 
+  MappingId InternMapping(const CreateMappingParams& params);
   CallsiteId InternCallsite(std::optional<CallsiteId> parent_callsite_id,
                             FrameId frame_id,
                             uint32_t depth);
-
-  void OnFrameCreated(FrameId frame_id);
+  FrameId InternFrame(MappingId mapping_id,
+                      uint64_t rel_pc,
+                      base::StringView function_name);
 
  private:
+  StringId InternBuildId(base::StringView build_id);
+
   TraceProcessorContext* const context_;
+  base::FlatHashMap<tables::StackProfileMappingTable::Row, MappingId>
+      mapping_unique_row_index_;
   base::FlatHashMap<tables::StackProfileCallsiteTable::Row, CallsiteId>
       callsite_unique_row_index_;
+  base::FlatHashMap<tables::StackProfileFrameTable::Row, FrameId>
+      frame_unique_row_index_;
 
-  struct FrameKey {
-    MappingId mapping_id;
-    uint64_t rel_pc;
-
-    bool operator==(const FrameKey& o) const {
-      return mapping_id == o.mapping_id && rel_pc == o.rel_pc;
+  struct MappingHasher {
+    size_t operator()(const std::pair<StringId, StringId>& o) const {
+      return static_cast<size_t>(
+          base::Hasher::Combine(o.first.raw_id(), o.second.raw_id()));
     }
-
-    bool operator!=(const FrameKey& o) const { return !(*this == o); }
-
-    struct Hasher {
-      size_t operator()(const FrameKey& o) const {
-        return static_cast<size_t>(
-            base::Hasher::Combine(o.mapping_id.value, o.rel_pc));
-      }
-    };
   };
+  base::FlatHashMap<std::pair<StringId, StringId>,
+                    std::vector<MappingId>,
+                    MappingHasher>
+      mappings_by_name_and_build_id_;
+
+  struct FrameHasher {
+    size_t operator()(const std::pair<MappingId, uint64_t>& o) const {
+      return static_cast<size_t>(
+          base::Hasher::Combine(o.first.value, o.second));
+    }
+  };
+  base::FlatHashMap<std::pair<MappingId, uint64_t>,
+                    std::vector<FrameId>,
+                    FrameHasher>
+      frame_by_mapping_and_rel_pc_;
 
   base::FlatHashMap<NameInPackage, std::vector<FrameId>, NameInPackage::Hasher>
       java_frames_for_name_;
diff --git a/src/trace_processor/importers/common/virtual_memory_mapping.cc b/src/trace_processor/importers/common/virtual_memory_mapping.cc
deleted file mode 100644
index 60166f59..0000000
--- a/src/trace_processor/importers/common/virtual_memory_mapping.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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/virtual_memory_mapping.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <optional>
-#include <string>
-#include <utility>
-
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/profiler_tables_py.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-
-MappingId CreateMapping(TraceProcessorContext* context,
-                        const CreateMappingParams& params) {
-  StringId build_id = context->storage->InternString(base::StringView(
-      params.build_id ? params.build_id->ToHex() : std::string()));
-  MappingId mapping_id =
-      context->storage->mutable_stack_profile_mapping_table()
-          ->Insert(
-              {build_id, static_cast<int64_t>(params.exact_offset),
-               static_cast<int64_t>(params.start_offset),
-               static_cast<int64_t>(params.memory_range.start()),
-               static_cast<int64_t>(params.memory_range.end()),
-               static_cast<int64_t>(params.load_bias),
-               context->storage->InternString(base::StringView(params.name))})
-          .id;
-
-  return mapping_id;
-}
-
-}  // namespace
-
-VirtualMemoryMapping::VirtualMemoryMapping(TraceProcessorContext* context,
-                                           CreateMappingParams params)
-    : context_(context),
-      mapping_id_(CreateMapping(context, params)),
-      memory_range_(params.memory_range),
-      offset_(params.exact_offset),
-      load_bias_(params.load_bias),
-      name_(std::move(params.name)),
-      build_id_(std::move(params.build_id)) {}
-
-VirtualMemoryMapping::~VirtualMemoryMapping() = default;
-
-KernelMemoryMapping::KernelMemoryMapping(TraceProcessorContext* context,
-                                         CreateMappingParams params)
-    : VirtualMemoryMapping(context, std::move(params)) {}
-
-KernelMemoryMapping::~KernelMemoryMapping() = default;
-
-UserMemoryMapping::UserMemoryMapping(TraceProcessorContext* context,
-                                     UniquePid upid,
-                                     CreateMappingParams params)
-    : VirtualMemoryMapping(context, std::move(params)), upid_(upid) {}
-
-UserMemoryMapping::~UserMemoryMapping() = default;
-
-FrameId VirtualMemoryMapping::InternFrame(uint64_t rel_pc,
-                                          base::StringView function_name) {
-  auto [frame_id, was_inserted] =
-      jit_delegate_ ? jit_delegate_->InternFrame(this, rel_pc, function_name)
-                    : InternFrameImpl(rel_pc, function_name);
-  if (was_inserted) {
-    frames_by_rel_pc_[rel_pc].push_back(frame_id);
-    context_->stack_profile_tracker->OnFrameCreated(frame_id);
-  }
-  return frame_id;
-}
-
-std::vector<FrameId> VirtualMemoryMapping::FindFrameIds(uint64_t rel_pc) const {
-  if (auto* res = frames_by_rel_pc_.Find(rel_pc); res != nullptr) {
-    return *res;
-  }
-  return {};
-}
-
-std::pair<FrameId, bool> VirtualMemoryMapping::InternFrameImpl(
-    uint64_t rel_pc,
-    base::StringView function_name) {
-  const FrameKey frame_key{rel_pc,
-                           context_->storage->InternString(function_name)};
-  if (FrameId* id = interned_frames_.Find(frame_key); id) {
-    return {*id, false};
-  }
-
-  const FrameId frame_id =
-      context_->storage->mutable_stack_profile_frame_table()
-          ->Insert(
-              {frame_key.name_id, mapping_id_, static_cast<int64_t>(rel_pc)})
-          .id;
-  interned_frames_.Insert(frame_key, frame_id);
-
-  return {frame_id, true};
-}
-
-}  // namespace trace_processor
-}  // namespace perfetto
diff --git a/src/trace_processor/importers/common/virtual_memory_mapping.h b/src/trace_processor/importers/common/virtual_memory_mapping.h
deleted file mode 100644
index 7b8ef58..0000000
--- a/src/trace_processor/importers/common/virtual_memory_mapping.h
+++ /dev/null
@@ -1,152 +0,0 @@
-
-/*
- * 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_VIRTUAL_MEMORY_MAPPING_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <optional>
-#include <string>
-#include <vector>
-
-#include "perfetto/ext/base/flat_hash_map.h"
-#include "perfetto/ext/base/hash.h"
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/create_mapping_params.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// TODO(carlscab): Reconsider whether jit is the best abstraction here. All we
-// really care is about mapping a `rel_pc` to a symbol (aka symbolization) and
-// whether is this is constant.
-class JitDelegate;
-
-// Represents a mapping in virtual memory.
-class VirtualMemoryMapping {
- public:
-  virtual ~VirtualMemoryMapping();
-  // Range of virtual memory this mapping covers.
-  AddressRange memory_range() const { return memory_range_; }
-  MappingId mapping_id() const { return mapping_id_; }
-  // This name could be the path of the underlying file mapped into memory.
-  const std::string& name() const { return name_; }
-  // For file mappings, this is the offset into the file for the first byte in
-  // the mapping
-  uint64_t offset() const { return offset_; }
-  // If the mapped file is an executable or shared library this will return the
-  // load bias, if known. Returns 0 otherwise.
-  uint64_t load_bias() const { return load_bias_; }
-  // If the mapped file is an executable or shared library this will return its
-  // build id, if known.
-  const std::optional<BuildId>& build_id() const { return build_id_; }
-
-  // Whether this maps to a region that holds jitted code.
-  bool is_jitted() const { return jit_delegate_ != nullptr; }
-
-  // Converts an absolute address into a relative one.
-  uint64_t ToRelativePc(uint64_t address) const {
-    return address - memory_range_.start() + offset_ + load_bias_;
-  }
-
-  // Creates a frame for the given `rel_pc`. Note that if the mapping
-  // `is_jitted()` same `rel_pc` values can return different mappings (as jitted
-  // functions can be created and deleted over time.) So for such mappings the
-  // returned `FrameId` should not be cached.
-  FrameId InternFrame(uint64_t rel_pc, base::StringView function_name);
-
-  // Returns all frames ever created in this mapping for the given `rel_pc`.
-  std::vector<FrameId> FindFrameIds(uint64_t rel_pc) const;
-
- protected:
-  VirtualMemoryMapping(TraceProcessorContext* context,
-                       CreateMappingParams params);
-
- private:
-  friend class MappingTracker;
-
-  std::pair<FrameId, bool> InternFrameImpl(uint64_t rel_pc,
-                                           base::StringView function_name);
-
-  void SetJitDelegate(JitDelegate* jit_delegate) {
-    jit_delegate_ = jit_delegate;
-  }
-
-  TraceProcessorContext* const context_;
-  const MappingId mapping_id_;
-  const AddressRange memory_range_;
-  const uint64_t offset_;
-  const uint64_t load_bias_;
-  const std::string name_;
-  std::optional<BuildId> const build_id_;
-  JitDelegate* jit_delegate_ = nullptr;
-
-  struct FrameKey {
-    uint64_t rel_pc;
-    // It doesn't seem to make too much sense to key on name, as for the same
-    // mapping and same rel_pc the name should always be the same. But who knows
-    // how producers behave.
-    StringId name_id;
-
-    bool operator==(const FrameKey& o) const {
-      return rel_pc == o.rel_pc && name_id == o.name_id;
-    }
-
-    struct Hasher {
-      size_t operator()(const FrameKey& k) const {
-        return static_cast<size_t>(
-            base::Hasher::Combine(k.rel_pc, k.name_id.raw_id()));
-      }
-    };
-  };
-  base::FlatHashMap<FrameKey, FrameId, FrameKey::Hasher> interned_frames_;
-  base::FlatHashMap<uint64_t, std::vector<FrameId>> frames_by_rel_pc_;
-};
-
-class KernelMemoryMapping : public VirtualMemoryMapping {
- public:
-  ~KernelMemoryMapping() override;
-
- private:
-  friend class MappingTracker;
-  KernelMemoryMapping(TraceProcessorContext* context,
-                      CreateMappingParams params);
-};
-
-class UserMemoryMapping : public VirtualMemoryMapping {
- public:
-  ~UserMemoryMapping() override;
-  UniquePid upid() const { return upid_; }
-
- private:
-  friend class MappingTracker;
-  UserMemoryMapping(TraceProcessorContext* context,
-                    UniquePid upid,
-                    CreateMappingParams params);
-
-  const UniquePid upid_;
-};
-
-}  // namespace trace_processor
-}  // namespace perfetto
-
-#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_VIRTUAL_MEMORY_MAPPING_H_
diff --git a/src/trace_processor/importers/perf/BUILD.gn b/src/trace_processor/importers/perf/BUILD.gn
index 960cd27..387468f 100644
--- a/src/trace_processor/importers/perf/BUILD.gn
+++ b/src/trace_processor/importers/perf/BUILD.gn
@@ -28,7 +28,6 @@
   ]
   deps = [
     "../../../../gn:default_deps",
-    "../../../../protos/perfetto/trace/profiling:zero",
     "../../importers/common",
     "../../importers/common:parser_types",
     "../../sorter",
@@ -48,8 +47,6 @@
     ":perf",
     "../../../../gn:default_deps",
     "../../../../gn:gtest_and_gmock",
-    "../../../../protos/perfetto/trace/profiling:zero",
     "../../../base",
-    "../../importers/common",
   ]
 }
diff --git a/src/trace_processor/importers/perf/perf_data_parser.cc b/src/trace_processor/importers/perf/perf_data_parser.cc
index bb79209..11a5a13 100644
--- a/src/trace_processor/importers/perf/perf_data_parser.cc
+++ b/src/trace_processor/importers/perf/perf_data_parser.cc
@@ -22,7 +22,6 @@
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/string_utils.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/perf/perf_data_reader.h"
 #include "src/trace_processor/importers/perf/perf_data_tracker.h"
@@ -59,8 +58,7 @@
 
   // First instruction pointer in the callchain should be from kernel space, so
   // it shouldn't be available in mappings.
-  if (context_->mapping_tracker->FindUserMappingForAddress(
-          *sample.pid, sample.callchain.front())) {
+  if (tracker_->FindMapping(*sample.pid, sample.callchain.front()).ok()) {
     context_->storage->IncrementStats(stats::perf_samples_skipped);
     return;
   }
@@ -72,22 +70,19 @@
 
   std::vector<FramesTable::Row> frame_rows;
   for (uint32_t i = 1; i < sample.callchain.size(); i++) {
-    UserMemoryMapping* mapping =
-        context_->mapping_tracker->FindUserMappingForAddress(
-            *sample.pid, sample.callchain[i]);
-    if (!mapping) {
+    auto mapping = tracker_->FindMapping(*sample.pid, sample.callchain[i]);
+    if (!mapping.ok()) {
       context_->storage->IncrementStats(stats::perf_samples_skipped);
       return;
     }
     FramesTable::Row new_row;
     std::string mock_name =
-        base::StackString<1024>(
-            "%" PRIu64, sample.callchain[i] - mapping->memory_range().start())
+        base::StackString<1024>("%" PRIu64,
+                                sample.callchain[i] - mapping->start)
             .ToStdString();
     new_row.name = context_->storage->InternString(mock_name.c_str());
-    new_row.mapping = mapping->mapping_id();
-    new_row.rel_pc =
-        static_cast<int64_t>(mapping->ToRelativePc(sample.callchain[i]));
+    new_row.mapping = mapping->id;
+    new_row.rel_pc = static_cast<int64_t>(sample.callchain[i] - mapping->start);
     frame_rows.push_back(new_row);
   }
 
diff --git a/src/trace_processor/importers/perf/perf_data_tokenizer.cc b/src/trace_processor/importers/perf/perf_data_tokenizer.cc
index 334148a..be1ec02 100644
--- a/src/trace_processor/importers/perf/perf_data_tokenizer.cc
+++ b/src/trace_processor/importers/perf/perf_data_tokenizer.cc
@@ -15,7 +15,6 @@
  */
 
 #include "src/trace_processor/importers/perf/perf_data_tokenizer.h"
-
 #include <cstdint>
 #include <cstring>
 #include <vector>
@@ -32,29 +31,9 @@
 #include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/util/status_macros.h"
 
-#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
-
 namespace perfetto {
 namespace trace_processor {
 namespace perf_importer {
-namespace {
-protos::pbzero::Profiling::CpuMode GetCpuMode(const perf_event_header& header) {
-  switch (header.misc & kPerfRecordMiscCpumodeMask) {
-    case PERF_RECORD_MISC_KERNEL:
-      return protos::pbzero::Profiling::MODE_KERNEL;
-    case PERF_RECORD_MISC_USER:
-      return protos::pbzero::Profiling::MODE_USER;
-    case PERF_RECORD_MISC_HYPERVISOR:
-      return protos::pbzero::Profiling::MODE_HYPERVISOR;
-    case PERF_RECORD_MISC_GUEST_KERNEL:
-      return protos::pbzero::Profiling::MODE_GUEST_KERNEL;
-    case PERF_RECORD_MISC_GUEST_USER:
-      return protos::pbzero::Profiling::MODE_GUEST_USER;
-    default:
-      return protos::pbzero::Profiling::MODE_UNKNOWN;
-  }
-}
-}  // namespace
 
 PerfDataTokenizer::PerfDataTokenizer(TraceProcessorContext* ctx)
     : context_(ctx),
@@ -145,7 +124,6 @@
                        sizeof(PerfDataTracker::Mmap2Record::Numeric));
         auto record = ParseMmap2Record(record_size);
         RETURN_IF_ERROR(record.status());
-        record->cpu_mode = GetCpuMode(ev_header);
         tracker_->PushMmap2Record(*record);
         break;
       }
diff --git a/src/trace_processor/importers/perf/perf_data_tracker.cc b/src/trace_processor/importers/perf/perf_data_tracker.cc
index c670258..0c9b209 100644
--- a/src/trace_processor/importers/perf/perf_data_tracker.cc
+++ b/src/trace_processor/importers/perf/perf_data_tracker.cc
@@ -15,53 +15,12 @@
  */
 
 #include "src/trace_processor/importers/perf/perf_data_tracker.h"
-
-#include <optional>
-
 #include "perfetto/base/status.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
-#include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/storage/stats.h"
-#include "src/trace_processor/storage/trace_storage.h"
-
-#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
 
 namespace perfetto {
 namespace trace_processor {
 namespace perf_importer {
-namespace {
-
-bool IsInKernel(protos::pbzero::Profiling::CpuMode cpu_mode) {
-  switch (cpu_mode) {
-    case protos::pbzero::Profiling::MODE_UNKNOWN:
-      PERFETTO_CHECK(false);
-    case protos::pbzero::Profiling::MODE_GUEST_KERNEL:
-    case protos::pbzero::Profiling::MODE_KERNEL:
-      return true;
-    case protos::pbzero::Profiling::MODE_USER:
-    case protos::pbzero::Profiling::MODE_HYPERVISOR:
-    case protos::pbzero::Profiling::MODE_GUEST_USER:
-      return false;
-  }
-  PERFETTO_CHECK(false);
-}
-
-CreateMappingParams BuildCreateMappingParams(
-    PerfDataTracker::Mmap2Record record) {
-  return {AddressRange::FromStartAndSize(record.num.addr, record.num.len),
-          record.num.pgoff,
-          // start_offset: This is the offset into the file where the ELF header
-          // starts. We assume all file mappings are ELF files an thus this
-          // offset is 0.
-          0,
-          // load_bias: This can only be read out of the actual ELF file, which
-          // we do not have here, so we set it to 0. When symbolizing we will
-          // hopefully have the real load bias and we can compensate there for a
-          // possible mismatch.
-          0, record.filename, std::nullopt};
-}
-}  // namespace
 
 PerfDataTracker::~PerfDataTracker() = default;
 
@@ -89,15 +48,31 @@
 }
 
 void PerfDataTracker::PushMmap2Record(Mmap2Record record) {
-  if (IsInKernel(record.cpu_mode)) {
-    context_->mapping_tracker->CreateKernelMemoryMapping(
-        BuildCreateMappingParams(std::move(record)));
-  } else {
-    UniquePid upid =
-        context_->process_tracker->GetOrCreateProcess(record.num.pid);
-    context_->mapping_tracker->CreateUserMemoryMapping(
-        upid, BuildCreateMappingParams(std::move(record)));
+  const auto mappings =
+      context_->storage->mutable_stack_profile_mapping_table();
+  MappingTable::Row row;
+  row.start = static_cast<int64_t>(record.num.addr);
+  row.end = static_cast<int64_t>(record.num.addr + record.num.len);
+  row.name = context_->storage->InternString(record.filename.c_str());
+  MappingTable::Id id = mappings->Insert(row).id;
+  MmapRange mmap2_range{record.num.addr, record.num.addr + record.num.len, id};
+  mmap2_ranges_[record.num.pid].push_back(mmap2_range);
+}
+
+base::StatusOr<PerfDataTracker::MmapRange> PerfDataTracker::FindMapping(
+    uint32_t pid,
+    uint64_t ips) {
+  auto vec = mmap2_ranges_.Find(pid);
+  if (!vec) {
+    return base::ErrStatus("Sample pid not found in mappings.");
   }
+
+  for (const auto& range : *vec) {
+    if (ips >= range.start && ips < range.end) {
+      return range;
+    }
+  }
+  return base::ErrStatus("No mapping for callstack frame instruction pointer");
 }
 
 base::StatusOr<PerfDataTracker::PerfSample> PerfDataTracker::ParseSample(
diff --git a/src/trace_processor/importers/perf/perf_data_tracker.h b/src/trace_processor/importers/perf/perf_data_tracker.h
index 11258ed..0ab99aa 100644
--- a/src/trace_processor/importers/perf/perf_data_tracker.h
+++ b/src/trace_processor/importers/perf/perf_data_tracker.h
@@ -25,7 +25,6 @@
 #include "perfetto/ext/base/flat_hash_map.h"
 #include "perfetto/ext/base/status_or.h"
 #include "perfetto/ext/base/string_utils.h"
-#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
 #include "src/trace_processor/importers/perf/perf_data_reader.h"
 #include "src/trace_processor/importers/perf/perf_event.h"
 #include "src/trace_processor/storage/trace_storage.h"
@@ -77,10 +76,14 @@
       uint32_t prot;
       uint32_t flags;
     };
-    protos::pbzero::Profiling::CpuMode cpu_mode;
     Numeric num;
     std::string filename;
   };
+  struct MmapRange {
+    uint64_t start;
+    uint64_t end;
+    MappingTable::Id id;
+  };
 
   PerfDataTracker(const PerfDataTracker&) = delete;
   PerfDataTracker& operator=(const PerfDataTracker&) = delete;
@@ -100,11 +103,14 @@
   base::StatusOr<PerfSample> ParseSample(
       perfetto::trace_processor::perf_importer::Reader&);
 
+  base::StatusOr<MmapRange> FindMapping(uint32_t pid, uint64_t ips);
+
  private:
   const perf_event_attr* FindAttrWithId(uint64_t id) const;
   TraceProcessorContext* context_;
   std::vector<AttrAndIds> attrs_;
 
+  base::FlatHashMap</*pid=*/uint32_t, std::vector<MmapRange>> mmap2_ranges_;
   uint64_t common_sample_type_;
 };
 }  // namespace perf_importer
diff --git a/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc b/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc
index 3cbdc80..6c59be6 100644
--- a/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc
+++ b/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc
@@ -22,35 +22,16 @@
 #include <vector>
 
 #include "perfetto/base/build_config.h"
-#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
-#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
 #include "src/trace_processor/importers/perf/perf_event.h"
 #include "test/gtest_and_gmock.h"
 
 namespace perfetto {
 namespace trace_processor {
 namespace perf_importer {
-namespace {
 
-class PerfDataTrackerUnittest : public testing::Test {
- public:
-  PerfDataTrackerUnittest() {
-    context_.storage = std::make_unique<TraceStorage>();
-    context_.process_tracker = std::make_unique<ProcessTracker>(&context_);
-    context_.stack_profile_tracker =
-        std::make_unique<StackProfileTracker>(&context_);
-    context_.mapping_tracker = std::make_unique<MappingTracker>(&context_);
-  }
-
- protected:
-  TraceProcessorContext context_;
-};
-
-TEST_F(PerfDataTrackerUnittest, ComputeCommonSampleType) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, ComputeCommonSampleType) {
+  TraceProcessorContext context;
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::AttrAndIds attr_and_ids;
   attr_and_ids.attr.sample_type =
@@ -65,15 +46,16 @@
   EXPECT_FALSE(tracker->common_sample_type() & PERF_SAMPLE_CALLCHAIN);
 }
 
-TEST_F(PerfDataTrackerUnittest, FindMapping) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, FindMapping) {
+  TraceProcessorContext context;
+  context.storage = std::make_unique<TraceStorage>();
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::Mmap2Record rec;
   rec.filename = "file1";
   rec.num.addr = 1000;
   rec.num.len = 100;
   rec.num.pid = 1;
-  rec.cpu_mode = protos::pbzero::Profiling::MODE_USER;
   tracker->PushMmap2Record(rec);
 
   rec.num.addr = 2000;
@@ -82,33 +64,32 @@
   rec.num.addr = 3000;
   tracker->PushMmap2Record(rec);
 
-  UserMemoryMapping* mapping =
-      context_.mapping_tracker->FindUserMappingForAddress(
-          context_.process_tracker->GetOrCreateProcess(1), 2050);
-  ASSERT_NE(mapping, nullptr);
-  EXPECT_EQ(mapping->memory_range().start(), 2000u);
-  EXPECT_EQ(mapping->memory_range().end(), 2100u);
+  auto res_status = tracker->FindMapping(1, 2050);
+  EXPECT_TRUE(res_status.ok());
+  EXPECT_EQ(res_status->start, 2000u);
+  EXPECT_EQ(res_status->end, 2100u);
 }
 
-TEST_F(PerfDataTrackerUnittest, FindMappingFalse) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, FindMappingFalse) {
+  TraceProcessorContext context;
+  context.storage = std::make_unique<TraceStorage>();
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::Mmap2Record rec;
   rec.filename = "file1";
   rec.num.addr = 1000;
   rec.num.len = 100;
   rec.num.pid = 1;
-  rec.cpu_mode = protos::pbzero::Profiling::MODE_USER;
   tracker->PushMmap2Record(rec);
 
-  UserMemoryMapping* mapping =
-      context_.mapping_tracker->FindUserMappingForAddress(
-          context_.process_tracker->GetOrCreateProcess(2), 2050);
-  EXPECT_EQ(mapping, nullptr);
+  auto res_status = tracker->FindMapping(2, 2050);
+  EXPECT_FALSE(res_status.ok());
 }
 
-TEST_F(PerfDataTrackerUnittest, ParseSampleTrivial) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, ParseSampleTrivial) {
+  TraceProcessorContext context;
+  context.storage = std::make_unique<TraceStorage>();
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::AttrAndIds attr_and_ids;
   attr_and_ids.attr.sample_type = PERF_SAMPLE_TIME;
@@ -126,8 +107,10 @@
   EXPECT_EQ(parsed_sample->ts, 100u);
 }
 
-TEST_F(PerfDataTrackerUnittest, ParseSampleCallchain) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, ParseSampleCallchain) {
+  TraceProcessorContext context;
+  context.storage = std::make_unique<TraceStorage>();
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::AttrAndIds attr_and_ids;
   attr_and_ids.attr.sample_type = PERF_SAMPLE_CALLCHAIN;
@@ -154,8 +137,10 @@
   EXPECT_EQ(parsed_sample->callchain.size(), 3u);
 }
 
-TEST_F(PerfDataTrackerUnittest, ParseSampleWithoutId) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, ParseSampleWithoutId) {
+  TraceProcessorContext context;
+  context.storage = std::make_unique<TraceStorage>();
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::AttrAndIds attr_and_ids;
   attr_and_ids.attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
@@ -192,8 +177,10 @@
   EXPECT_EQ(sample.ts, parsed_sample->ts);
 }
 
-TEST_F(PerfDataTrackerUnittest, ParseSampleWithId) {
-  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context_);
+TEST(PerfDataTrackerUnittest, ParseSampleWithId) {
+  TraceProcessorContext context;
+  context.storage = std::make_unique<TraceStorage>();
+  PerfDataTracker* tracker = PerfDataTracker::GetOrCreate(&context);
 
   PerfDataTracker::AttrAndIds attr_and_ids;
   attr_and_ids.attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_TID |
@@ -235,7 +222,6 @@
   EXPECT_EQ(100u, parsed_sample->ts);
 }
 
-}  // namespace
 }  // namespace perf_importer
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/perf/perf_event.h b/src/trace_processor/importers/perf/perf_event.h
index c60709f..53f5f05 100644
--- a/src/trace_processor/importers/perf/perf_event.h
+++ b/src/trace_processor/importers/perf/perf_event.h
@@ -223,15 +223,4 @@
   PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
 };
 
-constexpr auto kPerfRecordMiscCpumodeMask = 0x7;
-
-enum perf_record_misc {
-  PERF_RECORD_MISC_CPUMODE_UNKNOWN = 0,
-  PERF_RECORD_MISC_KERNEL = 1,
-  PERF_RECORD_MISC_USER = 2,
-  PERF_RECORD_MISC_HYPERVISOR = 3,
-  PERF_RECORD_MISC_GUEST_KERNEL = 4,
-  PERF_RECORD_MISC_GUEST_USER = 5,
-};
-
 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PERF_PERF_EVENT_H_
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 2e542d0..2eaa5fe 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -91,9 +91,9 @@
     "../../storage",
     "../../tables",
     "../../types",
-    "../../util:build_id",
     "../../util:gzip",
     "../../util:profiler_util",
+    "../../util:stack_traces_util",
     "../common",
     "../common:parser_types",
     "../ftrace:minimal",
@@ -181,6 +181,7 @@
     "../../util:profiler_util",
     "../../util:proto_profiler",
     "../../util:proto_to_args_parser",
+    "../../util:stack_traces_util",
     "../common",
     "../common:parser_types",
     "../etw:full",
@@ -275,6 +276,7 @@
     "../../types",
     "../../util:descriptors",
     "../../util:profiler_util",
+    "../../util:stack_traces_util",
     "../common",
     "../ftrace:full",
   ]
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index b80cae7..61596d3 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -24,7 +24,6 @@
 #include "src/trace_processor/importers/common/clock_tracker.h"
 #include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
 #include "src/trace_processor/importers/common/event_tracker.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
@@ -37,8 +36,8 @@
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/tables/profiler_tables_py.h"
 #include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
 #include "src/trace_processor/util/profiler_util.h"
+#include "src/trace_processor/util/stack_traces_util.h"
 
 #include "protos/perfetto/common/builtin_clock.pbzero.h"
 #include "protos/perfetto/common/perf_events.pbzero.h"
@@ -429,11 +428,19 @@
 
 void ProfileModule::ParseModuleSymbols(ConstBytes blob) {
   protos::pbzero::ModuleSymbols::Decoder module_symbols(blob.data, blob.size);
-  BuildId build_id = BuildId::FromRaw(module_symbols.build_id());
+  StringId build_id;
+  // TODO(b/148109467): Remove workaround once all active Chrome versions
+  // write raw bytes instead of a string as build_id.
+  if (util::IsHexModuleId(module_symbols.build_id())) {
+    build_id = context_->storage->InternString(module_symbols.build_id());
+  } else {
+    build_id = context_->storage->InternString(base::StringView(base::ToHex(
+        module_symbols.build_id().data, module_symbols.build_id().size)));
+  }
 
-  auto mappings =
-      context_->mapping_tracker->FindMappings(module_symbols.path(), build_id);
-  if (mappings.empty()) {
+  auto mapping_ids = context_->stack_profile_tracker->FindMappingRow(
+      context_->storage->InternString(module_symbols.path()), build_id);
+  if (mapping_ids.empty()) {
     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
     return;
   }
@@ -460,11 +467,12 @@
       continue;
     }
     bool frame_found = false;
-    for (VirtualMemoryMapping* mapping : mappings) {
+    for (MappingId mapping_id : mapping_ids) {
       context_->args_translation_table->AddNativeSymbolTranslationRule(
-          mapping->mapping_id(), address_symbols.address(), last_location);
+          mapping_id, address_symbols.address(), last_location);
       std::vector<FrameId> frame_ids =
-          mapping->FindFrameIds(address_symbols.address());
+          context_->stack_profile_tracker->FindFrameIds(
+              mapping_id, address_symbols.address());
 
       for (const FrameId frame_id : frame_ids) {
         auto* frames = context_->storage->mutable_stack_profile_frame_table();
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
index 31841fc..9d889ef 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
@@ -19,8 +19,6 @@
 #include "perfetto/base/flat_set.h"
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
@@ -30,7 +28,6 @@
 #include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -71,16 +68,17 @@
 
 void ProfilePacketSequenceState::AddMapping(SourceMappingId id,
                                             const SourceMapping& mapping) {
-  CreateMappingParams params;
+  StackProfileTracker::CreateMappingParams params;
   if (std::string* str = strings_.Find(mapping.build_id); str) {
-    params.build_id = BuildId::FromRaw(*str);
+    params.build_id = base::StringView(*str);
   } else {
     context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
     return;
   }
   params.exact_offset = mapping.exact_offset;
   params.start_offset = mapping.start_offset;
-  params.memory_range = AddressRange(mapping.start, mapping.end);
+  params.start = mapping.start;
+  params.end = mapping.end;
   params.load_bias = mapping.load_bias;
 
   std::vector<base::StringView> path_components;
@@ -95,16 +93,16 @@
       break;
     }
   }
-
-  params.name = ProfilePacketUtils::MakeMappingName(path_components);
-  mappings_.Insert(
-      id, &context_->mapping_tracker->InternMemoryMapping(std::move(params)));
+  std::string path = ProfilePacketUtils::MakeMappingName(path_components);
+  params.name = base::StringView(path);
+  MappingId mapping_id = context_->stack_profile_tracker->InternMapping(params);
+  mappings_.Insert(id, mapping_id);
 }
 
 void ProfilePacketSequenceState::AddFrame(SourceFrameId id,
                                           const SourceFrame& frame) {
-  VirtualMemoryMapping** mapping = mappings_.Find(frame.mapping_id);
-  if (!mapping) {
+  MappingId* mapping_id = mappings_.Find(frame.mapping_id);
+  if (!mapping_id) {
     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
     return;
   }
@@ -115,8 +113,9 @@
     return;
   }
 
-  FrameId frame_id =
-      (*mapping)->InternFrame(frame.rel_pc, base::StringView(*function_name));
+  FrameId frame_id = context_->stack_profile_tracker->InternFrame(
+      *mapping_id, frame.rel_pc, base::StringView(*function_name));
+
   frames_.Insert(id, frame_id);
 }
 
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.h b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
index 99661da..678aab2 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
@@ -23,6 +23,7 @@
 
 #include "perfetto/ext/base/hash.h"
 #include "perfetto/ext/base/string_view.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
 #include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
 #include "src/trace_processor/storage/trace_storage.h"
@@ -30,8 +31,6 @@
 namespace perfetto {
 namespace trace_processor {
 
-class VirtualMemoryMapping;
-
 // Keeps sequence specific state for profile packets.
 class ProfilePacketSequenceState final
     : public PacketSequenceStateGeneration::InternedDataTracker {
@@ -127,7 +126,7 @@
   TraceProcessorContext* const context_;
 
   base::FlatHashMap<SourceStringId, std::string> strings_;
-  base::FlatHashMap<SourceMappingId, VirtualMemoryMapping*> mappings_;
+  base::FlatHashMap<SourceMappingId, MappingId> mappings_;
   base::FlatHashMap<SourceFrameId, FrameId> frames_;
   base::FlatHashMap<SourceCallstackId, CallsiteId> callstacks_;
 
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
index c9cd6e3..ab947fa 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
@@ -18,9 +18,8 @@
 
 #include <memory>
 
-#include "src/trace_processor/importers/common/mapping_tracker.h"
-#include "src/trace_processor/importers/common/stack_profile_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 #include "test/gtest_and_gmock.h"
 
@@ -59,7 +58,6 @@
  public:
   HeapProfileTrackerDupTest() {
     context.storage.reset(new TraceStorage());
-    context.mapping_tracker.reset(new MappingTracker(&context));
     context.stack_profile_tracker.reset(new StackProfileTracker(&context));
     packet_sequence_state.reset(new PacketSequenceState(&context));
 
@@ -198,7 +196,6 @@
 TEST(HeapProfileTrackerTest, SourceMappingPath) {
   TraceProcessorContext context;
   context.storage.reset(new TraceStorage());
-  context.mapping_tracker.reset(new MappingTracker(&context));
   context.stack_profile_tracker.reset(new StackProfileTracker(&context));
   PacketSequenceState pss(&context);
   ProfilePacketSequenceState& ppss =
@@ -232,7 +229,6 @@
 TEST(HeapProfileTrackerTest, Functional) {
   TraceProcessorContext context;
   context.storage.reset(new TraceStorage());
-  context.mapping_tracker.reset(new MappingTracker(&context));
   context.stack_profile_tracker.reset(new StackProfileTracker(&context));
 
   PacketSequenceState pss(&context);
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index e612709..11a45f5 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -25,7 +25,6 @@
 #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/mapping_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/slice_tracker.h"
@@ -253,7 +252,6 @@
     context_.track_tracker.reset(new TrackTracker(&context_));
     context_.global_args_tracker.reset(
         new GlobalArgsTracker(context_.storage.get()));
-    context_.mapping_tracker.reset(new MappingTracker(&context_));
     context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
     context_.args_tracker.reset(new ArgsTracker(&context_));
     context_.args_translation_table.reset(new ArgsTranslationTable(storage_));
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.cc b/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
index a469f92..e503a09 100644
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
@@ -23,8 +23,6 @@
 #include "perfetto/ext/base/string_view.h"
 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "src/trace_processor/importers/common/address_range.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
@@ -32,7 +30,6 @@
 #include "src/trace_processor/storage/stats.h"
 #include "src/trace_processor/storage/trace_storage.h"
 #include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/build_id.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -51,23 +48,21 @@
 
 std::optional<MappingId> StackProfileSequenceState::FindOrInsertMapping(
     uint64_t iid) {
-  if (VirtualMemoryMapping* mapping = FindOrInsertMappingImpl(iid); mapping) {
-    return mapping->mapping_id();
-  }
-  return std::nullopt;
-}
-
-VirtualMemoryMapping* StackProfileSequenceState::FindOrInsertMappingImpl(
-    uint64_t iid) {
-  if (auto ptr = cached_mappings_.Find(iid); ptr) {
-    return *ptr;
+  if (MappingId* id = cached_mappings_.Find(iid); id) {
+    return *id;
   }
   auto* decoder =
       LookupInternedMessage<protos::pbzero::InternedData::kMappingsFieldNumber,
                             protos::pbzero::Mapping>(iid);
   if (!decoder) {
     context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
-    return nullptr;
+    return std::nullopt;
+  }
+
+  std::optional<base::StringView> build_id =
+      LookupInternedBuildId(decoder->build_id());
+  if (!build_id) {
+    return std::nullopt;
   }
 
   std::vector<base::StringView> path_components;
@@ -80,26 +75,19 @@
     }
     path_components.push_back(*str);
   }
+  std::string path = ProfilePacketUtils::MakeMappingName(path_components);
 
-  CreateMappingParams params;
-  std::optional<base::StringView> build_id =
-      LookupInternedBuildId(decoder->build_id());
-  if (!build_id) {
-    return nullptr;
-  }
-  params.build_id = BuildId::FromRaw(*build_id);
-
-  params.memory_range = AddressRange(decoder->start(), decoder->end());
+  StackProfileTracker::CreateMappingParams params;
+  params.build_id = *build_id;
   params.exact_offset = decoder->exact_offset();
   params.start_offset = decoder->start_offset();
+  params.start = decoder->start();
+  params.end = decoder->end();
   params.load_bias = decoder->load_bias();
-  params.name = ProfilePacketUtils::MakeMappingName(path_components);
-
-  VirtualMemoryMapping& mapping =
-      context_->mapping_tracker->InternMemoryMapping(std::move(params));
-
-  cached_mappings_.Insert(iid, &mapping);
-  return &mapping;
+  params.name = base::StringView(path);
+  MappingId mapping_id = context_->stack_profile_tracker->InternMapping(params);
+  cached_mappings_.Insert(iid, mapping_id);
+  return mapping_id;
 }
 
 std::optional<base::StringView>
@@ -122,6 +110,11 @@
 
 std::optional<base::StringView>
 StackProfileSequenceState::LookupInternedMappingPath(uint64_t iid) {
+  // This should really be an error (value not set) or at the very least return
+  // a null string, but for backward compatibility use an empty string instead.
+  if (iid == 0) {
+    return "";
+  }
   auto* decoder = LookupInternedMessage<
       protos::pbzero::InternedData::kMappingPathsFieldNumber,
       protos::pbzero::InternedString>(iid);
@@ -165,7 +158,7 @@
 
   cached_callstacks_.Insert(iid, *parent_callsite_id);
 
-  return parent_callsite_id;
+  return *parent_callsite_id;
 }
 
 std::optional<FrameId> StackProfileSequenceState::FindOrInsertFrame(
@@ -181,9 +174,9 @@
     return std::nullopt;
   }
 
-  VirtualMemoryMapping* mapping =
-      FindOrInsertMappingImpl(decoder->mapping_id());
-  if (!mapping) {
+  std::optional<MappingId> mapping_id =
+      FindOrInsertMapping(decoder->mapping_id());
+  if (!mapping_id) {
     return std::nullopt;
   }
 
@@ -197,7 +190,9 @@
     function_name = *func;
   }
 
-  FrameId frame_id = mapping->InternFrame(decoder->rel_pc(), function_name);
+  FrameId frame_id = context_->stack_profile_tracker->InternFrame(
+      *mapping_id, decoder->rel_pc(), function_name);
+
   cached_frames_.Insert(iid, frame_id);
 
   return frame_id;
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.h b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
index 82de785..7a7879a 100644
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.h
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
@@ -30,7 +30,6 @@
 namespace trace_processor {
 
 class TraceProcessorContext;
-class VirtualMemoryMapping;
 
 class StackProfileSequenceState final
     : public PacketSequenceStateGeneration::InternedDataTracker {
@@ -45,15 +44,13 @@
   std::optional<CallsiteId> FindOrInsertCallstack(uint64_t iid);
 
  private:
-  // Returns `nullptr`if non could be found.
-  VirtualMemoryMapping* FindOrInsertMappingImpl(uint64_t iid);
   std::optional<base::StringView> LookupInternedBuildId(uint64_t iid);
   std::optional<base::StringView> LookupInternedMappingPath(uint64_t iid);
   std::optional<base::StringView> LookupInternedFunctionName(uint64_t iid);
   std::optional<FrameId> FindOrInsertFrame(uint64_t iid);
 
   TraceProcessorContext* const context_;
-  base::FlatHashMap<uint64_t, VirtualMemoryMapping*> cached_mappings_;
+  base::FlatHashMap<uint64_t, MappingId> cached_mappings_;
   base::FlatHashMap<uint64_t, CallsiteId> cached_callstacks_;
   base::FlatHashMap<uint64_t, FrameId> cached_frames_;
 };
diff --git a/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn
index 2e5f02f..f69eafd 100644
--- a/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/slices/BUILD.gn
@@ -16,6 +16,7 @@
 
 perfetto_sql_source_set("slices") {
   sources = [
+    "cpu_time.sql",
     "flat_slices.sql",
     "slices.sql",
     "with_context.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql b/src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql
new file mode 100644
index 0000000..4a36d9c
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/slices/cpu_time.sql
@@ -0,0 +1,72 @@
+--
+-- Copyright 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
+--
+--     https://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.
+
+-- TODO(mayzner): Replace with good implementation of interval intersect.
+CREATE PERFETTO MACRO _interval_intersect_partition_utid(
+  left_table TableOrSubquery,
+  right_table TableOrSubquery
+)
+RETURNS TableOrSubquery AS
+(
+  WITH on_left AS (
+    SELECT
+      B.ts,
+      IIF(
+        A.ts + A.dur <= B.ts + B.dur,
+        A.ts + A.dur - B.ts, B.dur) AS dur,
+      A.id AS left_id,
+      B.id as right_id
+    FROM $left_table A
+    JOIN $right_table B ON (A.ts <= B.ts AND A.ts + A.dur > B.ts AND A.utid = B.utid)
+  ), on_right AS (
+    SELECT
+      B.ts,
+      IIF(
+        A.ts + A.dur <= B.ts + B.dur,
+        A.ts + A.dur - B.ts, B.dur) AS dur,
+      B.id as left_id,
+      A.id AS right_id
+    FROM $right_table A
+    -- The difference between this table and on_left is the lack of equality on
+    -- A.ts <= B.ts. This is to remove the issue of double accounting
+    -- timestamps that start at the same time.
+    JOIN $left_table B ON (A.ts < B.ts AND A.ts + A.dur > B.ts AND A.utid = B.utid)
+  )
+  SELECT * FROM on_left
+  UNION ALL
+  SELECT * FROM on_right
+);
+
+-- Time each thread slice spent running on CPU.
+-- Requires scheduling data to be available in the trace.
+CREATE PERFETTO TABLE thread_slice_cpu_time(
+    -- Slice id.
+    id INT,
+    -- Duration of the time the slice was running.
+    cpu_time INT) AS
+WITH slice_with_utid AS (
+  SELECT
+      slice.id,
+      slice.ts,
+      slice.dur,
+      utid
+  FROM slice
+  JOIN thread_track ON slice.track_id = thread_track.id
+  JOIN thread USING (utid)
+  WHERE utid != 0)
+SELECT left_id AS id, SUM(dur) AS cpu_time
+FROM _interval_intersect_partition_utid!(slice_with_utid, sched)
+GROUP BY 1
+ORDER BY 1;
\ No newline at end of file
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index 2ee7b3d..908fdea 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -27,7 +27,6 @@
 #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/mapping_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/sched_event_tracker.h"
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index b0c7a15..1f06a0f 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -26,7 +26,6 @@
 #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/mapping_tracker.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/importers/common/process_tracker.h"
 #include "src/trace_processor/importers/common/sched_event_tracker.h"
@@ -65,7 +64,6 @@
   context_.process_tracker.reset(new ProcessTracker(&context_));
   context_.clock_tracker.reset(new ClockTracker(&context_));
   context_.clock_converter.reset(new ClockConverter(&context_));
-  context_.mapping_tracker.reset(new MappingTracker(&context_));
   context_.perf_sample_tracker.reset(new PerfSampleTracker(&context_));
   context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
   context_.metadata_tracker.reset(new MetadataTracker(context_.storage.get()));
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index 26d1ff5..3b3336c 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -55,7 +55,6 @@
 class StackProfileTracker;
 class HeapGraphTracker;
 class PerfSampleTracker;
-class MappingTracker;
 class MetadataTracker;
 class PacketAnalyzer;
 class ProtoImporterModule;
@@ -103,7 +102,6 @@
   std::unique_ptr<SchedEventTracker> sched_event_tracker;
   std::unique_ptr<ClockTracker> clock_tracker;
   std::unique_ptr<ClockConverter> clock_converter;
-  std::unique_ptr<MappingTracker> mapping_tracker;
   std::unique_ptr<PerfSampleTracker> perf_sample_tracker;
   std::unique_ptr<StackProfileTracker> stack_profile_tracker;
   std::unique_ptr<MetadataTracker> metadata_tracker;
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 13aefe5..8420a06 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -61,17 +61,6 @@
   }
 }
 
-source_set("build_id") {
-  sources = [
-    "build_id.cc",
-    "build_id.h",
-  ]
-  deps = [
-    "../../../gn:default_deps",
-    "../../../include/perfetto/ext/base:base",
-  ]
-}
-
 source_set("profiler_util") {
   sources = [
     "profiler_util.cc",
@@ -85,6 +74,18 @@
   ]
 }
 
+source_set("stack_traces_util") {
+  sources = [
+    "stack_traces_util.cc",
+    "stack_traces_util.h",
+  ]
+  deps = [
+    "../../../gn:default_deps",
+    "../../../include/perfetto/ext/base:base",
+    "../../../protos/perfetto/trace/profiling:zero",
+  ]
+}
+
 source_set("protozero_to_text") {
   sources = [
     "protozero_to_text.cc",
diff --git a/src/trace_processor/util/build_id.cc b/src/trace_processor/util/build_id.cc
deleted file mode 100644
index 889291d..0000000
--- a/src/trace_processor/util/build_id.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2023 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/util/build_id.h"
-
-#include <cctype>
-#include <cstddef>
-#include <string>
-
-#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/string_utils.h"
-#include "perfetto/ext/base/string_view.h"
-
-namespace perfetto {
-namespace trace_processor {
-namespace {
-uint8_t HexToBinary(char c) {
-  switch (c) {
-    case '0':
-      return 0;
-    case '1':
-      return 1;
-    case '2':
-      return 2;
-    case '3':
-      return 3;
-    case '4':
-      return 4;
-    case '5':
-      return 5;
-    case '6':
-      return 6;
-    case '7':
-      return 7;
-    case '8':
-      return 8;
-    case '9':
-      return 9;
-    case 'a':
-    case 'A':
-      return 10;
-    case 'b':
-    case 'B':
-      return 11;
-    case 'c':
-    case 'C':
-      return 12;
-    case 'd':
-    case 'D':
-      return 13;
-    case 'e':
-    case 'E':
-      return 14;
-    case 'f':
-    case 'F':
-      return 15;
-    default:
-      PERFETTO_CHECK(false);
-  }
-}
-
-std::string HexToBinary(base::StringView hex) {
-  std::string res;
-  res.reserve((hex.size() + 1) / 2);
-  auto it = hex.begin();
-
-  if (hex.size() % 2 != 0) {
-    res.push_back(static_cast<char>(HexToBinary(*it)));
-    ++it;
-  }
-
-  while (it != hex.end()) {
-    int v = (HexToBinary(*it++) << 4);
-    v += HexToBinary(*it++);
-    res.push_back(static_cast<char>(v));
-  }
-  return res;
-}
-
-bool IsHex(base::StringView module) {
-  for (char c : module) {
-    if (!std::isxdigit(c)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-// Returns whether this string is of a hex chrome module or not to decide
-// whether to convert the module to/from hex.
-// TODO(b/148109467): Remove workaround once all active Chrome versions
-// write raw bytes instead of a string as build_id.
-bool IsHexModuleId(base::StringView module) {
-  return module.size() == 33 && IsHex(module);
-}
-
-}  // namespace
-
-// static
-BuildId BuildId::FromHex(base::StringView data) {
-  if (IsHexModuleId(data)) {
-    return BuildId(data.ToStdString());
-  }
-  return BuildId(HexToBinary(data));
-}
-
-std::string BuildId::ToHex() const {
-  if (IsHexModuleId(base::StringView(raw_))) {
-    return raw_;
-  }
-  return base::ToHex(raw_.data(), raw_.size());
-}
-
-}  // namespace trace_processor
-}  // namespace perfetto
diff --git a/src/trace_processor/util/build_id.h b/src/trace_processor/util/build_id.h
deleted file mode 100644
index 64ec9ac..0000000
--- a/src/trace_processor/util/build_id.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_UTIL_BUILD_ID_H_
-#define SRC_TRACE_PROCESSOR_UTIL_BUILD_ID_H_
-
-#include <string>
-#include <utility>
-
-#include "perfetto/ext/base/hash.h"
-#include "perfetto/ext/base/string_view.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Represents the unique identifier of an executable, shared library, or module.
-// For example for ELF files this is the id stored in the .note.gnu.build-id
-// section. Sometimes a breakpad module id is used.
-// This class abstracts away the details of where this id comes from and how it
-// is converted to a StringId which is the representation used by tables in
-// trace_processor.
-class BuildId {
- public:
-  // Allow hashing with base::Hash.
-  static constexpr bool kHashable = true;
-  size_t size() const { return raw_.size(); }
-  const char* data() const { return raw_.data(); }
-
-  static BuildId FromHex(base::StringView data);
-
-  static BuildId FromRaw(base::StringView data) {
-    return BuildId(data.ToStdString());
-  }
-  static BuildId FromRaw(std::string data) { return BuildId(std::move(data)); }
-  static BuildId FromRaw(const uint8_t* data, size_t size) {
-    return BuildId(std::string(reinterpret_cast<const char*>(data), size));
-  }
-
-  BuildId(const BuildId&) = default;
-  BuildId(BuildId&&) = default;
-
-  BuildId& operator=(const BuildId&) = default;
-  BuildId& operator=(BuildId&&) = default;
-
-  bool operator==(const BuildId& o) const { return raw_ == o.raw_; }
-
-  bool operator!=(const BuildId& o) const { return !(*this == o); }
-
-  bool operator<(const BuildId& o) const { return raw_ < o.raw_; }
-
-  std::string ToHex() const;
-
-  const std::string& raw() const { return raw_; }
-
- private:
-  explicit BuildId(std::string data) : raw_(std::move(data)) {}
-  std::string raw_;
-};
-
-}  // namespace trace_processor
-}  // namespace perfetto
-
-template <>
-struct std::hash<perfetto::trace_processor::BuildId> {
-  std::size_t operator()(
-      const perfetto::trace_processor::BuildId& o) const noexcept {
-    return perfetto::base::Hasher::Combine(o);
-  }
-};
-
-#endif  // SRC_TRACE_PROCESSOR_UTIL_BUILD_ID_H_
diff --git a/src/trace_processor/util/stack_traces_util.cc b/src/trace_processor/util/stack_traces_util.cc
new file mode 100644
index 0000000..a255560
--- /dev/null
+++ b/src/trace_processor/util/stack_traces_util.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 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/util/stack_traces_util.h"
+#include "perfetto/ext/base/string_view.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace util {
+
+bool IsHexModuleId(base::StringView module) {
+  return module.size() == 33;
+}
+
+}  // namespace util
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/util/stack_traces_util.h b/src/trace_processor/util/stack_traces_util.h
new file mode 100644
index 0000000..1171786
--- /dev/null
+++ b/src/trace_processor/util/stack_traces_util.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_UTIL_STACK_TRACES_UTIL_H_
+#define SRC_TRACE_PROCESSOR_UTIL_STACK_TRACES_UTIL_H_
+
+#include "perfetto/ext/base/string_view.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace util {
+
+// Returns whether this string is of a hex chrome module or not to decide
+// whether to convert the module to/from hex.
+// TODO(b/148109467): Remove workaround once all active Chrome versions
+// write raw bytes instead of a string as build_id.
+bool IsHexModuleId(base::StringView module);
+
+}  // namespace util
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_UTIL_STACK_TRACES_UTIL_H_
diff --git a/src/trace_redaction/trace_redactor_integrationtest.cc b/src/trace_redaction/trace_redactor_integrationtest.cc
index 8f14744..50074b1 100644
--- a/src/trace_redaction/trace_redactor_integrationtest.cc
+++ b/src/trace_redaction/trace_redactor_integrationtest.cc
@@ -23,6 +23,7 @@
 #include "perfetto/base/status.h"
 #include "perfetto/ext/base/file_utils.h"
 #include "perfetto/ext/base/temp_file.h"
+#include "src/base/test/tmp_dir_tree.h"
 #include "src/base/test/utils.h"
 #include "src/trace_redaction/find_package_uid.h"
 #include "src/trace_redaction/prune_package_list.h"
@@ -54,13 +55,10 @@
  protected:
   void SetUp() override {
     src_trace_ = base::GetTestDataPath(std::string(kTracePath));
-    dest_trace_ = std::make_unique<base::TempFile>(base::TempFile::Create());
   }
 
   const std::string& src_trace() const { return src_trace_; }
 
-  const std::string& dest_trace() const { return dest_trace_->path(); }
-
   std::vector<protozero::ConstBytes> GetPackageInfos(
       const Trace::Decoder& trace) const {
     std::vector<protozero::ConstBytes> infos;
@@ -79,9 +77,8 @@
     return infos;
   }
 
- private:
   std::string src_trace_;
-  std::unique_ptr<base::TempFile> dest_trace_;
+  base::TmpDirTree tmp_dir_;
 };
 
 TEST_F(TraceRedactorIntegrationTest, FindsPackageAndFiltersPackageList) {
@@ -92,12 +89,15 @@
   Context context;
   context.package_name = "com.Unity.com.unity.multiplayer.samples.coop";
 
-  auto result = redaction.Redact(src_trace(), dest_trace(), &context);
+  auto result = redaction.Redact(
+      src_trace(), tmp_dir_.AbsolutePath("dst.pftrace"), &context);
+  tmp_dir_.TrackFile("dst.pftrace");
 
   ASSERT_TRUE(result.ok()) << result.message();
 
   std::string redacted_buffer;
-  ASSERT_TRUE(base::ReadFile(dest_trace(), &redacted_buffer));
+  ASSERT_TRUE(
+      base::ReadFile(tmp_dir_.AbsolutePath("dst.pftrace"), &redacted_buffer));
 
   Trace::Decoder redacted_trace(redacted_buffer);
   std::vector<protozero::ConstBytes> infos = GetPackageInfos(redacted_trace);
@@ -139,11 +139,14 @@
   Context context;
   context.package_name = "com.google.android.networkstack.tethering";
 
-  auto result = redaction.Redact(src_trace(), dest_trace(), &context);
+  auto result = redaction.Redact(
+      src_trace(), tmp_dir_.AbsolutePath("dst.pftrace"), &context);
+  tmp_dir_.TrackFile("dst.pftrace");
   ASSERT_TRUE(result.ok()) << result.message();
 
   std::string redacted_buffer;
-  ASSERT_TRUE(base::ReadFile(dest_trace(), &redacted_buffer));
+  ASSERT_TRUE(
+      base::ReadFile(tmp_dir_.AbsolutePath("dst.pftrace"), &redacted_buffer));
 
   Trace::Decoder redacted_trace(redacted_buffer);
   std::vector<protozero::ConstBytes> infos = GetPackageInfos(redacted_trace);
diff --git a/test/trace_processor/diff_tests/stdlib/slices/tests.py b/test/trace_processor/diff_tests/stdlib/slices/tests.py
index e3db459..053dabf 100644
--- a/test/trace_processor/diff_tests/stdlib/slices/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/slices/tests.py
@@ -91,4 +91,28 @@
         "ThreadControllerImpl::RunTask",174796099970797,186000,0
         "Looper.dispatch: jy3(null)",174800056530797,1368000,0
         "ThreadControllerImpl::RunTask",174800107962797,132000,0
-      """))
\ No newline at end of file
+      """))
+
+  def test_thread_slice_cpu_time(self):
+    return DiffTestBlueprint(
+        trace=DataPath('example_android_trace_30s.pb'),
+        query="""
+        INCLUDE PERFETTO MODULE slices.cpu_time;
+
+        SELECT *
+        FROM thread_slice_cpu_time
+        LIMIT 10;
+        """,
+        out=Csv("""
+        "id","cpu_time"
+        0,178646
+        1,119740
+        2,58073
+        3,98698
+        4,121979
+        5,45000
+        6,35104
+        7,33333
+        8,46926
+        9,17865
+        """))
\ No newline at end of file