| // Copyright 2020 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_TRACE_EVENT_INTERNED_ARGS_HELPER_H_ | 
 | #define BASE_TRACE_EVENT_INTERNED_ARGS_HELPER_H_ | 
 |  | 
 | #include "base/base_export.h" | 
 | #include "base/containers/span.h" | 
 | #include "base/hash/hash.h" | 
 | #include "base/location.h" | 
 | #include "base/profiler/module_cache.h" | 
 | #include "base/trace_event/trace_event.h" | 
 | #include "third_party/abseil-cpp/absl/types/optional.h" | 
 | #include "third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h" | 
 | #include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h" | 
 |  | 
 | namespace base { | 
 | namespace trace_event { | 
 |  | 
 | // TrackEventInternedDataIndex expects the same data structure to be used for | 
 | // all interned fields with the same field number. We can't use base::Location | 
 | // for log event's location since base::Location uses program counter based | 
 | // location. | 
 | struct BASE_EXPORT TraceSourceLocation { | 
 |   const char* function_name = nullptr; | 
 |   const char* file_name = nullptr; | 
 |   int line_number = 0; | 
 |  | 
 |   TraceSourceLocation() = default; | 
 |   TraceSourceLocation(const char* function_name, | 
 |                       const char* file_name, | 
 |                       int line_number) | 
 |       : function_name(function_name), | 
 |         file_name(file_name), | 
 |         line_number(line_number) {} | 
 |   // Construct a new source location from an existing base::Location, the only | 
 |   // attributes that are read are |function_name|, |file_name| and | 
 |   // |line_number|. | 
 |   explicit TraceSourceLocation(const base::Location& location) | 
 |       : function_name(location.function_name()), | 
 |         file_name(location.file_name()), | 
 |         line_number(location.line_number()) {} | 
 |  | 
 |   bool operator==(const TraceSourceLocation& other) const { | 
 |     return file_name == other.file_name && | 
 |            function_name == other.function_name && | 
 |            line_number == other.line_number; | 
 |   } | 
 | }; | 
 |  | 
 | // Data structure for constructing an interned | 
 | // perfetto.protos.UnsymbolizedSourceLocation proto message. | 
 | struct BASE_EXPORT UnsymbolizedSourceLocation { | 
 |   uint64_t mapping_id = 0; | 
 |   uint64_t rel_pc = 0; | 
 |  | 
 |   UnsymbolizedSourceLocation() = default; | 
 |   UnsymbolizedSourceLocation(uint64_t mapping_id, uint64_t rel_pc) | 
 |       : mapping_id(mapping_id), rel_pc(rel_pc) {} | 
 |  | 
 |   bool operator==(const UnsymbolizedSourceLocation& other) const { | 
 |     return mapping_id == other.mapping_id && rel_pc == other.rel_pc; | 
 |   } | 
 | }; | 
 |  | 
 | }  // namespace trace_event | 
 | }  // namespace base | 
 |  | 
 | namespace std { | 
 |  | 
 | template <> | 
 | struct hash<base::trace_event::TraceSourceLocation> { | 
 |   std::size_t operator()( | 
 |       const base::trace_event::TraceSourceLocation& loc) const { | 
 |     return base::HashInts( | 
 |         base::HashInts(reinterpret_cast<uintptr_t>(loc.file_name), | 
 |                        reinterpret_cast<uintptr_t>(loc.function_name)), | 
 |         static_cast<size_t>(loc.line_number)); | 
 |   } | 
 | }; | 
 |  | 
 | template <> | 
 | struct hash<base::trace_event::UnsymbolizedSourceLocation> { | 
 |   std::size_t operator()( | 
 |       const base::trace_event::UnsymbolizedSourceLocation& module) const { | 
 |     return base::HashInts(module.mapping_id, module.rel_pc); | 
 |   } | 
 | }; | 
 |  | 
 | }  // namespace std | 
 |  | 
 | namespace base { | 
 | namespace trace_event { | 
 |  | 
 | struct BASE_EXPORT InternedSourceLocation | 
 |     : public perfetto::TrackEventInternedDataIndex< | 
 |           InternedSourceLocation, | 
 |           perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, | 
 |           TraceSourceLocation> { | 
 |   static void Add(perfetto::protos::pbzero::InternedData* interned_data, | 
 |                   size_t iid, | 
 |                   const TraceSourceLocation& location); | 
 |   using perfetto::TrackEventInternedDataIndex< | 
 |       InternedSourceLocation, | 
 |       perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, | 
 |       TraceSourceLocation>::Get; | 
 |   static size_t Get(perfetto::EventContext* ctx, const Location& location) { | 
 |     return perfetto::TrackEventInternedDataIndex< | 
 |         InternedSourceLocation, | 
 |         perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, | 
 |         TraceSourceLocation>::Get(ctx, TraceSourceLocation(location)); | 
 |   } | 
 | }; | 
 |  | 
 | struct BASE_EXPORT InternedLogMessage | 
 |     : public perfetto::TrackEventInternedDataIndex< | 
 |           InternedLogMessage, | 
 |           perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber, | 
 |           std::string> { | 
 |   static void Add(perfetto::protos::pbzero::InternedData* interned_data, | 
 |                   size_t iid, | 
 |                   const std::string& log_message); | 
 | }; | 
 |  | 
 | struct BASE_EXPORT InternedBuildId | 
 |     : public perfetto::TrackEventInternedDataIndex< | 
 |           InternedBuildId, | 
 |           perfetto::protos::pbzero::InternedData::kBuildIdsFieldNumber, | 
 |           std::string> { | 
 |   static void Add(perfetto::protos::pbzero::InternedData* interned_data, | 
 |                   size_t iid, | 
 |                   const std::string& build_id); | 
 | }; | 
 |  | 
 | struct BASE_EXPORT InternedMappingPath | 
 |     : public perfetto::TrackEventInternedDataIndex< | 
 |           InternedMappingPath, | 
 |           perfetto::protos::pbzero::InternedData::kMappingPathsFieldNumber, | 
 |           std::string> { | 
 |   static void Add(perfetto::protos::pbzero::InternedData* interned_data, | 
 |                   size_t iid, | 
 |                   const std::string& mapping_path); | 
 | }; | 
 |  | 
 | struct BASE_EXPORT InternedMapping | 
 |     : public perfetto::TrackEventInternedDataIndex< | 
 |           InternedMapping, | 
 |           perfetto::protos::pbzero::InternedData::kMappingsFieldNumber, | 
 |           const base::ModuleCache::Module*> { | 
 |   // We need a custom implementation here to plumb EventContext to Add. | 
 |   static size_t Get(perfetto::EventContext* ctx, | 
 |                     const base::ModuleCache::Module* module); | 
 |   static void Add(perfetto::EventContext* ctx, | 
 |                   size_t iid, | 
 |                   const base::ModuleCache::Module* module); | 
 | }; | 
 |  | 
 | // Interns an unsymbolized source code location + all it's "dependencies", i.e. | 
 | // module, strings used in the module definition, and so on. | 
 | struct BASE_EXPORT InternedUnsymbolizedSourceLocation | 
 |     : public perfetto::TrackEventInternedDataIndex< | 
 |           InternedUnsymbolizedSourceLocation, | 
 |           perfetto::protos::pbzero::InternedData:: | 
 |               kUnsymbolizedSourceLocationsFieldNumber, | 
 |           uintptr_t> { | 
 |   // We need a custom Get implementation to use ModuleCache, and to return | 
 |   // a nullopt if a module for the given address cannot be found. | 
 |   static absl::optional<size_t> Get(perfetto::EventContext* ctx, | 
 |                                     uintptr_t address); | 
 |   static void Add(perfetto::protos::pbzero::InternedData* interned_data, | 
 |                   size_t iid, | 
 |                   const UnsymbolizedSourceLocation& location); | 
 |  | 
 |  private: | 
 |   // This implies that a module cache lifetime = incremental state. | 
 |   // We don't want unlimited lifetime because it keeps modules pinned in | 
 |   // memory on some platforms (Windows). | 
 |   // TODO(b/237055179): Consider tying module cache to DataSource instead so | 
 |   // that the cache is not unnecessarily cleared on incremental state change. | 
 |   base::ModuleCache module_cache_; | 
 | }; | 
 |  | 
 | }  // namespace trace_event | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_TRACE_EVENT_INTERNED_ARGS_HELPER_H_ |