Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

HTML5 Conference 2015 悩める組込機器向けウェブコンテンツのパフォーマンス

11,725 views

Published on

近年、ブラウザーやブラウザーランタイムは、PCやスマートフォンのみならず、テレビ、コンソールゲーム機などの組み込み機器にも導入されるようになりました。また、Raspberry Piに代表されるSingle Board Computer(SBC)も流行りだし、ロースペックな環境で動作しなければならないウェブアプリケーション開発の需要が高まろうとしています。

多くの組み込み機器に搭載されたは、近年よく使われるAPIやCSSをサポートしています。しかし、そのパフォーマンスはスマートフォンと較べて非常に貧弱です。スマートフォンでは当たり前のパフォーマンスが得られることはありません。

本セッションでは、組み込み向け機器の現状を紹介し、その上で動作するウェブアプリケーションの開発の課題、私の経験での苦労話、そして、それに立ち向かうための Tips を紹介します。

Published in: Technology

HTML5 Conference 2015 悩める組込機器向けウェブコンテンツのパフォーマンス

  1. 1. 悩める組込機器向けウェブコンテンツのパフォーマンス 2015年1月25日 HTML5 Conference 2015 @futomi futomi.hatano
  2. 2. もくじ • 組込機器とブラウザー • 組込機器ブラウザーの問題 • パフォーマンスの定義 • ページのロード • ペイント領域とGPUメモリー • 画像のロード • ビデオのロード • メモリー消費 • prototype • DOMアクセス • まとめ
  3. 3. 組込機器とブラウザー
  4. 4. SBC (Single Board Computer) Raspberry Pi B+ BeagleBone Black ODROID-U3 ODROID-C1 Cubieboard 1/2 Marsboard RK3066 Radxa Rock Lite HummingBoard i1/i2 Banana Pi KDDI Open Web Board
  5. 5. 貧弱なCPUと少ないメモリ SONY Xperia Z3 Qualcomm Snapdragon 801 CPU: 4 Core (2.5GHz) RAM: 3GB Raspberry Pi B+ Broadcom BCM2835 CPU: 1 Core (700MHz) RAM: 512MB Cubieboard 2 Allwinner A20 CPU: 2 Core (1GHz) RAM: 1GB HummingBoard i1 Freescale i.MX6 Solo CPU: 1 Core (1GHz) RAM: 512GB Alcatel One Touch Fire Qualcomm Snapdragon MSM7227A CPU: 1 Core (1GHz) RAM: 256MB 近年のスマートフォンは超贅沢品
  6. 6. 組込機器ブラウザーの問題
  7. 7. テレビブラウザーの系統 スマートフォン向けブラウザー事情に酷似 ウェブアプリ開発の環境が整う
  8. 8. バージョンが固定 • なかなかブラウザーは更新されない • 機器のライフサイクルが長い • 古いバージョンが長期間残り続ける • いつか勝手に解決するとは思っては いけない... http://www.bbc.com/news/technology-20957218
  9. 9. 貧弱なCPUと少ないメモリー • 処理時間オーバー • スマートフォンではサクッと終わる処理がなかなか終わらない • アルゴリズムを考え直すか、分割して処理する必要がある • メモリーリーク • スマートフォンでは気にならなかったメモリーリークがすぐに顕在化 • JSによるメモリーのお漏らしは厳重にチェックする必要がある • ブラウザーのバグが顕著に出る • 組込機器はCPUが貧弱でメモリが少ないため、PCやスマートフォン では顕在化しない問題が起こる
  10. 10. パフォーマンスの定義
  11. 11. パフォーマンスとは • 速く • 起動を速く • 処理を速く • アニメーションを滑らかに • 少なく • メモリ消費を少なく • CPU処理を少なく • 長く • 安定動作を長く
  12. 12. パフォーマンスとは • 速く • 起動を速く • 処理を速く • アニメーションを滑らかに • 少なく • メモリ消費を少なく • CPU処理を少なく • 長く • 安定動作を長く すべてをかなえてくれる魔法の杖は...
  13. 13. パフォーマンスとは • 速く • 起動を速く • 処理を速く • アニメーションを滑らかに • 少なく • メモリ消費を少なく • CPU処理を少なく • 長く • 安定動作を長く すべてをかなえてくれる魔法の杖は... ありません!!!
  14. 14. パフォーマンスとは • 速く • 起動を速く • 処理を速く • アニメーションを滑らかに • 少なく • メモリ消費を少なく • CPU処理を少なく • 長く • 安定動作を長く すべてをかなえてくれる魔法の杖は... ありません!!! 何を捨てるのか、 何を諦めるのか、 を決めるのも重要 しかし、 ちょっとした配慮で パフォーマンスを改善
  15. 15. ページのロード
  16. 16. ネットワーク処理は高コスト • ダウンロードサイズとファイル数は少ないほど良い • HTML/CSS/JavaScriptのMinify • 極端に言えば、すべてHTMLにインラインに埋め込むのがベスト • パフォーマンスと保守性のバランスを考えましょう • 極度にMinifyツールを使うとJSが動作しない場合も • CSS Spriteもほどほどに
  17. 17. Google Closure Compiler https://developers.google.com/closure/compiler/
  18. 18. ペイント領域とGPUメモリー
  19. 19. Chromeデベロッパーツール 1 2 3 ペイント領域 FPS meter
  20. 20. ペイント領域とGPUメモリー • 一般的に良く言われる手法 • ペイント領域は可能な限り小さく • GPUアクセラレーションが有効な環境ならレイヤーを活用 • 動かすだけなら JavaScript のタイマーによる位置移動は避ける • CSS Transitions と CSS Transforms の活用 • 組込デバイスだと • GPUメモリーの上限が低い • レイヤー活用は必要最小限に • ペイント領域を可能な限り小さくするのは言うまでもない
  21. 21. コンテンツの移動 setTimeout() と left プロパティによるアニメーション CSS Transitions と CSS Transforms の translateX() によるアニメーション 移動のたびにペイント処理が実行され不効率 レイヤー処理により移動がスムーズかつGPUメモリー消費が少ない
  22. 22. レイヤーの使いすぎに注意 • 組込機器のGPUメモリーはさほど多くない • メインメモリーやGPUメモリーの速度もネックになる • 特にフルHDなど広い解像度を扱うコンテンツでは要注意 • 使いすぎると返って不効率
  23. 23. 値のリアルタイム更新 <p>経過時間: <span id="t">0</span> ミリ秒。</p> var el = document.querySelector("#t"); (function countUp(now) { el.textContent = Math.round(now); window.requestAnimationFrame(countUp); })(); 数値のみを書き換えているのに、 行全体が再ペイント JS
  24. 24. 値のリアルタイム更新 <p>経過時間: <span id="t">0</span> ミリ秒。</p> var el = document.querySelector("#t"); (function countUp(now) { el.textContent = Math.round(now); window.requestAnimationFrame(countUp); })(); 数値のみを書き換えているのに、 行全体が再ペイント JS
  25. 25. 浮かせる/サイズを固定する <p>経過時間: <span id="outer"><span id="t">0</span></span> ミリ秒。</p> var el = document.querySelector("#t"); (function countUp(now) { el.textContent = Math.round(now); window.requestAnimationFrame(countUp); })(); #outer { display: inline-block; width: 100px; height: 20px; position: relative; } #t { display: inline-block; width: 100px; position: absolute; text-align: right; } JS CSS
  26. 26. 表示と非表示の切替 <body> <img id="logo" src="imgs/logo.png"> <footer>...</footer> </body> var el = document.getElementById("logo"); var hidden = false; window.setInterval(function() { hidden = !hidden; el.style.display = hidden ? "none" : "block"; }, 1000); ロゴしか切り替えていないのに リフローの発生よりページ全体が 再ペイントの対象に 実際に見た目にリフローがなくても、 ブラウザーは再レンダリングを 行おうとしてしまう。 JS
  27. 27. CSSで位置固定 #logo { position: absolute; } <body> <img id="logo" src="imgs/logo.png"> <footer>...</footer> </body> var el = document.getElementById("logo"); var hidden = false; window.setInterval(function() { hidden = !hidden; el.style.display = hidden ? "none" : "block"; }, 1000); JS CSS
  28. 28. 画像のロード
  29. 29. img要素のloadイベント http://www.w3.org/TR/html5/embedded-content-0.html#the-img-element HTML5仕様曰く: If the download was successful and the user agent was able to determine the image's width and height, [...] fire a simple event named load at the img element. ダウンロードが成功し、ユーザーエージェントが画像の幅と高さを判定できたら、 [...] img要素で load という名前のシンプルなイベントを発出します。 loadイベントはレンダリング完了を表しているわけではない 組込機器では、loadイベントの発生と、実際にレンダリングが完了した タイミングの差が大きく出る
  30. 30. 巨大な画像のロード直後の処理 • img要素のloadイベント発生直後に重い処理をするとペイント処理とか ぶってしまいブラウザーが固まる場合がある • ペイントが完了したというイベントは取れない • 手を抜くなら、こうするしかない... imgElement.onload = function() { window.setTimeout(function() { // 何か次の処理 }, 100); }; JS
  31. 31. ビデオのロード
  32. 32. 組込機器には大敵なビデオデータ • 再生開始タイミングのパフォーマンスを気にするなら <video preload="auto"> • たとえ再生されなくてもバッファリング分のメモリーを消費 • 複数のビデオを事前に用意するのは厳しい • メモリーにやさしい方法を選ぶなら <video preload="none"> • 再生開始のタイミングがかなり遅れる • どうしても事前にビデオの寸法と尺を知りたいなら <video preload="metadata">
  33. 33. MP4の再生開始パフォーマンス • ファイルの最後にメタ情報が格納されている • これによって再生開始が大幅に遅れる • ブラウザーの挙動 1. ファイルの先頭を読み取る 2. メタ情報がないと判定し、ファイルの末尾を読み取る 3. ファイルの先頭に戻ってバッファリング分のビデオデータをダウンロードする
  34. 34. • エンコード時にFast Startを有効にする • メタ情報がファイルの先頭にセットされる • ブラウザーの読み取り回数が1回で済む • 再生開始パフォーマンスが向上する Fast Start
  35. 35. メモリー消費
  36. 36. メモリーリークの確認 Heap、Documents、Nodes、Listenersすべての推移の確認が重要
  37. 37. ノコギリ型のメモリー消費 • ガベージコレクションは負荷が高いためアニメーションを妨げる • 一般的にノコギリ型のメモリー消費は良くないと言われるが、それはデバ イス環境とユースケース次第 • メモリーが少ない環境では、早めにガベージコレクションを発生させ、 ピークを抑えるほうが良い場合もある
  38. 38. prototype
  39. 39. prototypeを使わない場合 var MyWallet = function(init_price) { this.price = init_price; this.earn = function(price) { this.price += price; if(this.price > 1000) { this.pay(this.price - 1000); } }; this.pay = function(price) { this.price -= price; }; this.look = function() { return this.price; }; }; JS
  40. 40. prototypeを使った場合 var MyWallet = function(init_price) { this.price = init_price; }; MyWallet.prototype.earn = function(price) { this.price += price; if(this.price > 1000) { this.pay(this.price - 1000); } }; MyWallet.prototype.pay = function(price) { this.price -= price; }; MyWallet.prototype.look = function() { return this.price; }; JS
  41. 41. メモリー消費に違いが出る(極端な例) var list = []; for( var i=0; i<100000; i++ ) { var w = new MyWallet(0); list.push(w); } prototypeを使わない場合 prototypeを使った場合 62MB 32MB JS
  42. 42. DOMアクセス
  43. 43. JavaScriptライブラリー • 使わない機能もテンコ盛り • 使わなくてもメモリーに展開されてしまう • できる限り機能を限定したライブラリーが良い • おすすめのJSライブラリーは...
  44. 44. http://vanilla-js.com/
  45. 45. 全機能にチェックを入れても、gzipでたったの25バイト 展開したら、なんと0バイト
  46. 46. みなさん、もうお気づきですね Vanilla JS はジョークサイトです DOM 操作は素で書くのが最もパフォーマンスに優れます
  47. 47. まとめ
  48. 48. • 流行りのライブラリーやプログラミング手法が良いとは限らない • メモリーが潤沢な環境を前提としていないかを考えるべき • レガシーな手法も見直そう • メモリーが少ない時代に考えられた手法は今なお組込デバイスでは有効
  49. 49. ご清聴ありがとうございました @futomi futomi.hatano

×