Flutter Engine
The Flutter Engine
compiler_timings.h
Go to the documentation of this file.
1// Copyright (c) 2021, 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_COMPILER_COMPILER_TIMINGS_H_
6#define RUNTIME_VM_COMPILER_COMPILER_TIMINGS_H_
7
8#include <memory>
9
10#include "platform/allocation.h"
12#include "vm/thread.h"
13#include "vm/timer.h"
14
15#if defined(DART_PRECOMPILED_RUNTIME)
16#error "AOT runtime should not use compiler sources (including header files)"
17#endif // defined(DART_PRECOMPILED_RUNTIME)
18
19#define PRECOMPILER_TIMERS_LIST(V) \
20 V(CompileAll) \
21 V(Iterate) \
22 V(CompileFunction) \
23 V(AddCalleesOf) \
24 V(CheckForNewDynamicFunctions) \
25 V(CollectCallbackFields) \
26 V(PrecompileConstructors) \
27 V(AttachOptimizedTypeTestingStub) \
28 V(TraceForRetainedFunctions) \
29 V(FinalizeDispatchTable) \
30 V(ReplaceFunctionStaticCallEntries) \
31 V(Drop) \
32 V(Obfuscate) \
33 V(Dedup) \
34 V(SymbolsCompact)
35
36#define INLINING_TIMERS_LIST(V) \
37 V(CollectGraphInfo) \
38 V(PopulateWithICData) \
39 V(FindCallSites) \
40 V(SetInliningId) \
41 V(MakeInliningDecision) \
42 V(CheckForPragma) \
43 V(InlineCall) \
44 V(InlineRecognizedMethod) \
45 V(DiscoverBlocks) \
46 V(BuildDecisionGraph) \
47 V(PrepareGraphs)
48
49// Note: COMPILER_PASS_LIST must be the first element of the list below because
50// we expect that pass ids are the same as ids of corresponding timers.
51#define COMPILER_TIMERS_LIST(V) \
52 COMPILER_PASS_LIST(V) \
53 PRECOMPILER_TIMERS_LIST(V) \
54 INLINING_TIMERS_LIST(V) \
55 V(BuildGraph) \
56 V(EmitCode) \
57 V(FinalizeCode)
58
59namespace dart {
60
61// |CompilerTimings| provides a way to track time taken by various compiler
62// passes via a fixed number of timers (specified in |COMPILER_TIMERS_LIST|).
63//
64// It supports arbitrary nesting of timers e.g. if |DiscoverBlocks| is invoked
65// within two different compiler passes like |IfConvert| and |BranchSimplify|
66// then |CompilerTimings| will separate these two invocations and measure each
67// separately.
69 private:
70#define INC(Name) +1
71 static constexpr intptr_t kNumTimers = 0 COMPILER_TIMERS_LIST(INC);
72#undef INC
73
74 struct Timers : public MallocAllocated {
75 Timer timers_[kNumTimers];
76 std::unique_ptr<Timers> nested_[kNumTimers];
77 };
78
79 public:
80 enum TimerId {
81#define DECLARE_TIMER_ID(Name) k##Name,
83#undef DECLARE_TIMER_ID
84 };
85
86 // Timing scope which starts and stop the timer with the given |id|.
87 class Scope : public StackResource {
88 public:
90 : StackResource(thread), stats_(thread->compiler_timings()) {
91 if (stats_ != nullptr) {
92 outer_nested_ = stats_->nested_;
93 if (*outer_nested_ == nullptr) {
94 // Created array of nested timers if we don't have one yet.
95 *outer_nested_ = std::make_unique<Timers>();
96 }
97
98 timer_ = &(*outer_nested_)->timers_[id];
99 stats_->nested_ = &(*outer_nested_)->nested_[id];
100
101 timer_->Start();
102 }
103 }
104
106 if (stats_ != nullptr) {
107 timer_->Stop();
108 stats_->nested_ = outer_nested_;
109 }
110 }
111
112 private:
113 CompilerTimings* const stats_;
114 Timer* timer_;
115 std::unique_ptr<Timers>* outer_nested_;
116 };
117
118 CompilerTimings() { total_.Start(); }
119
120 void RecordInliningStatsByOutcome(bool success, const Timer& timer) {
121 if (success) {
122 try_inlining_success_.AddTotal(timer);
123 } else {
124 try_inlining_failure_.AddTotal(timer);
125 }
126 }
127
128 void Print();
129
130 private:
131 void PrintTimers(Zone* zone,
132 const std::unique_ptr<CompilerTimings::Timers>& timers,
133 const Timer& total,
134 intptr_t level);
135
136 Timer total_;
137 std::unique_ptr<Timers> root_ = std::make_unique<Timers>();
138
139 // Timers nested under the currently running timer(s).
140 std::unique_ptr<Timers>* nested_ = &root_;
141
142 Timer try_inlining_success_;
143 Timer try_inlining_failure_;
144};
145
146#define TIMER_SCOPE_NAME2(counter) timer_scope_##counter
147#define TIMER_SCOPE_NAME(counter) TIMER_SCOPE_NAME2(counter)
148
149#define COMPILER_TIMINGS_TIMER_SCOPE(thread, timer_id) \
150 CompilerTimings::Scope TIMER_SCOPE_NAME(__COUNTER__)( \
151 thread, CompilerTimings::k##timer_id)
152
153#define COMPILER_TIMINGS_PASS_TIMER_SCOPE(thread, pass_id) \
154 CompilerTimings::Scope TIMER_SCOPE_NAME(__COUNTER__)( \
155 thread, static_cast<CompilerTimings::TimerId>(pass_id))
156
157#define PRECOMPILER_TIMER_SCOPE(precompiler, timer_id) \
158 CompilerTimings::Scope TIMER_SCOPE_NAME(__COUNTER__)( \
159 (precompiler) -> thread(), CompilerTimings::k##timer_id)
160
161} // namespace dart
162
163#endif // RUNTIME_VM_COMPILER_COMPILER_TIMINGS_H_
Scope(Thread *thread, TimerId id)
void RecordInliningStatsByOutcome(bool success, const Timer &timer)
ThreadState * thread() const
Definition: allocation.h:33
void AddTotal(const Timer &other)
Definition: timer.h:135
void Stop()
Definition: timer.h:117
void Start()
Definition: timer.h:111
#define DECLARE_TIMER_ID(Name)
#define INC(Name)
#define COMPILER_TIMERS_LIST(V)
Definition: dart_vm.cc:33
const uintptr_t id