Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a5570bd

Browse files
aartbikcommit-bot@chromium.org
authored andcommitted
[vm/compiler] Add optimization flag
Rationale: See min-design doc. Change-Id: Ic949a01ea2dcc873cf9e6d4d862e159be91da6f9 Reviewed-on: https://dart-review.googlesource.com/c/92161 Reviewed-by: Aart Bik <[email protected]> Reviewed-by: Siva Annamalai <[email protected]> Commit-Queue: Aart Bik <[email protected]>
1 parent f0d5cb7 commit a5570bd

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Dart MiniDesign Doc
2+
3+
## Optimization Levels for AOT Dart Compiler
4+
5+
# Introduction
6+
7+
In order to strike the right balance between compile-time, code speed, and code size, most optimizing compilers support several levels of optimizations, typically controlled by an -Ox switch. The usual ones relevant to this design code are:
8+
9+
* O0: short compilation-time, unoptimized code, small code size; highly debuggable
10+
* O2: medium compilation-time, optimized code, reasonable code size
11+
* O3: potentially long compilation-time, highly optimized code, possibly larger code size
12+
* Os: medium compilation-time, optimized while favoring code size
13+
14+
The O0 level is typically used during development and early testing, when a very fast compilation-time is more desirable than code speed. Also, this code is best for debugging, since unoptimized code has a very straightforward mapping between native instructions and memory locations and source program instructions and variables.
15+
16+
The O2 level is used to generate code for shipping. It strikes a right balance between compile-time and generated code speed and size. Since shipping occurs less frequently than debugging and testing, slightly longer compilation-times are acceptable.
17+
18+
When either code speed or size is favored, respectively, levels O3 or Os are used. For the former, longer compilation-times are acceptable as well.
19+
20+
The Dart compiler conceptually only supports level O0 (the un-optimized code that is used as our deopt "fallback") and level O2 (optimized code). Although the quality of optimization can heavily depend on profile feedback (JIT) and the possibility for speculative execution, both JIT and AOT strike more or less the same balance between generated code speed and size.
21+
22+
# Proposal
23+
24+
Some optimizations are known to benefit mostly code speed (with an unfavorable or unknown impact on code size) or mostly code size (with an unfavorable or unknown impact on code speed). For example, more aggressively inlining (to a certain extent) usually yields faster but more sizable code. Conversely, not aligning code (where allowed) usually yields more compact, but potentially slower running code.
25+
26+
Sometimes performing more expensive analysis, which negatively impacts compile-time, may discover more optimization opportunities in some cases, but remain completely empty handed in other cases. For example, doing an expensive data dependence analysis of loops only pays of if the loop is eventually vectorized or parallelized. Otherwise, all analysis time is wasted.
27+
28+
Note that almost every optimization decision_ is heuristic in nature_; optimizations generally improve a certain aspect of the code, but there are no hard guarantees.
29+
30+
Since Dart conceptually only supports O2, _all_ optimizations must always be chosen to strike a balance between compile-time and generated code speed and size. In order to give users more control over the optimization decision when using the Dart compiler, we propose adding the concept of Os and O3 as additional compilation modes. This could be implemented as an optimization level, for example as:
31+
32+
```
33+
--optimization_level=
34+
0: unoptimized (O0)
35+
1: size optimized (Os)
36+
2: default optimized (O2)
37+
3: speed optimized (O3)
38+
```
39+
40+
Level 0 corresponds to our current unoptimized path, whereas level 2 corresponds to the default path through our optimization passes. The other two levels alter the default path using the following guidelines.
41+
42+
* optimization_level=1 (Os)
43+
* Skip O2 optimizations that tend to increase code size, even if doing so may negatively impacts code speed
44+
* Introduce new optimizations that "heuristically" decrease code size, but at high risk of negatively impacting code speed
45+
* optimization_level=3 (O3)
46+
* Introduce more detailed analysis or optimizations that "heuristically" increase code speed, but at high risk of negatively impacting compile-time or code size
47+
48+
The guidelines are intentionally worded this way to avoid reckless use of the flag as a substitute for proper heuristics. For example, an optimization aimed at reducing code size with a neutral impact on code speed belongs in O2, not Os. As another example, always inlining without proper heuristics just in the hope to improve speed by blindly giving up size is not something we want in O3. Also, inlining heuristics that overall increase code speed with only minimal code size increase belongs in O2.
49+
50+
The proposal would apply to both the JIT and AOT compiler (to avoid adding yet another dimension through the optimization passes), although initially we may only want to expose the switch externally for the AOT compiler.
51+
52+
Advantages of approach:
53+
54+
* Allows new optimizations for size or speed that don't fit the current O2 philosophy
55+
* Enables removal of existing optimization from O2 that had a disproportionate negative impact on only size
56+
* Allows introduction of more expensive analysis that can (but is not guaranteed to) find more opportunities for optimization
57+
* Gives more control to users that favor size or speed differently than others
58+
* Potentially gives more insights on optimizations that were initially deemed to risky but helped "in the field"; perhaps better heuristics can be found to move these to O2
59+
60+
Disadvantages of the approach:
61+
62+
* Two additional code paths through compiler, increases the size of all testing matrices (Dart, Flutter, performance, correctness)
63+
* Risk of misusing the flag to avoid spending time finding better heuristics

runtime/vm/compiler/backend/inliner.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,8 +1482,12 @@ class CallSiteInliner : public ValueObject {
14821482
call->FirstArgIndex(), &arguments, call_info[call_idx].caller(),
14831483
call_info[call_idx].caller_graph->inlining_id());
14841484

1485-
// Calls outside loops are subject to stricter heuristics under AOT.
1485+
// Under AOT, calls outside loops may pass our regular heuristics due
1486+
// to a relatively high ratio. So, unless we are optimizing solely for
1487+
// speed, such call sites are subject to subsequent stricter heuristic
1488+
// to limit code size increase.
14861489
bool stricter_heuristic = FLAG_precompiled_mode &&
1490+
FLAG_optimization_level <= 2 &&
14871491
!inliner_->AlwaysInline(target) &&
14881492
call_info[call_idx].nesting_depth == 0;
14891493
if (TryInlining(call->function(), call->argument_names(), &call_data,

runtime/vm/flag_list.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ constexpr bool kDartPrecompiledRuntime = false;
126126
"Initial size of new gen semi space in MB") \
127127
P(optimization_counter_threshold, int, 30000, \
128128
"Function's usage-counter value before it is optimized, -1 means never") \
129+
P(optimization_level, int, 2, \
130+
"Optimization level: 1 (favor size), 2 (default), 3 (favor speed)") \
129131
P(old_gen_heap_size, int, kDefaultMaxOldGenHeapSize, \
130132
"Max size of old gen heap size in MB, or 0 for unlimited," \
131133
"e.g: --old_gen_heap_size=1024 allows up to 1024MB old gen heap") \

0 commit comments

Comments
 (0)