1 // Copyright 2020 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TRACE_EVENT_INTERNED_ARGS_HELPER_H_ 6 #define BASE_TRACE_EVENT_INTERNED_ARGS_HELPER_H_ 7 8 #include <optional> 9 #include <string> 10 11 #include "base/base_export.h" 12 #include "base/containers/span.h" 13 #include "base/hash/hash.h" 14 #include "base/location.h" 15 #include "base/profiler/module_cache.h" 16 #include "base/trace_event/trace_event.h" 17 #include "build/build_config.h" 18 #include "third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h" 19 #include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h" 20 21 namespace base { 22 namespace trace_event { 23 24 // TrackEventInternedDataIndex expects the same data structure to be used for 25 // all interned fields with the same field number. We can't use base::Location 26 // for log event's location since base::Location uses program counter based 27 // location. 28 struct BASE_EXPORT TraceSourceLocation { 29 const char* function_name = nullptr; 30 const char* file_name = nullptr; 31 int line_number = 0; 32 33 TraceSourceLocation() = default; TraceSourceLocationTraceSourceLocation34 TraceSourceLocation(const char* function_name, 35 const char* file_name, 36 int line_number) 37 : function_name(function_name), 38 file_name(file_name), 39 line_number(line_number) {} 40 // Construct a new source location from an existing base::Location, the only 41 // attributes that are read are |function_name|, |file_name| and 42 // |line_number|. TraceSourceLocationTraceSourceLocation43 explicit TraceSourceLocation(const base::Location& location) 44 : function_name(location.function_name()), 45 file_name(location.file_name()), 46 line_number(location.line_number()) {} 47 48 bool operator==(const TraceSourceLocation& other) const { 49 return file_name == other.file_name && 50 function_name == other.function_name && 51 line_number == other.line_number; 52 } 53 }; 54 55 // Data structure for constructing an interned 56 // perfetto.protos.UnsymbolizedSourceLocation proto message. 57 struct BASE_EXPORT UnsymbolizedSourceLocation { 58 uint64_t mapping_id = 0; 59 uint64_t rel_pc = 0; 60 61 UnsymbolizedSourceLocation() = default; UnsymbolizedSourceLocationUnsymbolizedSourceLocation62 UnsymbolizedSourceLocation(uint64_t mapping_id, uint64_t rel_pc) 63 : mapping_id(mapping_id), rel_pc(rel_pc) {} 64 65 bool operator==(const UnsymbolizedSourceLocation& other) const { 66 return mapping_id == other.mapping_id && rel_pc == other.rel_pc; 67 } 68 }; 69 70 } // namespace trace_event 71 } // namespace base 72 73 namespace std { 74 75 template <> 76 struct hash<base::trace_event::TraceSourceLocation> { 77 std::size_t operator()( 78 const base::trace_event::TraceSourceLocation& loc) const { 79 return base::HashInts( 80 base::HashInts(reinterpret_cast<uintptr_t>(loc.file_name), 81 reinterpret_cast<uintptr_t>(loc.function_name)), 82 static_cast<size_t>(loc.line_number)); 83 } 84 }; 85 86 template <> 87 struct hash<base::trace_event::UnsymbolizedSourceLocation> { 88 std::size_t operator()( 89 const base::trace_event::UnsymbolizedSourceLocation& module) const { 90 return base::HashInts(module.mapping_id, module.rel_pc); 91 } 92 }; 93 94 } // namespace std 95 96 namespace base { 97 namespace trace_event { 98 99 struct BASE_EXPORT InternedSourceLocation 100 : public perfetto::TrackEventInternedDataIndex< 101 InternedSourceLocation, 102 perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, 103 TraceSourceLocation> { 104 static void Add(perfetto::protos::pbzero::InternedData* interned_data, 105 size_t iid, 106 const TraceSourceLocation& location); 107 using perfetto::TrackEventInternedDataIndex< 108 InternedSourceLocation, 109 perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, 110 TraceSourceLocation>::Get; 111 static size_t Get(perfetto::EventContext* ctx, const Location& location) { 112 return perfetto::TrackEventInternedDataIndex< 113 InternedSourceLocation, 114 perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, 115 TraceSourceLocation>::Get(ctx, TraceSourceLocation(location)); 116 } 117 }; 118 119 struct BASE_EXPORT InternedLogMessage 120 : public perfetto::TrackEventInternedDataIndex< 121 InternedLogMessage, 122 perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber, 123 std::string> { 124 static void Add(perfetto::protos::pbzero::InternedData* interned_data, 125 size_t iid, 126 const std::string& log_message); 127 }; 128 129 struct BASE_EXPORT InternedBuildId 130 : public perfetto::TrackEventInternedDataIndex< 131 InternedBuildId, 132 perfetto::protos::pbzero::InternedData::kBuildIdsFieldNumber, 133 std::string> { 134 static void Add(perfetto::protos::pbzero::InternedData* interned_data, 135 size_t iid, 136 const std::string& build_id); 137 }; 138 139 struct BASE_EXPORT InternedMappingPath 140 : public perfetto::TrackEventInternedDataIndex< 141 InternedMappingPath, 142 perfetto::protos::pbzero::InternedData::kMappingPathsFieldNumber, 143 std::string> { 144 static void Add(perfetto::protos::pbzero::InternedData* interned_data, 145 size_t iid, 146 const std::string& mapping_path); 147 }; 148 149 struct BASE_EXPORT InternedMapping 150 : public perfetto::TrackEventInternedDataIndex< 151 InternedMapping, 152 perfetto::protos::pbzero::InternedData::kMappingsFieldNumber, 153 const base::ModuleCache::Module*> { 154 // We need a custom implementation here to plumb EventContext to Add. 155 static size_t Get(perfetto::EventContext* ctx, 156 const base::ModuleCache::Module* module); 157 static void Add(perfetto::EventContext* ctx, 158 size_t iid, 159 const base::ModuleCache::Module* module); 160 }; 161 162 // Interns an unsymbolized source code location + all it's "dependencies", i.e. 163 // module, strings used in the module definition, and so on. 164 struct BASE_EXPORT InternedUnsymbolizedSourceLocation 165 : public perfetto::TrackEventInternedDataIndex< 166 InternedUnsymbolizedSourceLocation, 167 perfetto::protos::pbzero::InternedData:: 168 kUnsymbolizedSourceLocationsFieldNumber, 169 uintptr_t> { 170 // We need a custom Get implementation to use ModuleCache, and to return 171 // a nullopt if a module for the given address cannot be found. 172 static std::optional<size_t> Get(perfetto::EventContext* ctx, 173 uintptr_t address); 174 static void Add(perfetto::protos::pbzero::InternedData* interned_data, 175 size_t iid, 176 const UnsymbolizedSourceLocation& location); 177 178 // We use thread local storage for the module cache if we are using the 179 // client library since it is more optimal. It was not worth it to write 180 // optimal caching for not client library users since everyone will convert. 181 #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY) 182 private: 183 // This implies that a module cache lifetime = incremental state. 184 // We don't want unlimited lifetime because it keeps modules pinned in 185 // memory on some platforms (Windows). 186 // TODO(b/237055179): Consider tying module cache to DataSource instead so 187 // that the cache is not unnecessarily cleared on incremental state change. 188 base::ModuleCache module_cache_; 189 #endif 190 }; 191 192 } // namespace trace_event 193 } // namespace base 194 195 #endif // BASE_TRACE_EVENT_INTERNED_ARGS_HELPER_H_ 196