Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
470 static void PrintAllocationJSON(JSONStream* stream,
471 const Class& cls,
472 int64_t time_origin_micros,
473 int64_t time_extent_micros);
474
475 static void PrintAllocationJSON(JSONStream* stream,
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 InsertCode(ProfileCode *new_code)
ProfileCode * FindCodeForPC(uword pc) const
intptr_t FindCodeIndexForPC(uword pc) const
void ExpandUpper(uword end)
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)
void set_start(uword start)
const char * name() const
intptr_t code_table_index() const
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)
static const uint8_t buffer[]
uint32_t uint32_t * format
Dart_NativeFunction function
Definition fuchsia.cc:51
uintptr_t uword
Definition globals.h:501
#define Pd
Definition globals.h:408
Point offset