Merge "Move protolog_viewer_config parsing to TokenizePacket" into main
diff --git a/src/trace_processor/importers/common/mapping_tracker.cc b/src/trace_processor/importers/common/mapping_tracker.cc
index 02976f9..6e6fbf3 100644
--- a/src/trace_processor/importers/common/mapping_tracker.cc
+++ b/src/trace_processor/importers/common/mapping_tracker.cc
@@ -25,6 +25,7 @@
 #include "perfetto/ext/base/string_view.h"
 #include "src/trace_processor/importers/common/address_range.h"
 #include "src/trace_processor/importers/common/jit_cache.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"
@@ -161,14 +162,15 @@
       });
 }
 
-VirtualMemoryMapping* MappingTracker::GetDummyMapping() {
-  if (!dummy_mapping_) {
-    CreateMappingParams params;
-    params.memory_range =
-        AddressRange::FromStartAndSize(0, std::numeric_limits<uint64_t>::max());
-    dummy_mapping_ = &InternMemoryMapping(params);
-  }
-  return dummy_mapping_;
+DummyMemoryMapping& MappingTracker::CreateDummyMapping(std::string name) {
+  CreateMappingParams params;
+  params.name = std::move(name);
+  params.memory_range =
+      AddressRange::FromStartAndSize(0, std::numeric_limits<uint64_t>::max());
+  std::unique_ptr<DummyMemoryMapping> mapping(
+      new DummyMemoryMapping(context_, std::move(params)));
+
+  return AddMapping(std::move(mapping));
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/common/mapping_tracker.h b/src/trace_processor/importers/common/mapping_tracker.h
index 4791dba..c655d57 100644
--- a/src/trace_processor/importers/common/mapping_tracker.h
+++ b/src/trace_processor/importers/common/mapping_tracker.h
@@ -68,6 +68,10 @@
   UserMemoryMapping& CreateUserMemoryMapping(UniquePid upid,
                                              CreateMappingParams params);
 
+  // Sometimes we just need a mapping and we are lacking trace data to create a
+  // proper one. Use this mapping in those cases.
+  DummyMemoryMapping& CreateDummyMapping(std::string name);
+
   // Create an "other" mapping. Returned reference will be valid for the
   // duration of this instance.
   VirtualMemoryMapping& InternMemoryMapping(CreateMappingParams params);
@@ -91,10 +95,6 @@
   // Jitted ranges will only be applied to UserMemoryMappings
   void AddJitRange(UniquePid upid, AddressRange range, JitCache* jit_cache);
 
-  // Sometimes we just need a mapping and we are lacking trace data to create a
-  // proper one. Use this mapping in those cases.
-  VirtualMemoryMapping* GetDummyMapping();
-
  private:
   template <typename MappingImpl>
   MappingImpl& AddMapping(std::unique_ptr<MappingImpl> mapping);
@@ -140,8 +140,6 @@
   KernelMemoryMapping* kernel_ = nullptr;
 
   base::FlatHashMap<UniquePid, AddressRangeMap<JitCache*>> jit_caches_;
-
-  VirtualMemoryMapping* dummy_mapping_ = nullptr;
 };
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/common/virtual_memory_mapping.cc b/src/trace_processor/importers/common/virtual_memory_mapping.cc
index 0485243..99aa23b 100644
--- a/src/trace_processor/importers/common/virtual_memory_mapping.cc
+++ b/src/trace_processor/importers/common/virtual_memory_mapping.cc
@@ -23,6 +23,7 @@
 #include <string>
 #include <utility>
 
+#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/jit_cache.h"
@@ -119,5 +120,39 @@
   return {frame_id, true};
 }
 
+DummyMemoryMapping::~DummyMemoryMapping() = default;
+
+DummyMemoryMapping::DummyMemoryMapping(TraceProcessorContext* context,
+                                       CreateMappingParams params)
+    : VirtualMemoryMapping(context, std::move(params)) {}
+
+FrameId DummyMemoryMapping::InternDummyFrame(base::StringView function_name,
+                                             base::StringView source_file) {
+  DummyFrameKey key{context()->storage->InternString(function_name),
+                    context()->storage->InternString(source_file)};
+
+  if (FrameId* id = interned_dummy_frames_.Find(key); id) {
+    return *id;
+  }
+
+  uint32_t symbol_set_id = context()->storage->symbol_table().row_count();
+
+  tables::SymbolTable::Id symbol_id =
+      context()
+          ->storage->mutable_symbol_table()
+          ->Insert({symbol_set_id, key.function_name_id, key.source_file_id})
+          .id;
+
+  PERFETTO_CHECK(symbol_set_id == symbol_id.value);
+
+  const FrameId frame_id = context()
+                               ->storage->mutable_stack_profile_frame_table()
+                               ->Insert({key.function_name_id, mapping_id(), 0})
+                               .id;
+  interned_dummy_frames_.Insert(key, frame_id);
+
+  return frame_id;
+}
+
 }  // 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
index 498a9ef..1676437 100644
--- a/src/trace_processor/importers/common/virtual_memory_mapping.h
+++ b/src/trace_processor/importers/common/virtual_memory_mapping.h
@@ -86,6 +86,8 @@
   VirtualMemoryMapping(TraceProcessorContext* context,
                        CreateMappingParams params);
 
+  TraceProcessorContext* context() const { return context_; }
+
  private:
   friend class MappingTracker;
 
@@ -149,6 +151,42 @@
   const UniquePid upid_;
 };
 
+// Dummy mapping to be able to create frames when we have no real pc addresses
+// or real mappings.
+class DummyMemoryMapping : public VirtualMemoryMapping {
+ public:
+  ~DummyMemoryMapping() override;
+
+  // Interns a frame based solely on function name and source file. This is
+  // useful for profilers that do not emit an address nor a mapping.
+  FrameId InternDummyFrame(base::StringView function_name,
+                           base::StringView source_file);
+
+ private:
+  friend class MappingTracker;
+  DummyMemoryMapping(TraceProcessorContext* context,
+                     CreateMappingParams params);
+
+  struct DummyFrameKey {
+    StringId function_name_id;
+    StringId source_file_id;
+
+    bool operator==(const DummyFrameKey& o) const {
+      return function_name_id == o.function_name_id &&
+             source_file_id == o.source_file_id;
+    }
+
+    struct Hasher {
+      size_t operator()(const DummyFrameKey& k) const {
+        return static_cast<size_t>(base::Hasher::Combine(
+            k.function_name_id.raw_id(), k.source_file_id.raw_id()));
+      }
+    };
+  };
+  base::FlatHashMap<DummyFrameKey, FrameId, DummyFrameKey::Hasher>
+      interned_dummy_frames_;
+};
+
 }  // namespace trace_processor
 }  // namespace perfetto
 
diff --git a/src/trace_processor/importers/perf/record_parser.cc b/src/trace_processor/importers/perf/record_parser.cc
index a63a5bd..0b0d169 100644
--- a/src/trace_processor/importers/perf/record_parser.cc
+++ b/src/trace_processor/importers/perf/record_parser.cc
@@ -225,7 +225,7 @@
       context_->storage->IncrementStats(stats::perf_dummy_mapping_used);
       // Simpleperf will not create mappings for anonymous executable mappings
       // which are used by JITted code (e.g. V8 JavaScript).
-      mapping = mapping_tracker_->GetDummyMapping();
+      mapping = GetDummyMapping(upid);
     }
 
     const FrameId frame_id =
@@ -346,4 +346,14 @@
   return base::OkStatus();
 }
 
+DummyMemoryMapping* RecordParser::GetDummyMapping(UniquePid upid) {
+  if (auto it = dummy_mappings_.Find(upid); it) {
+    return *it;
+  }
+
+  DummyMemoryMapping* mapping = &mapping_tracker_->CreateDummyMapping("");
+  dummy_mappings_.Insert(upid, mapping);
+  return mapping;
+}
+
 }  // namespace perfetto::trace_processor::perf_importer
diff --git a/src/trace_processor/importers/perf/record_parser.h b/src/trace_processor/importers/perf/record_parser.h
index 76926d1..6230845 100644
--- a/src/trace_processor/importers/perf/record_parser.h
+++ b/src/trace_processor/importers/perf/record_parser.h
@@ -22,6 +22,7 @@
 #include <optional>
 
 #include "perfetto/base/status.h"
+#include "perfetto/ext/base/flat_hash_map.h"
 #include "src/trace_processor/importers/common/trace_parser.h"
 #include "src/trace_processor/importers/perf/mmap_record.h"
 #include "src/trace_processor/importers/perf/record.h"
@@ -31,6 +32,7 @@
 namespace perfetto {
 namespace trace_processor {
 
+class DummyMemoryMapping;
 class MappingTracker;
 class TraceProcessorContext;
 
@@ -66,8 +68,11 @@
 
   UniquePid GetUpid(const CommonMmapRecordFields& fields) const;
 
-  TraceProcessorContext* const context_ = nullptr;
+  DummyMemoryMapping* GetDummyMapping(UniquePid upid);
+
+  TraceProcessorContext* const context_;
   MappingTracker* const mapping_tracker_;
+  base::FlatHashMap<UniquePid, DummyMemoryMapping*> dummy_mappings_;
 };
 
 }  // namespace perf_importer