1 // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions 5 // are met: 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above copyright 9 // notice, this list of conditions and the following disclaimer in 10 // the documentation and/or other materials provided with the 11 // distribution. 12 // * Neither the name of Google, Inc. nor the names of its contributors 13 // may be used to endorse or promote products derived from this 14 // software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 // SUCH DAMAGE. 28 29 #ifndef TOOLS_PLATFORM_H_ 30 #define TOOLS_PLATFORM_H_ 31 32 #include "PlatformMacros.h" 33 34 #include "mozilla/Logging.h" 35 #include "mozilla/MathAlgorithms.h" 36 #include "mozilla/ProfileBufferEntrySerialization.h" 37 #include "mozilla/TimeStamp.h" 38 #include "mozilla/UniquePtr.h" 39 #include "mozilla/Vector.h" 40 #include "nsString.h" 41 42 #include <cstddef> 43 #include <cstdint> 44 #include <functional> 45 46 class ProfilerCodeAddressService; 47 48 namespace mozilla { 49 struct SymbolTable; 50 } 51 52 extern mozilla::LazyLogModule gProfilerLog; 53 54 // These are for MOZ_LOG="prof:3" or higher. It's the default logging level for 55 // the profiler, and should be used sparingly. 56 #define LOG_TEST MOZ_LOG_TEST(gProfilerLog, mozilla::LogLevel::Info) 57 #define LOG(arg, ...) \ 58 MOZ_LOG(gProfilerLog, mozilla::LogLevel::Info, \ 59 ("[%d] " arg, profiler_current_process_id(), ##__VA_ARGS__)) 60 61 // These are for MOZ_LOG="prof:4" or higher. It should be used for logging that 62 // is somewhat more verbose than LOG. 63 #define DEBUG_LOG_TEST MOZ_LOG_TEST(gProfilerLog, mozilla::LogLevel::Debug) 64 #define DEBUG_LOG(arg, ...) \ 65 MOZ_LOG(gProfilerLog, mozilla::LogLevel::Debug, \ 66 ("[%d] " arg, profiler_current_process_id(), ##__VA_ARGS__)) 67 68 typedef uint8_t* Address; 69 70 // ---------------------------------------------------------------------------- 71 // Miscellaneous 72 73 class PlatformData; 74 75 // We can't new/delete the type safely without defining it 76 // (-Wdelete-incomplete). Use these to hide the details from clients. 77 struct PlatformDataDestructor { 78 void operator()(PlatformData*); 79 }; 80 81 typedef mozilla::UniquePtr<PlatformData, PlatformDataDestructor> 82 UniquePlatformData; 83 UniquePlatformData AllocPlatformData(int aThreadId); 84 85 namespace mozilla { 86 class JSONWriter; 87 } 88 void AppendSharedLibraries(mozilla::JSONWriter& aWriter); 89 90 // Convert the array of strings to a bitfield. 91 uint32_t ParseFeaturesFromStringArray(const char** aFeatures, 92 uint32_t aFeatureCount, 93 bool aIsStartup = false); 94 95 void profiler_get_profile_json_into_lazily_allocated_buffer( 96 const std::function<char*(size_t)>& aAllocator, double aSinceTime, 97 bool aIsShuttingDown); 98 99 // Flags to conveniently track various JS instrumentations. 100 enum class JSInstrumentationFlags { 101 StackSampling = 0x1, 102 TraceLogging = 0x2, 103 Allocations = 0x4, 104 }; 105 106 // Record an exit profile from a child process. 107 void profiler_received_exit_profile(const nsCString& aExitProfile); 108 109 // Write out the information of the active profiling configuration. 110 void profiler_write_active_configuration(mozilla::JSONWriter& aWriter); 111 112 // Extract all received exit profiles that have not yet expired (i.e., they 113 // still intersect with this process' buffer range). 114 mozilla::Vector<nsCString> profiler_move_exit_profiles(); 115 116 // If the "MOZ_PROFILER_SYMBOLICATE" env-var is set, we return a new 117 // ProfilerCodeAddressService object to use for local symbolication of profiles. 118 // This is off by default, and mainly intended for local development. 119 mozilla::UniquePtr<ProfilerCodeAddressService> 120 profiler_code_address_service_for_presymbolication(); 121 122 extern "C" { 123 // This function is defined in the profiler rust module at 124 // tools/profiler/rust-helper. mozilla::SymbolTable and CompactSymbolTable 125 // have identical memory layout. 126 bool profiler_get_symbol_table(const char* debug_path, const char* breakpad_id, 127 mozilla::SymbolTable* symbol_table); 128 129 bool profiler_demangle_rust(const char* mangled, char* buffer, size_t len); 130 } 131 132 // For each running times value, call MACRO(index, name, unit, jsonProperty) 133 #define PROFILER_FOR_EACH_RUNNING_TIME(MACRO) \ 134 MACRO(0, ThreadCPU, Delta, threadCPUDelta) 135 136 // This class contains all "running times" such as CPU usage measurements. 137 // All measurements are listed in `PROFILER_FOR_EACH_RUNNING_TIME` above. 138 // Each measurement is optional and only takes a value when explicitly set. 139 // Two RunningTimes object may be subtracted, to get the difference between 140 // known values. 141 class RunningTimes { 142 public: 143 constexpr RunningTimes() = default; 144 145 // Constructor with only a timestamp, useful when no measurements will be 146 // taken. RunningTimes(const mozilla::TimeStamp & aTimeStamp)147 constexpr explicit RunningTimes(const mozilla::TimeStamp& aTimeStamp) 148 : mPostMeasurementTimeStamp(aTimeStamp) {} 149 Clear()150 constexpr void Clear() { *this = RunningTimes{}; } 151 IsEmpty()152 constexpr bool IsEmpty() const { return mKnownBits == 0; } 153 154 // This should be called right after CPU measurements have been taken. SetPostMeasurementTimeStamp(const mozilla::TimeStamp & aTimeStamp)155 void SetPostMeasurementTimeStamp(const mozilla::TimeStamp& aTimeStamp) { 156 mPostMeasurementTimeStamp = aTimeStamp; 157 } 158 PostMeasurementTimeStamp()159 const mozilla::TimeStamp& PostMeasurementTimeStamp() const { 160 return mPostMeasurementTimeStamp; 161 } 162 163 // Should be filled for any registered thread. 164 165 #define RUNNING_TIME_MEMBER(index, name, unit, jsonProperty) \ 166 constexpr bool Is##name##unit##Known() const { \ 167 return (mKnownBits & mGot##name##unit) != 0; \ 168 } \ 169 \ 170 constexpr void Clear##name##unit() { \ 171 m##name##unit = 0; \ 172 mKnownBits &= ~mGot##name##unit; \ 173 } \ 174 \ 175 constexpr void Reset##name##unit(uint64_t a##name##unit) { \ 176 m##name##unit = a##name##unit; \ 177 mKnownBits |= mGot##name##unit; \ 178 } \ 179 \ 180 constexpr void Set##name##unit(uint64_t a##name##unit) { \ 181 MOZ_ASSERT(!Is##name##unit##Known(), #name #unit " already set"); \ 182 Reset##name##unit(a##name##unit); \ 183 } \ 184 \ 185 constexpr mozilla::Maybe<uint64_t> Get##name##unit() const { \ 186 if (Is##name##unit##Known()) { \ 187 return mozilla::Some(m##name##unit); \ 188 } \ 189 return mozilla::Nothing{}; \ 190 } 191 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_MEMBER)192 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_MEMBER) 193 194 #undef RUNNING_TIME_MEMBER 195 196 // Take values from another RunningTimes. 197 RunningTimes& TakeFrom(RunningTimes& aOther) { 198 if (!aOther.IsEmpty()) { 199 #define RUNNING_TIME_TAKE(index, name, unit, jsonProperty) \ 200 if (aOther.Is##name##unit##Known()) { \ 201 Set##name##unit(std::exchange(aOther.m##name##unit, 0)); \ 202 } 203 204 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_TAKE) 205 206 #undef RUNNING_TIME_TAKE 207 208 aOther.mKnownBits = 0; 209 } 210 return *this; 211 } 212 213 // Difference from `aBefore` to `this`. Any unknown makes the result unknown. 214 // PostMeasurementTimeStamp set to `this` PostMeasurementTimeStamp, to keep 215 // the most recent timestamp associated with the end of the interval over 216 // which the difference applies. 217 RunningTimes operator-(const RunningTimes& aBefore) const { 218 RunningTimes diff; 219 diff.mPostMeasurementTimeStamp = mPostMeasurementTimeStamp; 220 #define RUNNING_TIME_SUB(index, name, unit, jsonProperty) \ 221 if (Is##name##unit##Known() && aBefore.Is##name##unit##Known()) { \ 222 diff.Set##name##unit(m##name##unit - aBefore.m##name##unit); \ 223 } 224 225 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_SUB) 226 227 #undef RUNNING_TIME_SUB 228 return diff; 229 } 230 231 private: 232 friend mozilla::ProfileBufferEntryWriter::Serializer<RunningTimes>; 233 friend mozilla::ProfileBufferEntryReader::Deserializer<RunningTimes>; 234 235 mozilla::TimeStamp mPostMeasurementTimeStamp; 236 237 uint32_t mKnownBits = 0u; 238 239 #define RUNNING_TIME_MEMBER(index, name, unit, jsonProperty) \ 240 static constexpr uint32_t mGot##name##unit = 1u << index; \ 241 uint64_t m##name##unit = 0; 242 243 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_MEMBER) 244 245 #undef RUNNING_TIME_MEMBER 246 }; 247 248 template <> 249 struct mozilla::ProfileBufferEntryWriter::Serializer<RunningTimes> { 250 static Length Bytes(const RunningTimes& aRunningTimes) { 251 return ULEB128Size(aRunningTimes.mKnownBits) + 252 mozilla::CountPopulation32(aRunningTimes.mKnownBits) * 253 sizeof(uint64_t); 254 } 255 256 static void Write(ProfileBufferEntryWriter& aEW, 257 const RunningTimes& aRunningTimes) { 258 aEW.WriteULEB128(aRunningTimes.mKnownBits); 259 260 #define RUNNING_TIME_SERIALIZE(index, name, unit, jsonProperty) \ 261 if (aRunningTimes.Is##name##unit##Known()) { \ 262 aEW.WriteObject(aRunningTimes.m##name##unit); \ 263 } 264 265 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_SERIALIZE) 266 267 #undef RUNNING_TIME_SERIALIZE 268 } 269 }; 270 271 template <> 272 struct mozilla::ProfileBufferEntryReader::Deserializer<RunningTimes> { 273 static void ReadInto(ProfileBufferEntryReader& aER, 274 RunningTimes& aRunningTimes) { 275 aRunningTimes = Read(aER); 276 } 277 278 static RunningTimes Read(ProfileBufferEntryReader& aER) { 279 // Start with empty running times, everything is cleared. 280 RunningTimes times; 281 282 // This sets all the bits into mKnownBits, we don't need to modify it 283 // further. 284 times.mKnownBits = aER.ReadULEB128<uint32_t>(); 285 286 // For each member that should be known, read its value. 287 #define RUNNING_TIME_DESERIALIZE(index, name, unit, jsonProperty) \ 288 if (times.Is##name##unit##Known()) { \ 289 aER.ReadIntoObject(times.m##name##unit); \ 290 } 291 292 PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_DESERIALIZE) 293 294 #undef RUNNING_TIME_DESERIALIZE 295 296 return times; 297 } 298 }; 299 300 #endif /* ndef TOOLS_PLATFORM_H_ */ 301