angular-cn/packages/core/test/render3/perf
Miško Hevery 9bd9590767 refactor(ivy): change styling to use programmatic API on updates (#34804)
Previously we would write to class/style as strings `element.className` and `element.style.cssText`. Turns out that approach is good for initial render but not good for updates. Updates using this approach are problematic because we have to check to see if there was an out of bound write to style and than perform reconciliation. This also requires the browser to bring up CSS parser which is expensive.

Another problem with old approach is that we had to queue the DOM writes and flush them twice. Once on element advance instruction and once in `hostBindings`. The double flushing is expensive but it also means that a directive can observe that styles are not yet written (they are written after directive executes.)

The new approach uses `element.classList.add/remove` and `element.style.setProperty/removeProperty` API for updates only (it continues to use `element.className` and `element.style.cssText` for initial render as it is cheaper.) The other change is that the styling changes are applied immediately (no queueing). This means that it is the instruction which computes priority. In some circumstances it may result in intermediate writes which are than overwritten with new value. (This should be rare)

Overall this change deletes most of the previous code and replaces it with new simplified implement. The simplification results in code savings.

PR Close #34804
2020-01-24 12:23:19 -08:00
..
class_binding test(ivy): `class_binding` benchmark fixes (#34242) 2019-12-11 09:50:23 -08:00
directive_inputs perf(ivy): add micro-benchmark focused on directive input update (#33798) 2019-11-19 11:55:59 -08:00
directive_instantiate perf(ivy): fix creation time micro-benchmarks (#34031) 2019-11-25 12:47:58 -05:00
duplicate_map_based_style_and_class_bindings test(ivy): introduce a benchmark for duplicate map-based style/class bindings (#33608) 2019-11-07 20:34:26 +00:00
duplicate_style_and_class_bindings test(ivy): introduce a benchmark for duplicate style/class bindings (#33600) 2019-11-07 17:50:33 +00:00
element_text_create perf(ivy): fix creation time micro-benchmarks (#34031) 2019-11-25 12:47:58 -05:00
interpolation perf(ivy): convert all node-based benchmark to use a testing harness (#32699) 2019-09-16 09:31:15 -07:00
listeners perf(ivy): fix creation time micro-benchmarks (#34031) 2019-11-25 12:47:58 -05:00
map_based_style_and_class_bindings refactor(ivy): move `styling/instructions.ts` to `instructions/styling.ts` (#32731) 2019-09-18 15:06:39 -07:00
ng_template perf(ivy): fix creation time micro-benchmarks (#34031) 2019-11-25 12:47:58 -05:00
noop_change_detection refactor(ivy): Intruduce LFrame to store global instruction information (#33178) 2019-10-24 14:42:15 -07:00
property_binding perf(ivy): convert all node-based benchmark to use a testing harness (#32699) 2019-09-16 09:31:15 -07:00
property_binding_update refactor(ivy): improve micro-benchmark profiling (#32647) 2019-09-12 13:06:38 -07:00
style_and_class_bindings perf(ivy): move attributes array into component def (#32798) 2019-10-09 13:16:55 -07:00
style_binding refactor(ivy): move `styling/instructions.ts` to `instructions/styling.ts` (#32731) 2019-09-18 15:06:39 -07:00
BUILD.bazel refactor(ivy): change styling to use programmatic API on updates (#34804) 2020-01-24 12:23:19 -08:00
README.md docs: update run instructions (#34090) 2019-11-27 10:39:17 -08:00
micro_bench.ts refactor(ivy): Add style reconciliation algorithm (#34004) 2020-01-24 12:21:39 -08:00
noop_renderer.ts test(ivy): support `className` in micro benchmarks (#33392) 2019-10-25 09:17:52 -07:00
noop_renderer_spec.ts test(ivy): support `className` in micro benchmarks (#33392) 2019-10-25 09:17:52 -07:00
profile_all.js build: migrate references and scripts that set to build with ivy via compile=aot to use config=ivy (#33983) 2019-11-26 16:38:40 -05:00
profile_in_browser.html build: migrate references and scripts that set to build with ivy via compile=aot to use config=ivy (#33983) 2019-11-26 16:38:40 -05:00
setup.ts perf(ivy): fix creation time micro-benchmarks (#34031) 2019-11-25 12:47:58 -05:00
shared.ts test(ivy): introduce a benchmark for duplicate style/class bindings (#33600) 2019-11-07 17:50:33 +00:00

README.md

Build

yarn bazel build //packages/core/test/render3/perf:${BENCHMARK}_lib.min_debug.es2015.js --config=ivy

Run

node dist/bin/packages/core/test/render3/perf/${BENCHMARK}_lib.min_debug.es2015.js

Profile

node --no-turbo-inlining --inspect-brk dist/bin/packages/core/test/render3/perf/${BENCHMARK}_lib.min_debug.es2015.js

then connect with a debugger (the --inspect-brk option will make sure that benchmark execution doesn't start until a debugger is connected and the code execution is manually resumed).

The actual benchmark code has calls that will start (console.profile) and stop (console.profileEnd) a profiling session.

Deoptigate

yarn add deoptigate
yarn deoptigate dist/bin/packages/core/test/render3/perf/${BENCHMARK}_lib.min_debug.es2015.js

Run All

To run all of the benchmarks use the profile_all.js script:

node packages/core/test/render3/perf/profile_all.js

NOTE: This command will build all of the tests, so there is no need to do so manually.

Optionally use the --write command to save the run result to a file for later comparison.

node packages/core/test/render3/perf/profile_all.js --write baseline.json

Comparing Runs

If you have saved the baseline (as described in the step above) you can use it to get change in performance like so:

node packages/core/test/render3/perf/profile_all.js --read baseline.json

The resulting output should look something like this:

┌────────────────────────────────────┬─────────┬──────┬───────────┬───────────┬───────┐
│              (index)               │  time   │ unit │ base_time │ base_unit │   %   │
├────────────────────────────────────┼─────────┼──────┼───────────┼───────────┼───────┤
│       directive_instantiate        │ 276.652 │ 'ms' │  286.292  │   'ms'    │ -3.37 │
│        element_text_create         │ 262.868 │ 'ms' │  260.031  │   'ms'    │ 1.09  │
│           interpolation            │ 257.733 │ 'us' │  260.489  │   'us'    │ -1.06 │
│             listeners              │  1.997  │ 'us' │   1.985   │   'us'    │  0.6  │
│ map_based_style_and_class_bindings │  10.07  │ 'ms' │   9.786   │   'ms'    │  2.9  │
│       noop_change_detection        │ 93.256  │ 'us' │  91.745   │   'us'    │ 1.65  │
│          property_binding          │ 290.777 │ 'us' │  280.586  │   'us'    │ 3.63  │
│      property_binding_update       │ 588.545 │ 'us' │  583.334  │   'us'    │ 0.89  │
│      style_and_class_bindings      │  1.061  │ 'ms' │   1.047   │   'ms'    │ 1.34  │
│           style_binding            │ 543.841 │ 'us' │  545.385  │   'us'    │ -0.28 │
└────────────────────────────────────┴─────────┴──────┴───────────┴───────────┴───────┘

Notes

To run the benchmark use bazel run <benchmark_target>, example:

  • yarn bazel run --config=ivy //packages/core/test/render3/perf:noop_change_detection

To profile, append _profile to the target name and attach a debugger via chrome://inspect, example:

  • yarn bazel run --config=ivy //packages/core/test/render3/perf:noop_change_detection_profile

To interactively edit/rerun benchmarks use ibazel instead of bazel.