| Nim owns the screen, Dart owns the pixels 43a02c2 nandi yesterday | 1 | /// What the boundary costs, measured rather than assumed. |
| 2 | /// |
| 3 | /// The spike's architecture rebuilds the whole screen in Nim and ships it as |
| 4 | /// JSON on every event. That is the obvious objection to it, so this is the |
| 5 | /// number that answers the objection — or doesn't. |
| 6 | /// |
| 7 | /// just nim-bench |
| 8 | import 'dart:convert'; |
| 9 | import 'package:frq_core/frq_core.dart' as core; |
| 10 | |
| 11 | void main() { |
| 12 | core.resetUi(); |
| 13 | final json = jsonEncode({'id': 'noop'}); |
| 14 | print('tree size: ${core.render().toString().length} chars (as objects)'); |
| 15 | |
| 16 | // The raw JSON, to say what actually crosses the wire. |
| 17 | final bytes = utf8.encode(jsonEncode(_flatten(core.render()))); |
| 18 | print('tree bytes: ${bytes.length}'); |
| 19 | |
| 20 | for (final n in [1000, 10000]) { |
| 21 | var sw = Stopwatch()..start(); |
| 22 | for (var i = 0; i < n; i++) { |
| 23 | core.render(); |
| 24 | } |
| 25 | sw.stop(); |
| 26 | final perRender = sw.elapsedMicroseconds / n; |
| 27 | print('render(): ${perRender.toStringAsFixed(1)}µs ' |
| 28 | '(${(1000000 / perRender).round()}/s, ' |
| 29 | '${(perRender / 16666 * 100).toStringAsFixed(3)}% of a 60fps frame)'); |
| 30 | |
| 31 | sw = Stopwatch()..start(); |
| 32 | for (var i = 0; i < n; i++) { |
| 33 | core.dispatch('tls.toggle'); |
| 34 | } |
| 35 | sw.stop(); |
| 36 | final perDispatch = sw.elapsedMicroseconds / n; |
| 37 | print('dispatch(): ${perDispatch.toStringAsFixed(1)}µs ' |
| 38 | '(${(1000000 / perDispatch).round()}/s)'); |
| 39 | } |
| 40 | // ignore: unused_local_variable |
| 41 | final _ = json; |
| 42 | } |
| 43 | |
| 44 | Map<String, dynamic> _flatten(core.UiNode n) => { |
| 45 | 'tag': n.tag, |
| 46 | 'props': n.props, |
| 47 | 'children': n.children.map(_flatten).toList(), |
| 48 | }; |