Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ViewModel decreases Blaze performance x3 ~ x10 #290

Open
arggh opened this issue Jul 24, 2017 · 4 comments
Open

ViewModel decreases Blaze performance x3 ~ x10 #290

arggh opened this issue Jul 24, 2017 · 4 comments

Comments

@arggh
Copy link

arggh commented Jul 24, 2017

@mitar built an UI benchmarking tool for Meteor. It included Blaze, vanilla JS, Blaze Components, Vue and React.

Blaze Components turned out to be really slow compared to plain Blaze.

I then created a fork of the tool with ViewModel included and found out ViewModel is even slower, in some tests a lot slower.

All frameworks compared:

Full results
[HMR] Vue 2.4.2
modules.js?hash=0b4346a…:8438 Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
modules.js?hash=0b4346a…:8448 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
dev-client.js:88 [HMR] Dev client URL 10.0.1.2:3003
dev-client.js:95 [HMR] Dev client connected
favicon.ico:1 GET http://localhost:3000/favicon.ico 404 (Not Found)
main.js:265 Benchmark started using 2 loops. Mon Jul 24 2017 13:48:28 GMT+0300 (EEST)
main.js:243 blaze: null -> other: 3 ms
main.js:243 blaze: other -> table1: 2537 ms
main.js:243 blaze: table1 -> other: 1147 ms
main.js:243 blaze: other -> table1: 2344 ms
main.js:243 blaze: table1 -> other: 647 ms
main.js:243 blaze: other -> recursive: 8882 ms
main.js:243 blaze: recursive -> other: 4730 ms
main.js:243 blaze: other -> recursive: 13502 ms
main.js:243 blaze: recursive -> other: 3373 ms
main.js:243 blaze: other -> table1: 5856 ms
main.js:243 blaze: table1 -> table3: 9078 ms
main.js:243 blaze: table3 -> table1: 10642 ms
main.js:243 blaze: table1 -> table3: 4411 ms
main.js:243 blaze: table3 -> table1: 6167 ms
main.js:243 blaze: table1 -> table2: 8260 ms
main.js:243 blaze: table2 -> table1: 4394 ms
main.js:243 blaze: table1 -> table2: 6395 ms
main.js:243 blaze: table2 -> table1: 8327 ms
main.js:243 viewmodel: null -> other: 144 ms
main.js:243 viewmodel: other -> table1: 15761 ms
main.js:243 viewmodel: table1 -> other: 2607 ms
main.js:243 viewmodel: other -> table1: 16816 ms
main.js:243 viewmodel: table1 -> other: 2516 ms
main.js:243 viewmodel: other -> recursive: 104410 ms
main.js:243 viewmodel: recursive -> other: 16367 ms
main.js:243 viewmodel: other -> recursive: 105932 ms
main.js:243 viewmodel: recursive -> other: 14835 ms
main.js:243 viewmodel: other -> table1: 14592 ms
main.js:243 viewmodel: table1 -> table3: 16792 ms
main.js:243 viewmodel: table3 -> table1: 19754 ms
main.js:243 viewmodel: table1 -> table3: 17362 ms
main.js:243 viewmodel: table3 -> table1: 17412 ms
main.js:243 viewmodel: table1 -> table2: 19769 ms
main.js:243 viewmodel: table2 -> table1: 23314 ms
main.js:243 viewmodel: table1 -> table2: 19045 ms
main.js:243 viewmodel: table2 -> table1: 25242 ms
main.js:243 blaze-components: null -> other: 824 ms
main.js:243 blaze-components: other -> table1: 11025 ms
main.js:243 blaze-components: table1 -> other: 2054 ms
main.js:243 blaze-components: other -> table1: 9106 ms
main.js:243 blaze-components: table1 -> other: 2048 ms
main.js:243 blaze-components: other -> recursive: 32702 ms
main.js:243 blaze-components: recursive -> other: 15840 ms
main.js:243 blaze-components: other -> recursive: 29574 ms
main.js:243 blaze-components: recursive -> other: 13835 ms
main.js:243 blaze-components: other -> table1: 15389 ms
main.js:243 blaze-components: table1 -> table3: 14838 ms
main.js:243 blaze-components: table3 -> table1: 13041 ms
main.js:243 blaze-components: table1 -> table3: 15187 ms
main.js:243 blaze-components: table3 -> table1: 13378 ms
main.js:243 blaze-components: table1 -> table2: 16261 ms
main.js:243 blaze-components: table2 -> table1: 13427 ms
main.js:243 blaze-components: table1 -> table2: 17379 ms
main.js:243 blaze-components: table2 -> table1: 13973 ms
main.js:243 manual: null -> other: 1 ms
main.js:243 manual: other -> table1: 1252 ms
main.js:243 manual: table1 -> other: 74 ms
main.js:243 manual: other -> table1: 639 ms
main.js:243 manual: table1 -> other: 72 ms
main.js:243 manual: other -> recursive: 338 ms
main.js:243 manual: recursive -> other: 278 ms
main.js:243 manual: other -> recursive: 144 ms
main.js:243 manual: recursive -> other: 277 ms
main.js:243 manual: other -> table1: 1094 ms
main.js:243 manual: table1 -> table3: 912 ms
main.js:243 manual: table3 -> table1: 2317 ms
main.js:243 manual: table1 -> table3: 249 ms
main.js:243 manual: table3 -> table1: 228 ms
main.js:243 manual: table1 -> table2: 214 ms
main.js:243 manual: table2 -> table1: 210 ms
main.js:243 manual: table1 -> table2: 206 ms
main.js:243 manual: table2 -> table1: 213 ms
main.js:243 stateful-react: null -> other: 7 ms
main.js:243 stateful-react: other -> table1: 1920 ms
main.js:243 stateful-react: table1 -> other: 244 ms
main.js:243 stateful-react: other -> table1: 985 ms
main.js:243 stateful-react: table1 -> other: 229 ms
main.js:243 stateful-react: other -> recursive: 3778 ms
main.js:243 stateful-react: recursive -> other: 829 ms
main.js:243 stateful-react: other -> recursive: 2760 ms
main.js:243 stateful-react: recursive -> other: 852 ms
main.js:243 stateful-react: other -> table1: 865 ms
main.js:243 stateful-react: table1 -> table3: 1102 ms
main.js:243 stateful-react: table3 -> table1: 1092 ms
main.js:243 stateful-react: table1 -> table3: 1163 ms
main.js:243 stateful-react: table3 -> table1: 1086 ms
main.js:243 stateful-react: table1 -> table2: 1096 ms
main.js:243 stateful-react: table2 -> table1: 1088 ms
main.js:243 stateful-react: table1 -> table2: 1127 ms
main.js:243 stateful-react: table2 -> table1: 1152 ms
main.js:243 stateful-vue: null -> other: 5 ms
main.js:243 stateful-vue: other -> table1: 1077 ms
main.js:243 stateful-vue: table1 -> other: 1870 ms
main.js:243 stateful-vue: other -> table1: 936 ms
main.js:243 stateful-vue: table1 -> other: 1991 ms
main.js:243 stateful-vue: other -> recursive: 3111 ms
main.js:243 stateful-vue: recursive -> other: 10577 ms
main.js:243 stateful-vue: other -> recursive: 2875 ms
main.js:243 stateful-vue: recursive -> other: 12496 ms
main.js:243 stateful-vue: other -> table1: 1246 ms
main.js:243 stateful-vue: table1 -> table3: 6065 ms
main.js:243 stateful-vue: table3 -> table1: 7207 ms
main.js:243 stateful-vue: table1 -> table3: 6312 ms
main.js:243 stateful-vue: table3 -> table1: 7163 ms
main.js:243 stateful-vue: table1 -> table2: 6667 ms
main.js:243 stateful-vue: table2 -> table1: 7304 ms
main.js:243 stateful-vue: table1 -> table2: 6757 ms
main.js:243 stateful-vue: table2 -> table1: 6760 ms
main.js:243 stateless-vue: null -> other: 12 ms
main.js:243 stateless-vue: other -> table1: 400 ms
main.js:243 stateless-vue: table1 -> other: 66 ms
main.js:243 stateless-vue: other -> table1: 357 ms
main.js:243 stateless-vue: table1 -> other: 61 ms
main.js:243 stateless-vue: other -> recursive: 1228 ms
main.js:243 stateless-vue: recursive -> other: 231 ms
main.js:243 stateless-vue: other -> recursive: 591 ms
main.js:243 stateless-vue: recursive -> other: 229 ms
main.js:243 stateless-vue: other -> table1: 1188 ms
main.js:243 stateless-vue: table1 -> table3: 377 ms
main.js:243 stateless-vue: table3 -> table1: 722 ms
main.js:243 stateless-vue: table1 -> table3: 346 ms
main.js:243 stateless-vue: table3 -> table1: 363 ms
main.js:243 stateless-vue: table1 -> table2: 367 ms
main.js:243 stateless-vue: table2 -> table1: 356 ms
main.js:243 stateless-vue: table1 -> table2: 352 ms
main.js:243 stateless-vue: table2 -> table1: 463 ms
main.js:286 Benchmark ended. Mon Jul 24 2017 14:11:06 GMT+0300 (EEST)
main.js:292 Computing minimongo baseline. Mon Jul 24 2017 14:11:06 GMT+0300 (EEST)
main.js:301 Done. Mon Jul 24 2017 14:11:06 GMT+0300 (EEST)
main.js:305 Result minimongo 106
main.js:321 Result blaze other -> table1 2440.5 2.581173982020095
main.js:321 Result blaze table1 -> other 897 12.287671232876713
main.js:321 Result blaze other -> recursive 11192 46.439834024896264
main.js:321 Result blaze recursive -> other 4051.5 14.6
main.js:321 Result blaze table1 -> table3 6744.5 11.618432385874247
main.js:321 Result blaze table3 -> table1 8404.5 6.604715127701375
main.js:321 Result blaze table1 -> table2 7327.5 34.892857142857146
main.js:321 Result blaze table2 -> table1 6360.5 30.073286052009458
main.js:321 Result viewmodel other -> table1 16288.5 17.22739291380222
main.js:321 Result viewmodel table1 -> other 2561.5 35.08904109589041
main.js:321 Result viewmodel other -> recursive 105171 436.3941908713693
main.js:321 Result viewmodel recursive -> other 15601 56.21981981981982
main.js:321 Result viewmodel table1 -> table3 17077 29.417743324720067
main.js:321 Result viewmodel table3 -> table1 18583 14.603536345776032
main.js:321 Result viewmodel table1 -> table2 19407 92.41428571428571
main.js:321 Result viewmodel table2 -> table1 24278 114.78959810874704
main.js:321 Result blaze-components other -> table1 10065.5 10.645690111052353
main.js:321 Result blaze-components table1 -> other 2051 28.095890410958905
main.js:321 Result blaze-components other -> recursive 31138 129.2033195020747
main.js:321 Result blaze-components recursive -> other 14837.5 53.468468468468465
main.js:321 Result blaze-components table1 -> table3 15012.5 25.86132644272179
main.js:321 Result blaze-components table3 -> table1 13209.5 10.38074656188605
main.js:321 Result blaze-components table1 -> table2 16820 80.0952380952381
main.js:321 Result blaze-components table2 -> table1 13700 64.77541371158392
main.js:321 Result manual other -> table1 945.5 1
main.js:321 Result manual table1 -> other 73 1
main.js:321 Result manual other -> recursive 241 1
main.js:321 Result manual recursive -> other 277.5 1
main.js:321 Result manual table1 -> table3 580.5 1
main.js:321 Result manual table3 -> table1 1272.5 1
main.js:321 Result manual table1 -> table2 210 1
main.js:321 Result manual table2 -> table1 211.5 1
main.js:321 Result stateful-react other -> table1 1452.5 1.5362242199894236
main.js:321 Result stateful-react table1 -> other 236.5 3.23972602739726
main.js:321 Result stateful-react other -> recursive 3269 13.564315352697095
main.js:321 Result stateful-react recursive -> other 840.5 3.028828828828829
main.js:321 Result stateful-react table1 -> table3 1132.5 1.950904392764858
main.js:321 Result stateful-react table3 -> table1 1089 0.8557956777996071
main.js:321 Result stateful-react table1 -> table2 1111.5 5.292857142857143
main.js:321 Result stateful-react table2 -> table1 1120 5.295508274231678
main.js:321 Result stateful-vue other -> table1 1006.5 1.064516129032258
main.js:321 Result stateful-vue table1 -> other 1930.5 26.445205479452056
main.js:321 Result stateful-vue other -> recursive 2993 12.41908713692946
main.js:321 Result stateful-vue recursive -> other 11536.5 41.57297297297297
main.js:321 Result stateful-vue table1 -> table3 6188.5 10.660637381567614
main.js:321 Result stateful-vue table3 -> table1 7185 5.6463654223968565
main.js:321 Result stateful-vue table1 -> table2 6712 31.961904761904762
main.js:321 Result stateful-vue table2 -> table1 7032 33.248226950354606
main.js:321 Result stateless-vue other -> table1 378.5 0.40031729243786357
main.js:321 Result stateless-vue table1 -> other 63.5 0.8698630136986302
main.js:321 Result stateless-vue other -> recursive 909.5 3.7738589211618256
main.js:321 Result stateless-vue recursive -> other 230 0.8288288288288288
main.js:321 Result stateless-vue table1 -> table3 361.5 0.6227390180878553
main.js:321 Result stateless-vue table3 -> table1 542.5 0.4263261296660118
main.js:321 Result stateless-vue table1 -> table2 359.5 1.7119047619047618
main.js:321 Result stateless-vue table2 -> table1 409.5 1.9361702127659575

meteor_benchmark_results

Detailed comparison of just Blaze and ViewModel:

Full results
[HMR] Vue 2.4.1
akryum_vue-component-dev-client.js:174 [HMR] Dev client URL 10.0.1.3:4003
modules.js:8417 Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
modules.js:8427 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
akryum_vue-component-dev-client.js:181 [HMR] Dev client connected
main.js:257 Benchmark started. Mon Jul 24 2017 14:38:22 GMT+0300 (EEST)
main.js:238 blaze: null -> other: 2 ms
main.js:238 blaze: other -> table1: 2633 ms
main.js:238 blaze: table1 -> other: 1066 ms
main.js:238 blaze: other -> table1: 3838 ms
main.js:238 blaze: table1 -> other: 702 ms
main.js:238 blaze: other -> table1: 4021 ms
main.js:238 blaze: table1 -> other: 1153 ms
main.js:238 blaze: other -> recursive: 13006 ms
main.js:238 blaze: recursive -> other: 5486 ms
main.js:238 blaze: other -> recursive: 16816 ms
main.js:238 blaze: recursive -> other: 3731 ms
main.js:238 blaze: other -> recursive: 16692 ms
main.js:238 blaze: recursive -> other: 6881 ms
main.js:238 blaze: other -> table1: 11134 ms
main.js:238 blaze: table1 -> table3: 5288 ms
main.js:238 blaze: table3 -> table1: 7305 ms
main.js:238 blaze: table1 -> table3: 9565 ms
main.js:238 blaze: table3 -> table1: 5145 ms
main.js:238 blaze: table1 -> table3: 7301 ms
main.js:238 blaze: table3 -> table1: 9281 ms
main.js:238 blaze: table1 -> table2: 5199 ms
main.js:238 blaze: table2 -> table1: 7197 ms
main.js:238 blaze: table1 -> table2: 9419 ms
main.js:238 blaze: table2 -> table1: 5161 ms
main.js:238 blaze: table1 -> table2: 7414 ms
main.js:238 blaze: table2 -> table1: 9448 ms
main.js:238 viewmodel: null -> other: 151 ms
main.js:238 viewmodel: other -> table1: 15573 ms
main.js:238 viewmodel: table1 -> other: 3213 ms
main.js:238 viewmodel: other -> table1: 17095 ms
main.js:238 viewmodel: table1 -> other: 3182 ms
main.js:238 viewmodel: other -> table1: 16375 ms
main.js:238 viewmodel: table1 -> other: 3753 ms
main.js:238 viewmodel: other -> recursive: 106261 ms
main.js:238 viewmodel: recursive -> other: 17294 ms
main.js:238 viewmodel: other -> recursive: 99806 ms
main.js:238 viewmodel: recursive -> other: 13226 ms
main.js:238 viewmodel: other -> recursive: 99385 ms
main.js:238 viewmodel: recursive -> other: 15117 ms
main.js:238 viewmodel: other -> table1: 13720 ms
main.js:238 viewmodel: table1 -> table3: 16988 ms
main.js:238 viewmodel: table3 -> table1: 19877 ms
main.js:238 viewmodel: table1 -> table3: 20706 ms
main.js:238 viewmodel: table3 -> table1: 27242 ms
main.js:238 viewmodel: table1 -> table3: 18666 ms
main.js:238 viewmodel: table3 -> table1: 18674 ms
main.js:238 viewmodel: table1 -> table2: 20651 ms
main.js:238 viewmodel: table2 -> table1: 26188 ms
main.js:238 viewmodel: table1 -> table2: 17672 ms
main.js:238 viewmodel: table2 -> table1: 20641 ms
main.js:238 viewmodel: table1 -> table2: 23957 ms
main.js:238 viewmodel: table2 -> table1: 20232 ms
main.js:278 Benchmark ended. Mon Jul 24 2017 14:55:10 GMT+0300 (EEST)
main.js:284 Computing minimongo baseline. Mon Jul 24 2017 14:55:10 GMT+0300 (EEST)
main.js:293 Done. Mon Jul 24 2017 14:55:12 GMT+0300 (EEST)
main.js:297 Result minimongo 496
main.js:313 Result blaze other -> table1 3497.3333333333335 NaN
main.js:313 Result blaze table1 -> other 973.6666666666666 NaN
main.js:313 Result blaze other -> recursive 15504.666666666666 NaN
main.js:313 Result blaze recursive -> other 5366 NaN
main.js:313 Result blaze table1 -> table3 7384.666666666667 NaN
main.js:313 Result blaze table3 -> table1 7243.666666666667 NaN
main.js:313 Result blaze table1 -> table2 7344 NaN
main.js:313 Result blaze table2 -> table1 7268.666666666667 NaN
main.js:313 Result viewmodel other -> table1 16347.666666666666 NaN
main.js:313 Result viewmodel table1 -> other 3382.6666666666665 NaN
main.js:313 Result viewmodel other -> recursive 101817.33333333333 NaN
main.js:313 Result viewmodel recursive -> other 15212.333333333334 NaN
main.js:313 Result viewmodel table1 -> table3 18786.666666666668 NaN
main.js:313 Result viewmodel table3 -> table1 21931 NaN
main.js:313 Result viewmodel table1 -> table2 20760 NaN
main.js:313 Result viewmodel table2 -> table1 22353.666666666668 NaN

blaze viewmodel chart

As you can see, ViewModel's results seem to be about 4x-5x larger than those of plain Blaze (for example, rendering table1, Blaze takes about ~3500ms, ViewModel variant takes ~ 16000ms).

However, the biggest difference is in the recursive test, in which Blaze succeeds in approximately 16 000ms, ViewModel takes a whopping ~100 000 ms.

Profiling the execution with Chrome's Dev Tools Performance tab, there seems to be a few time hogs, one related to firing a lot of timers.

Also, this isn't just a benchmarking problem. I had a real world app with a dynamic table with typically ~100 rows. First draft used ViewModel, with approximate rendering time of 16 seconds. After refactoring to pure Blaze the rendering time dropped to about 3-4 seconds.

Maybe there's a low hanging fruit with a tenfold speed improvement for ViewModel in some scenarios?

@ManuelDeLeon
Copy link
Owner

ManuelDeLeon commented Jul 24, 2017

Yeah, there has to be plenty of low hanging fruit since I've spent exactly 0s optimizing VM =/

Thank you for setting this up! I really appreciate it.

@juho
Copy link

juho commented Sep 7, 2017

+1 this, any improvements you can do Manuel are greatly appreciated!

@jamesgibson14
Copy link
Contributor

I have a very large app running Blaze and Viewmodel, most of the time it is not an issue, but sometimes I would enjoy some performance benefits.
@ManuelDeLeon I don't know how much help I can be but could you point me towards some of those "low hanging fruits" and maybe I can create some pull requests?

@ManuelDeLeon
Copy link
Owner

I don't have anything in mind right now (haven't worked on the Blaze version in years). You can just create a page and repeat an object hundreds of times and see what the hot paths are. Repeat the same process for other things like bindings, handling events, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants