Scalaでのwasmの出力サイズは?source mapは?jsと比較してどちらが大きい?調べてみました!

まずはこれを読みましょう

zenn.dev

さて、

その上で、実際にとあるライブラリでsize計測してみた、という話です。 versionはこれを書いてる時点の最新のscala-js 1.17.0。

実行速度は気が向いたら計測する可能性もあるけれど、どうせそんなに差が出ないと言ってるし、正確な計測も一般論として難しいので、まずは出力されるsizeだけ計測しました。

使ったのは、今や完全にcatsに取って代わられて、今まで以上に、自分専用のおもちゃというか実験場になりつつあるscalazくんです。

https://github.com/xuwei-k/scalaz/commit/ea3214b8f267d2001e51a3cfd4a307bc51456481

ちなみに、何もせずに最低限の設定をしたらscalazのscalacheck使ったテストは、いとも簡単に全てwasmでCI通ったので、もうmaster branchにCI設定ツッコミました。めでたい。

https://github.com/scalaz/scalaz/commit/cddec34f827abf3c1d47fed94e29d45c527ac90a

さて、testのバイナリのsizeや、sizeの計測のために専用のコード書いてもいいのですが、scalazには都合よく、exampleプロジェクトに複数のmainがあるので、それをエントリーポイントにして、ほぼ全部size計測しようとしました。

https://github.com/scalaz/scalaz/tree/cddec34f827abf3c1d47fed94e29d45c527ac90a/example/src/main/scala/scalaz/example

正確には全部やろうとしたけど、途中でjsの方の最適化中か何かにOOMになったので、全部はやれてないですが8割前後やったので、サンプルとしては十分でしょう。

fastLinkJSの方 (生成は速いが、sizeは大きくなる)

ではなく

fullLinkJS (生成に時間はかかる可能性があるが、sizeはより小さくなる可能性がある)

の方です。

wasmの場合は、デフォルトでは以下のようなファイルを生成するようです

__loader.js
main.js
main.wasm
main.wasm.map

jsの場合は以下

main.js
main.js.map

両方とも .map とついてるのはsource mapですね。これが結構な大きさを占めるので要注意です。よって、source map含めたsizeと、含めないsizeを出しました。

また、wasmの方は現状では必ず main.js__loader.js が生成されそれらすべてがセットで動くもののはずなので、これらの合計のsizeとします。

結果は以下。

wasmのsizejsのsize で割り算し、小数点以下3まで出しました

source mapなし

2倍近くwasmの方が大きい

scalaz.example.AdjunctUsage 1.966
scalaz.example.ApplyUsage 1.790
scalaz.example.ArrowUsage 1.975
scalaz.example.BifunctorUsage 2.019
scalaz.example.CaseInsensitiveUsage 1.623
scalaz.example.CodensityUsage 2.259
scalaz.example.ContravariantCoyonedaUsage 1.709
scalaz.example.DirectTypeClassUsage 1.890
scalaz.example.DisjunctionUsage 2.898
scalaz.example.EndoUsage 1.779
scalaz.example.EnumUsage 1.962
scalaz.example.FibStateExample 1.781
scalaz.example.FingerTreeUsage 2.094
scalaz.example.Foldable1Usage 1.801
scalaz.example.FoldableUsage 1.732
scalaz.example.FreeApUsage 1.690
scalaz.example.FreeUsage 1.802
scalaz.example.FunctorUsage 1.692
scalaz.example.IListUsage 1.983
scalaz.example.IsomorphismUsage 2.027
scalaz.example.IterateeUsage 2.041
scalaz.example.KleisliUsage 2.345
scalaz.example.LaunchburyInterpreter 1.811
scalaz.example.MixedBag 1.777
scalaz.example.NameNeedValueUsage 1.882
scalaz.example.NewTypeUsage 1.775
scalaz.example.PartiallyApplied 3.017
scalaz.example.ReaderWriterStateTUsage 1.989
scalaz.example.STUsage 1.783
scalaz.example.StringUsage 1.804
scalaz.example.StrongUsage 1.974
scalaz.example.SyntaxUsage 1.974

source map含めた全部

2〜3割くらい、wasmの方が小さい。 というか、wasmのsource mapが思ったより小さい、というべきか、jsのsource mapがとにかく巨大過ぎる!!!

scalaz.example.AdjunctUsage 0.675
scalaz.example.ApplyUsage 0.652
scalaz.example.ArrowUsage 0.679
scalaz.example.BifunctorUsage 0.763
scalaz.example.CaseInsensitiveUsage 0.640
scalaz.example.CodensityUsage 0.763
scalaz.example.ContravariantCoyonedaUsage 0.628
scalaz.example.DirectTypeClassUsage 0.775
scalaz.example.DisjunctionUsage 0.994
scalaz.example.EndoUsage 0.659
scalaz.example.EnumUsage 0.668
scalaz.example.FibStateExample 0.661
scalaz.example.FingerTreeUsage 0.756
scalaz.example.Foldable1Usage 0.649
scalaz.example.FoldableUsage 0.639
scalaz.example.FreeApUsage 0.627
scalaz.example.FreeUsage 0.658
scalaz.example.FunctorUsage 0.622
scalaz.example.IListUsage 0.679
scalaz.example.IsomorphismUsage 0.730
scalaz.example.IterateeUsage 0.693
scalaz.example.KleisliUsage 0.798
scalaz.example.LaunchburyInterpreter 0.656
scalaz.example.MixedBag 0.640
scalaz.example.NameNeedValueUsage 0.793
scalaz.example.NewTypeUsage 0.659
scalaz.example.PartiallyApplied 1.710
scalaz.example.ReaderWriterStateTUsage 0.681
scalaz.example.STUsage 0.646
scalaz.example.StringUsage 0.725
scalaz.example.StrongUsage 0.679
scalaz.example.SyntaxUsage 0.678

いかがでしたか!!!

実際にブラウザで使う用途となったら、さらにこれらを圧縮した状態でも計測するべきとか色々ありますし、上記のzennの記事にもあるようにsize含めた最適化はまだまだこれからなので、今の時点で計測してどの程度意味があるのか?は微妙ですが、これからに期待したいですね。

一番下に元データも貼っておきます。

  • class名
  • source map含めた全部のsize(byte数)
  • source map除いたsize(byte数)

の順番です。

js

scalaz.example.AdjunctUsage 1425322 298786
scalaz.example.ApplyUsage 926182 199029
scalaz.example.ArrowUsage 1454414 304567
scalaz.example.BifunctorUsage 251750 61816
scalaz.example.CaseInsensitiveUsage 638101 141870
scalaz.example.CodensityUsage 739723 163306
scalaz.example.ContravariantCoyonedaUsage 1466713 306364
scalaz.example.DirectTypeClassUsage 106521 29708
scalaz.example.DisjunctionUsage 195121 48752
scalaz.example.EndoUsage 538314 122167
scalaz.example.EnumUsage 1692405 354141
scalaz.example.FibStateExample 511490 116833
scalaz.example.FingerTreeUsage 655261 145691
scalaz.example.Foldable1Usage 680295 148798
scalaz.example.FoldableUsage 890067 190983
scalaz.example.FreeApUsage 923496 199754
scalaz.example.FreeUsage 569054 128461
scalaz.example.FunctorUsage 1148069 247395
scalaz.example.IListUsage 1507701 315034
scalaz.example.IsomorphismUsage 281967 66912
scalaz.example.IterateeUsage 1617716 337205
scalaz.example.KleisliUsage 532271 119760
scalaz.example.LaunchburyInterpreter 725747 160242
scalaz.example.MixedBag 914252 197713
scalaz.example.NameNeedValueUsage 86448 25503
scalaz.example.NewTypeUsage 435474 99280
scalaz.example.PartiallyApplied 36930 14390
scalaz.example.ReaderWriterStateTUsage 850523 182649
scalaz.example.STUsage 559813 126458
scalaz.example.StringUsage 234655 60158
scalaz.example.StrongUsage 1448865 303605
scalaz.example.SyntaxUsage 1475382 309241

wasm

scalaz.example.AdjunctUsage 961727 587353
scalaz.example.ApplyUsage 603975 356263
scalaz.example.ArrowUsage 987164 601457
scalaz.example.BifunctorUsage 191989 124787
scalaz.example.CaseInsensitiveUsage 408365 230317
scalaz.example.CodensityUsage 564257 368896
scalaz.example.ContravariantCoyonedaUsage 920473 523576
scalaz.example.DirectTypeClassUsage 82532 56147
scalaz.example.DisjunctionUsage 193889 141263
scalaz.example.EndoUsage 354897 217307
scalaz.example.EnumUsage 1130286 694957
scalaz.example.FibStateExample 338181 208029
scalaz.example.FingerTreeUsage 495127 305034
scalaz.example.Foldable1Usage 441349 267928
scalaz.example.FoldableUsage 568703 330703
scalaz.example.FreeApUsage 579033 337522
scalaz.example.FreeUsage 374341 231539
scalaz.example.FunctorUsage 713608 418666
scalaz.example.IListUsage 1024473 624729
scalaz.example.IsomorphismUsage 205914 135640
scalaz.example.IterateeUsage 1120370 688138
scalaz.example.KleisliUsage 424994 280835
scalaz.example.LaunchburyInterpreter 476363 290198
scalaz.example.MixedBag 585509 351278
scalaz.example.NameNeedValueUsage 68545 48001
scalaz.example.NewTypeUsage 286933 176243
scalaz.example.PartiallyApplied 63135 43417
scalaz.example.ReaderWriterStateTUsage 579489 363221
scalaz.example.STUsage 361493 225432
scalaz.example.StringUsage 170139 108495
scalaz.example.StrongUsage 983242 599262
scalaz.example.SyntaxUsage 1000041 610452