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