One important optimization to avoid trying a bunch of dead end solutions is to see if we can eagerly determine that a piece will always end up in some state based on just the size of its contents and the page width. In order to apply that optimization, we walk the piece tree when constructing the solution and ask each piece if it can be eagerly bound.
Unfortunately, that traversal itself has significant overhead:
Times (ms)
AstNodeVisitor build Piece tree = 777.852
AstNodeVisitor.run() = 4166.931
CodeWriter.format() write separate piece text = 46.461
PieceWriter.finish() format piece tree = 3383.440
Solution bind by page width = 442.435
Solution.mergeSubtree() = 110.427
Solver dequeue = 74.833
Solver enqueue = 58.036
Whole enchilada = 5147.055
That's the "Solution bind by page width" step here.
This PR gets rid of the separate eager traversal. Instead, when we reach a piece during formatting, if it isn't already bound, we try the eager binding optimization then. That yields:
Times (ms)
AstNodeVisitor build Piece tree = 790.935
AstNodeVisitor.run() = 3944.811
CodeWriter try to bind by page width = 145.603
CodeWriter.format() write separate piece text = 45.283
PieceWriter.finish() format piece tree = 3151.060
Solution.mergeSubtree() = 119.708
Solver dequeue = 74.775
Solver enqueue = 56.464
Whole enchilada = 4813.870
The binding step is now "CodeWriter try to bind by page width" and is much faster.
This improves the overall performance when formatting the Flutter repo from 3.575s to 3.325s, or 7.5% faster. Some of the benchmarks show a more significant improvement:
One important optimization to avoid trying a bunch of dead end solutions is to see if we can eagerly determine that a piece will always end up in some state based on just the size of its contents and the page width. In order to apply that optimization, we walk the piece tree when constructing the solution and ask each piece if it can be eagerly bound.
Unfortunately, that traversal itself has significant overhead:
That's the "Solution bind by page width" step here.
This PR gets rid of the separate eager traversal. Instead, when we reach a piece during formatting, if it isn't already bound, we try the eager binding optimization then. That yields:
The binding step is now "CodeWriter try to bind by page width" and is much faster.
This improves the overall performance when formatting the Flutter repo from 3.575s to 3.325s, or 7.5% faster. Some of the benchmarks show a more significant improvement:
Not bad for a small code change.