Flutter Engine
The Flutter Engine
profiler_service.h
Go to the documentation of this file.
1// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_PROFILER_SERVICE_H_
6#define RUNTIME_VM_PROFILER_SERVICE_H_
7
9#include "vm/allocation.h"
10#include "vm/code_observers.h"
11#include "vm/globals.h"
12#include "vm/growable_array.h"
13#include "vm/object.h"
14#include "vm/profiler.h"
15#include "vm/tags.h"
17#include "vm/token_position.h"
18
19#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
20#include "perfetto/protozero/scattered_heap_buffer.h"
23#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
24
25// CPU Profile model and service protocol bits.
26// NOTE: For sampling and stack walking related code, see profiler.h.
27
28namespace dart {
29
30// Forward declarations.
31class Code;
32class Function;
33class JSONArray;
34class JSONStream;
35class ProfileFunctionTable;
36class ProfileCodeTable;
37class SampleFilter;
38class ProcessedSample;
39class ProcessedSampleBuffer;
40class Profile;
41
43 public:
45
46 void Tick(bool exclusive);
47
48 TokenPosition token_pos() const { return token_pos_; }
49 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
50 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
51
52 private:
53 TokenPosition token_pos_;
54 intptr_t exclusive_ticks_;
55 intptr_t inclusive_ticks_;
56
57 DISALLOW_ALLOCATION();
58};
59
61 public:
62 ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) {
63 for (intptr_t i = 0; i < kCacheSize; i++) {
64 cache_[i].Reset();
65 }
66 cache_hit_ = 0;
67 cache_miss_ = 0;
68 }
69
71 if (FLAG_trace_profiler) {
72 intptr_t total = cache_hit_ + cache_miss_;
73 OS::PrintErr("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total,
74 cache_hit_, cache_miss_);
75 }
76 }
77
78 void Get(uword pc,
79 const Code& code,
80 ProcessedSample* sample,
81 intptr_t frame_index,
82 // Outputs:
83 GrowableArray<const Function*>** inlined_functions,
84 GrowableArray<TokenPosition>** inlined_token_positions,
85 TokenPosition* token_position);
86
87 private:
88 bool FindInCache(uword pc,
89 intptr_t offset,
90 GrowableArray<const Function*>** inlined_functions,
91 GrowableArray<TokenPosition>** inlined_token_positions,
92 TokenPosition* token_position);
93
94 // Add to cache and fill in outputs.
95 void Add(uword pc,
96 const Code& code,
97 ProcessedSample* sample,
98 intptr_t frame_index,
99 // Outputs:
100 GrowableArray<const Function*>** inlined_functions,
101 GrowableArray<TokenPosition>** inlined_token_positions,
102 TokenPosition* token_position);
103
104 intptr_t NextFreeIndex() {
105 cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
106 return cache_cursor_;
107 }
108
109 intptr_t OffsetForPC(uword pc,
110 const Code& code,
111 ProcessedSample* sample,
112 intptr_t frame_index);
113 struct CacheEntry {
114 void Reset() {
115 pc = 0;
116 offset = 0;
117 inlined_functions.Clear();
118 inlined_token_positions.Clear();
119 }
120 uword pc;
121 intptr_t offset;
122 GrowableArray<const Function*> inlined_functions;
123 GrowableArray<TokenPosition> inlined_token_positions;
124 TokenPosition token_position = TokenPosition::kNoSource;
125 };
126
127 static constexpr intptr_t kCacheSize = 128;
128 intptr_t cache_cursor_;
129 intptr_t last_hit_;
130 CacheEntry cache_[kCacheSize];
131 intptr_t cache_miss_;
132 intptr_t cache_hit_;
133};
134
135// Profile data related to a |Function|.
137 public:
138 enum Kind {
139 kDartFunction, // Dart function.
140 kNativeFunction, // Synthetic function for Native (C/C++).
141 kTagFunction, // Synthetic function for a VM or User tag.
142 kStubFunction, // Synthetic function for stub code.
143 kUnknownFunction, // A singleton function for unknown objects.
144 };
145
147 const char* name,
148 const Function& function,
149 const intptr_t table_index);
150
151 const char* name() const {
152 ASSERT(name_ != nullptr);
153 return name_;
154 }
155
156 const char* Name() const;
157
158 const Function* function() const { return &function_; }
159
160 // Returns the resolved_url for the script containing this function.
161 const char* ResolvedScriptUrl() const;
162
163 bool is_visible() const;
164
165 intptr_t table_index() const { return table_index_; }
166
167 Kind kind() const { return kind_; }
168
169 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
170 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
171
172 void IncInclusiveTicks() { inclusive_ticks_++; }
173
174 void Tick(bool exclusive,
175 intptr_t inclusive_serial,
176 TokenPosition token_position);
177
178 static const char* KindToCString(Kind kind);
179
180 void PrintToJSONArray(JSONArray* functions, bool print_only_ids = false);
181
182 // Returns true if the call was successful and |pfsp| is set.
184
185 void TickSourcePosition(TokenPosition token_position, bool exclusive);
186
187 intptr_t NumSourcePositions() const {
188 return source_position_ticks_.length();
189 }
190
192 return source_position_ticks_.At(i);
193 }
194
195 private:
196 const Kind kind_;
197 const char* name_;
198 const Function& function_;
199 const intptr_t table_index_;
200 ZoneGrowableArray<intptr_t> profile_codes_;
202
203 intptr_t exclusive_ticks_;
204 intptr_t inclusive_ticks_;
205 intptr_t inclusive_serial_;
206
207 void PrintToJSONObject(JSONObject* func);
208 // A |ProfileCode| that contains this function.
209 void AddProfileCode(intptr_t code_table_index);
210
211 friend class ProfileCode;
212 friend class ProfileBuilder;
213};
214
216 public:
217 explicit ProfileCodeAddress(uword pc);
218
219 void Tick(bool exclusive);
220
221 uword pc() const { return pc_; }
222 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
223 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
224
225 private:
226 uword pc_;
227 intptr_t exclusive_ticks_;
228 intptr_t inclusive_ticks_;
229};
230
231// Profile data related to a |Code|.
233 public:
234 enum Kind {
235 kDartCode, // Live Dart code.
236 kCollectedCode, // Dead Dart code.
237 kNativeCode, // Native code.
238 kReusedCode, // Dead Dart code that has been reused by new kDartCode.
239 kTagCode, // A special kind of code representing a tag.
240 };
241
243 uword start,
244 uword end,
245 int64_t timestamp,
246 const AbstractCode code);
247
248 Kind kind() const { return kind_; }
249
250 uword start() const { return start_; }
251 void set_start(uword start) { start_ = start; }
252
253 uword end() const { return end_; }
254 void set_end(uword end) { end_ = end; }
255
256 void ExpandLower(uword start);
257 void ExpandUpper(uword end);
259 void TruncateUpper(uword end);
260
261 bool Contains(uword pc) const { return (pc >= start_) && (pc < end_); }
262
263 bool Overlaps(const ProfileCode* other) const;
264
265 int64_t compile_timestamp() const { return compile_timestamp_; }
266 void set_compile_timestamp(int64_t timestamp) {
267 compile_timestamp_ = timestamp;
268 }
269
270 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
272 exclusive_ticks_ = exclusive_ticks;
273 }
274 void IncExclusiveTicks() { exclusive_ticks_++; }
275
276 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
278 inclusive_ticks_ = inclusive_ticks;
279 }
280 void IncInclusiveTicks() { inclusive_ticks_++; }
281
282 bool IsOptimizedDart() const;
283 const AbstractCode code() const { return code_; }
284
285 const char* name() const { return name_; }
286 void SetName(const char* name);
287 void GenerateAndSetSymbolName(const char* prefix);
288
289 static const char* KindToCString(Kind kind);
290
291 void PrintToJSONArray(JSONArray* codes);
292
293 ProfileFunction* function() const { return function_; }
294
295 intptr_t code_table_index() const { return code_table_index_; }
296
297 private:
298 void Tick(uword pc, bool exclusive, intptr_t serial);
299 void TickAddress(uword pc, bool exclusive);
300
301 ProfileFunction* SetFunctionAndName(ProfileFunctionTable* table);
302
303 void PrintNativeCode(JSONObject* profile_code_obj);
304 void PrintCollectedCode(JSONObject* profile_code_obj);
305 void PrintOverwrittenCode(JSONObject* profile_code_obj);
306 void PrintTagCode(JSONObject* profile_code_obj);
307
308 void set_code_table_index(intptr_t index) { code_table_index_ = index; }
309
310 const Kind kind_;
311 uword start_;
312 uword end_;
313 intptr_t exclusive_ticks_;
314 intptr_t inclusive_ticks_;
315 intptr_t inclusive_serial_;
316
317 const AbstractCode code_;
318 char* name_;
319 int64_t compile_timestamp_;
320 ProfileFunction* function_;
321 intptr_t code_table_index_;
322 ZoneGrowableArray<ProfileCodeAddress> address_ticks_;
323
324 friend class ProfileBuilder;
325};
326
328 public:
329 ProfileCodeTable() : table_(8) {}
330
331 intptr_t length() const { return table_.length(); }
332
333 ProfileCode* At(intptr_t index) const {
334 ASSERT(index >= 0);
335 ASSERT(index < length());
336 return table_[index];
337 }
338
339 // Find the table index to the ProfileCode containing pc.
340 // Returns < 0 if not found.
341 intptr_t FindCodeIndexForPC(uword pc) const;
342
344 intptr_t index = FindCodeIndexForPC(pc);
345 if (index < 0) {
346 return nullptr;
347 }
348 return At(index);
349 }
350
351 // Insert |new_code| into the table. Returns the table index where |new_code|
352 // was inserted. Will merge with an overlapping ProfileCode if one is present.
353 intptr_t InsertCode(ProfileCode* new_code);
354
355 private:
356 void FindNeighbors(uword pc,
357 intptr_t* lo,
358 intptr_t* hi,
359 ProfileCode** lo_code,
360 ProfileCode** hi_code) const;
361
362 void VerifyOrder();
363 void VerifyOverlap();
364
366};
367
368// The model for a profile. Most of the model is zone allocated, therefore
369// a zone must be created that lives longer than this object.
370class Profile : public ValueObject {
371 public:
372 Profile();
373
374 // Build a filtered model using |filter|.
375 void Build(Thread* thread,
376 Isolate* isolate,
377 SampleFilter* filter,
378 SampleBlockBuffer* sample_block_buffer);
379
380 // After building:
381 int64_t min_time() const { return min_time_; }
382 int64_t max_time() const { return max_time_; }
383 int64_t GetTimeSpan() const { return max_time() - min_time(); }
384 intptr_t sample_count() const { return sample_count_; }
385 ProcessedSample* SampleAt(intptr_t index);
386
387 intptr_t NumFunctions() const;
388
389 ProfileFunction* GetFunction(intptr_t index);
390 ProfileCode* GetCode(intptr_t index);
391 ProfileCode* GetCodeFromPC(uword pc, int64_t timestamp);
392
393 void PrintProfileJSON(JSONStream* stream, bool include_code_samples);
395 bool include_code_samples,
396 bool is_event = false);
397#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
398 void PrintProfilePerfetto(JSONStream* js);
399#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
400
402
403 private:
404 void PrintHeaderJSON(JSONObject* obj);
405 void ProcessSampleFrameJSON(JSONArray* stack,
407 ProcessedSample* sample,
408 intptr_t frame_index);
409#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
410 void ProcessSampleFramePerfetto(
413 ProcessedSample* sample,
414 intptr_t frame_index);
415#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
416 void ProcessInlinedFunctionFrameJSON(JSONArray* stack,
417 const Function* inlined_function);
418 void PrintFunctionFrameIndexJSON(JSONArray* stack, ProfileFunction* function);
419 void PrintCodeFrameIndexJSON(JSONArray* stack,
420 ProcessedSample* sample,
421 intptr_t frame_index);
422 void PrintSamplesJSON(JSONObject* obj, bool code_samples);
423#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
424 /*
425 * Appends Perfetto packets describing the CPU samples in this profile to
426 * |jsonBase64String|. The |packet| parameter allows us to reuse an existing
427 * heap-buffered packet to avoid allocating a new one.
428 */
429 void PrintSamplesPerfetto(
430 JSONBase64String* jsonBase64String,
431 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet);
432#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
433
434 Zone* zone_;
435 ProcessedSampleBuffer* samples_;
436 ProfileCodeTable* live_code_;
437 ProfileCodeTable* dead_code_;
438 ProfileCodeTable* tag_code_;
439 ProfileFunctionTable* functions_;
440 intptr_t dead_code_index_offset_;
441 intptr_t tag_code_index_offset_;
442
443 int64_t min_time_;
444 int64_t max_time_;
445
446 intptr_t sample_count_;
447
448 friend class ProfileBuilder;
449};
450
452 public:
453 /*
454 * Prints a CpuSamples service response into |js|.
455 */
456 static void PrintJSON(JSONStream* stream,
457 int64_t time_origin_micros,
458 int64_t time_extent_micros,
459 bool include_code_samples);
460
461#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
462 /*
463 * Prints a PerfettoCpuSamples service response into |js|.
464 */
465 static void PrintPerfetto(JSONStream* js,
466 int64_t time_origin_micros,
467 int64_t time_extent_micros);
468#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
469
471 const Class& cls,
472 int64_t time_origin_micros,
473 int64_t time_extent_micros);
474
476 int64_t time_origin_micros,
477 int64_t time_extent_micros);
478
479 static void ClearSamples();
480
481 private:
482 enum PrintFormat : bool { JSON = false, Perfetto = true };
483
484 static void PrintCommonImpl(PrintFormat format,
485 Thread* thread,
486 JSONStream* js,
487 SampleFilter* filter,
489 bool include_code_samples);
490
491 /*
492 * If |format| is |PrintFormat::JSON|, prints a CpuSamples service response
493 * into |js|. If |format| is |PrintFormat::Perfetto|, prints a
494 * PerfettoCpuSamples service response into |js|. Note that the value of
495 * |include_code_samples| is ignored when |format| is |PrintFormat::Perfetto|.
496 */
497 static void PrintCommon(PrintFormat format,
498 JSONStream* js,
499 int64_t time_origin_micros,
500 int64_t time_extent_micros,
501 bool include_code_samples = false);
502};
503
504} // namespace dart
505
506#endif // RUNTIME_VM_PROFILER_SERVICE_H_
SI F table(const skcms_Curve *curve, F v)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
void Tick(bool exclusive)
intptr_t exclusive_ticks() const
intptr_t inclusive_ticks() const
void Get(uword pc, const Code &code, ProcessedSample *sample, intptr_t frame_index, GrowableArray< const Function * > **inlined_functions, GrowableArray< TokenPosition > **inlined_token_positions, TokenPosition *token_position)
ProfileCode * At(intptr_t index) const
intptr_t length() const
intptr_t InsertCode(ProfileCode *new_code)
ProfileCode * FindCodeForPC(uword pc) const
intptr_t FindCodeIndexForPC(uword pc) const
void ExpandUpper(uword end)
uword start() const
const AbstractCode code() const
void set_inclusive_ticks(intptr_t inclusive_ticks)
void TruncateLower(uword start)
intptr_t inclusive_ticks() const
static const char * KindToCString(Kind kind)
int64_t compile_timestamp() const
ProfileFunction * function() const
void TruncateUpper(uword end)
void SetName(const char *name)
intptr_t exclusive_ticks() const
bool IsOptimizedDart() const
void set_end(uword end)
bool Contains(uword pc) const
void ExpandLower(uword start)
void PrintToJSONArray(JSONArray *codes)
bool Overlaps(const ProfileCode *other) const
void set_compile_timestamp(int64_t timestamp)
void GenerateAndSetSymbolName(const char *prefix)
void set_exclusive_ticks(intptr_t exclusive_ticks)
ProfileCode(Kind kind, uword start, uword end, int64_t timestamp, const AbstractCode code)
void set_start(uword start)
const char * name() const
intptr_t code_table_index() const
ProfileFunctionSourcePosition(TokenPosition token_pos)
ProfileFunction(Kind kind, const char *name, const Function &function, const intptr_t table_index)
void Tick(bool exclusive, intptr_t inclusive_serial, TokenPosition token_position)
const Function * function() const
intptr_t table_index() const
const char * name() const
void TickSourcePosition(TokenPosition token_position, bool exclusive)
intptr_t inclusive_ticks() const
const char * ResolvedScriptUrl() const
void PrintToJSONArray(JSONArray *functions, bool print_only_ids=false)
bool GetSinglePosition(ProfileFunctionSourcePosition *pfsp)
intptr_t exclusive_ticks() const
const ProfileFunctionSourcePosition & GetSourcePosition(intptr_t i) const
const char * Name() const
intptr_t NumSourcePositions() const
static const char * KindToCString(Kind kind)
int64_t max_time() const
intptr_t sample_count() const
ProcessedSample * SampleAt(intptr_t index)
ProfileCode * GetCodeFromPC(uword pc, int64_t timestamp)
intptr_t NumFunctions() const
void Build(Thread *thread, Isolate *isolate, SampleFilter *filter, SampleBlockBuffer *sample_block_buffer)
ProfileCode * GetCode(intptr_t index)
int64_t min_time() const
void PrintProfileJSON(JSONStream *stream, bool include_code_samples)
ProfileFunction * FindFunction(const Function &function)
ProfileFunction * GetFunction(intptr_t index)
int64_t GetTimeSpan() const
static void PrintAllocationJSON(JSONStream *stream, const Class &cls, int64_t time_origin_micros, int64_t time_extent_micros)
static void PrintJSON(JSONStream *stream, int64_t time_origin_micros, int64_t time_extent_micros, bool include_code_samples)
#define ASSERT(E)
uint32_t uint32_t * format
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: dart_vm.cc:33
uintptr_t uword
Definition: globals.h:501
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition: switches.h:191
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
void Reset(SkPath *path)
Definition: path_ops.cc:40
#define Pd
Definition: globals.h:408
SeparatedVector2 offset