ラベル パフォーマンスチューニング の投稿を表示しています。 すべての投稿を表示
ラベル パフォーマンスチューニング の投稿を表示しています。 すべての投稿を表示

JavaScriptのメモリ消費について

今回は、メモ書き...

テーマはJavaScriptのメモリ消費についてです。

JavaScriptのメモリモデルはガベージコレクションという技術を用いています。
この手法は、ガベージコレクター(以下、GC)が最適と判断したタイミングでメモリの開放を行います。

問題点としては、下記があげられます。
・タイミングが制御できない
・GCの処理中は、プログラムが利用可能な処理時間を奪う

要は、メモリ消費が大きいWebアプリはGCが頻発し、パフォーマンス劣化に繋がるよってこと。

GCの頻度はどうやって確認する?

下記の画像は、YahooのトップページをDeveloper ToolsのTimelineタブでレコーディングしたものです。
山になっている水色部分がメモリの使用量で、一回ガクッと下がっています。
これがGCのタイミングで、ギザギザになってるほどGCの頻度が高いです。
(「バージョン 39.0.2159.0 canary (64-bit)」の画面です。)
図1. Developer ToolsのTimeline
ちゃんと確認したいのであれば、「GC」でフィルタするとことによっていつGCが発生したのかが確認できます。
図2. Developer ToolsのTimeline

GCの対象は?

JavaScript内ではすべての値がオブジェクトグラフに属しており、グラフにはルートが存在します。
そのルートからの参照がなくなった時点で、値はガベージコレクションの対象になります。

(そして、GCの処理中はオブジェクトグラフがルートから順に走査される間はページのスクリプト実行は中断されるって感じになる。)

GCの頻度を下げるにはどうしたらいいか?


  • メモリリークについて理解する

これについては説明が長くなりそうなので、下記の記事が非常に参考になります。
要は、不必要なクロージャに使用を避ける&循環参照を避けるってことがポイント。

【JavaScript】メモリの浪費を避けるコーディング
http://utage.headwaters.co.jp/blog/?p=1116

JavaScript アプリケーションのメモリー・リークを理解する
http://www.ibm.com/developerworks/jp/web/library/wa-jsmemory/


  • 大量のオブジェクトを作成/破棄することをなるべくしないようにすればよい

スタティックメモリJavaScriptというテクニック
(があるらしい。こういう実装したことないので知識だけ書いておきます。)

1. 同じ型を持つオブジェクトを必要な分だけセットして保持しておく、オブジェクトプールと呼ばれるものを作る。
2. 新しいオブジェクトが必要となった場合、システムのヒープメモリから取ってくるのではなく、プール内の使用されていないオブジェクトを再利用する。
3. 不要になったオブジェクトは、メインメモリではなくプールに返却する。

つまり、最初にオブジェクトをゴソッと作って、必要な場合はゴソッと作った中のものを使う。

【メリット】
フレーム毎に生成/破棄されるオブジェクトの数を必要最低限に抑えることができる

【デメリット】
初期化時の挙動が重い
メモリをあまり使用していないときも、使用メモリ量は減らない

(その他..)
また、
'hoge'.slice() とか 'hoge'.substr() とか非破壊関数は新しく配列・文字列を作って返すので注意すべし。

終わりに

ここに書いたことは、
担当している案件で動作が遅いとか、パフォーマンスチューニングして?って言われたときに気にするポイントの1つです。

ネットワーク部分以外のチューニングとしては、他に描画処理のパフォーマンスチューニングやJavaScriptのコード最適化(JSXみたいな)などがあります。
今後記事にできたらいいなーと思います。

以上!

参考

オブジェクトプールを使った静的メモリ JavaScript
http://www.html5rocks.com/ja/tutorials/speed/static-mem-pools/

Gmail スケールの効率的メモリ管理術
http://www.html5rocks.com/ja/tutorials/memory/effectivemanagement/

compassが遅い件 vol.3

「compassが遅い件 vol.2」の続きです。

今回はcssの生成を並列化したいと思います。
ディレクトリ構成等々は、vol.1・vol.2と同様です。

またもやconfig.rbに処理を書き込むカタチになります。

※ vol.1に記載した↓とは別件です。
> 最終的には、このグループでのコンパイルをforkさせ、複数のグループを並列にコンパイルさせるとこまでやりました。
> 今回は、それをするための前準備になります。

必要なものをインストールする

今回は並列実行ということで、Parallelというgemを使いたいと思います。
(スレッド数の管理もしてくれるし、とても楽に導入できたので。)

・Parallelをインストール(筆者はMacです…)
$ sudo gem install parallel
・Compassのバージョン
$ compass -v
Compass 0.12.2 (Alnilam)
Copyright (c) 2008-2014 Chris Eppstein
Released under the MIT License.
Compass is charityware.
Please make a tax deductable donation for a worthy cause: http://umdf.org/compass

並列化が実感できる環境をつくる

「vol.2」で作成したsass/test.scssはコンパイルに10秒以上かかっていたので、test2.scssとtest3.scssをつくり、css生成がブロックされる状態にしておく。
$ cp -ip sass/print.scss sass/test2.scss
$ cp -ip sass/print.scss sass/test3.scss
準備オッケー。
通常のコンパイルをしてみる。
$ compass compile --time --force
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.03s)
identical stylesheets/test.css (18.165s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.0s)
Compilation took 18.201s
test.css生成に時間がかかり、test2.cssとtest3.cssの生成がブロックされているのが分かります。

ソースの修正

修正箇所は、sass_filesのループで回してるところをparallelを使って並列化させるだけ。

ここの処理を_config.rbで上書きし、並列化させる。

すると、上限2スレッドでcss生成が開始される。
(test.cssでブロック中にtest2.css、test3.cssが生成されてるのがわかる。
$ compass compile --time --force
identical stylesheets/ie.css (0.001s)
identical stylesheets/print.css (0.001s)
identical stylesheets/screen.css (0.016s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.001s)
identical stylesheets/test.css (16.213s)
Compilation took 16.216s

オプションで指定できるようにする

例のごとく、環境変数でパラメータを受け取れるようにします。
今回は、全ソース乗っけます。(いろいろ細かく書いていってたので、まとめの意味で。

下記のようなコマンドで実行できます。
$ ./bin/zoocompass compile --time --force --compile-threads 2

終わりに

だいぶ複雑になってきましたね。。
苦肉の策でもあるので、ほんとにどうしようもないときに。。とか使いどきを選んでいただきたい所存。

以上!

compassが遅い件 vol.2


「compassが遅い件 vol.1」の続きです!

今回は、image-width/image-heightの高速化手法を記載します!
(ディレクトリ構成等々は、vol.1と同様です。

はじめに

前回はconfig.rbに追記していきましたが、今回もそうなります。

この調子で追記しまくっていったら、煩雑になってしまいます。。
そこで、カスタマイズしてる部分を分離しましょう!

カスタマイズしてる部分を分離する

簡単です。
$ cp -ip config.rb _config.rb
$ vim config.rb
⇒ 前回追記したところを全部消して、下記を追記する

$ vim _config.rb
⇒ 前回追記したところのみにする

以上です。量が増えたら、機能ごとにファイル分けてもいいかも。

image-width/image-heightの高速化 事前準備

測定のために、準備していきたいと思います。

1. 適当な画像を配置する
$ mkdir images
⇒ このディレクトリの中に、「200px.png」を入れておく。(画像なら何でも良いです

2. scssファイルを作っておく
$ vim sass/test.scss

3. コンパイルしてみる
$ compass compile --time --force
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.024s)
identical stylesheets/test.css (13.207s)
Compilation took 13.235s
⇒ おっそい...

※ 毎回全部コンパイルしたいとき。
スプライトも含めて全部コンパイルし直したい
→ compassの--forceオプション
cssファイルのみ全部コンパイルし直したい
→ config.rbの更新日付を新しくすると走ります。(touchしてみるとかで)

image-width/image-heightの高速化1

当たりをつけたのは、この辺り。
https://github.com/Compass/compass/blob/stable/lib/compass/sass_extensions/functions/image_size.rb#L47-L51

毎回画像のサイズ測ってるんじゃない?ということで、一回測ったらメモリに格納しておくようにしてみます。
(もしかしたら、.sass-cacheディレクトリでいい感じキャッシュ持ってるのかもしれませんが。筆者はそこまでわかりません!

こんな感じの修正になりました。これを_config.rbに追記します。

実行してみる
$ compass compile --time --force
identical stylesheets/ie.css (0.001s)
identical stylesheets/print.css (0.001s)
identical stylesheets/screen.css (0.03s)
identical stylesheets/test.css (7.889s)
Compilation took 7.93s
→ 5秒も短縮!

しかしこの修正には問題が、、
watchオプションのときを考慮しておりません。

理想はcompileオプションのときだけにしたいけど、これもzoocompassにオプション追加して使いたい時だけ発動するようにします。

image-width/image-heightの高速化2

_config.rbの修正

bin/zoocompassのcustom_optionsを修正(追記)

実行してみる
$ ./bin/zoocompass compile --time --force --enable-dimensions true
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.026s)
identical stylesheets/test.css (7.758s)
Compilation took 7.787s
$ ./bin/zoocompass compile --time --force --enable-dimensions false
identical stylesheets/ie.css (0.001s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.028s)
identical stylesheets/test.css (13.401s)
Compilation took 13.433s
$ ./bin/zoocompass compile --time --force
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.029s)
identical stylesheets/test.css (12.895s)
Compilation took 12.928s
うん、正しい!!

終わりに

今回は極端な例ですが、地味に効果があると思います。
高速化対応したgem作りたいなあ。。

以上です!

compassが遅い件 vol.1

以前、compassのコンパイルが遅い…と記載しましたが、
「遅い」に対していくつか対策したのでその手法を記事にしました。
(色々手法があるので、今回はvol. 1として書きます!

はじめに

compassはRubyで書かれており、モンキーパッチングが出来る。

ということで、compassのconfigファイル(config.rb)でcompassの処理を上書きすることができます。

今回は、どうやって変更を加えるのかを実験した後に
「コンパイルする対象を正規表現で絞り込むカスタマイズ」をしたいと思います。

実質的にコンパイル速度が早くなるという修正ではないです。
任意のグループでコンパイルを走らせることができるようになりました。ぐらいの変更です。
(これだけでも筆者の案件状況ではかなり効果的でした。詳しくは書かないですが、同一ソースで複数サービスが動くという状況。

最終的には、このグループでのコンパイルをforkさせ、複数のグループを並列にコンパイルさせるとこまでやりました。
今回は、それをするための前準備になります。

・compassのソースはこちら(GitHub)
https://github.com/Compass/compass

・macだと、このあたりにソースがあります
/Library/Ruby/Gems/1.8/gems/compass-0.12.2/

・筆者のcompassのバージョン
$ compass -v
Compass 0.12.2 (Alnilam)

実験する環境をつくる

まずはじめに、コンパイルできる環境を作ります。

1. コンパイル環境をつくる
任意のディレクトリに移動し、下記コマンドを実行すると、コンパイルに必要なファイル/フォルダが生成されます。
$ compass init
↓が生成される。
config.rb
sass
stylesheets

2. とりあえずコンパイルしてみる
$ compass compile --time
⇒ すると、コンパイルが走っていることが確認できます。
※ --timeオプションでコンパイルにかかった時間が表示されるので、今回は毎回このオプションをつけて実行する

実験する

compassのconfigファイル(config.rb)でcompassの処理を上書きすることができると記述しましたが、
本当に上書きできてるの?ってことを実験したいと思います。

compassでコンパイルする対象を取得するメソッドはこのような実装

config.rbに対して下記のような修正を加える(筆者はconfig.rbの下部に書いている)

⇒ この処理は、既存のメソッドをそのままコピーし、間に「p "here!!"」と1行追加しました。
※ 上書きすることができているならば、「compass compile」時に、「here!!」とログが流れ、正常にコンパイルが通っているはず。

$ compass compile --time
"here!"
"here!"
   remove .sass-cache/
   remove stylesheets/ie.css
   remove stylesheets/print.css
   remove stylesheets/screen.css
"here!"
   create stylesheets/ie.css (0.002s)
   create stylesheets/print.css (0.001s)
   create stylesheets/screen.css (0.104s)
Compilation took 0.141s

うん、正しい!

コンパイルする対象を正規表現で絞り込むカスタマイズ

では、上記のことを利用して、コンパイル対象を正規表現で絞り込むカスタマイズをしたいと思います。

config.rbに対して下記のような修正を加える。

これは何の修正なのか?
sassファイル名が「^.*ie.*$」にマッチするファイルをコンパイルするように修正しています。
(SASS_FILE_PATTERNSのIEを指定しているためです。

コンパイルしてみる
$ compass compile --time
   remove .sass-cache/
   remove stylesheets/ie.css
   create stylesheets/ie.css (0.002s)
Compilation took 0.003s

絞り込めてる!正しい!

ちなみに、DEFAULT_TARGET_PATTERNを「PRINT」にすることで、下記のみコンパイルされることも確認。
stylesheets/print.css

コンパイル対象を変える際に、いちいちconfig.rbを書き換えるのも面倒くさい…

きっと、↑のようなことになると思うので、オプションで指定したいですよね。

config.rbでオプション追加できるかなーと思って処理を追ってみましたが、
config.rbを読み込む前にcompassコマンドのオプション解析を済ませておりました‥
(compassのcオプションでconfig.rbを指定できるので、今思うと当たり前。
http://kanapple.net/study/archives/16

ということで、コマンドをラップするしかありません。
compassをrequireしてコマンドを新たに作ろうかなーとも思ったので、面倒なので↓にしてみました。

$ mkdir bin
$ touch bin/zoocompass
$ chmod 755 bin/zoocompass
$ vim bin/zoocompass

合わせて、config.rbのTARGET_PATTERN部分を下記に修正する(ENVでパラメータを受け取る

compassをラップした「bin/zoocompass」を使うと、オプションで指定したパラメータをconfig.rbで参照できるようになります。
(それ以外はcompassと何も変わりません。

何も変わってないか、試してみる
$ ./bin/zoocompass compile --time
   remove .sass-cache/
   remove stylesheets/ie.css
   create stylesheets/ie.css (0.003s)
Compilation took 0.005s

うん、変わってない。


追加したオプションで試してみる
$ ./bin/zoocompass compile --time --target IE
unchanged sass/ie.scss
Compilation took 0.001s

うん、よい。

$ ./bin/zoocompass compile --time --target PRINT
   remove .sass-cache/
   remove stylesheets/print.css
   create stylesheets/print.css (0.003s)
Compilation took 0.004s

うん、指定できてるぽい。

できた!!

注意事項!

compassのバージョンを上げる場合は、元のソース(compass側のソース)に変更がないか要確認。
案件内でやる場合には、みんなに周知しないと。

終わりに

次回以降、これを使って並列実行させた記事も書いていきたいと思います。
やったことを少しずつ記事にしてきますー。

以上!

Skia DebuggerによるCSSプロパティの重み測定 〜測定編〜

今回はSkia Debuggerの測定編ということで、install編の続きを書いていきたいと思います。

今回もまた、
(筆者がMacなので、Macのインストール談です。。Windowsのひと、ごめんなさいごめんなさい。


「.skp」ファイルを取得する

1. オプション付きでCanaryを起動
$ /Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --enable-impl-side-painting --enable-skia-benchmarking


2. tracingへアクセス
・Canaryで下記URLへアクセス
chrome://tracing/
図1. tracing


3. 「.skp」ファイルを取得する

・レコーディング状態にする
左上の「Record」ボタンを押す
「Settings preset: Web developer」となっている。

図2. tracing record

「Settings preset: Manually select settings」にすると表示が変わる。

図3. tracing record2

「Record Categories」のccをチェック
「Disabled By Default Categories」のcc.debugをチェック
右下の「Record」ボタンを押す。(すると、Recording状態になる。


・レコーディング〜レコーディングを停止する
新たなタブを開き、チェックしたWebサイトへ遷移して、計測したいページを開き、描画が変わるようなことをする。
(今回の場合、http://localhost/test/skia/

その後、元のタブ(chrome://tracing/)へ戻り、「Stop」ボタンを押してレコーディングを停止する


・レコーディング結果から「.skp」ファイルをexportする
アコーディオンがいくつかあるので、「Renderer (pid xxxxx): Index of /test/skia」を開き、
リストの見出しにある「cc::Picture」の右側の丸ポチを押す。
(すると、そのタブで開いた画面遷移が閲覧でき、遷移の流れを確認できる(右左ボタンでも切り替わるよ)

取得したい状態の.skpファイルを取得するには、画面左側の「Skia Picture」下部のskpicture.skp「Export」ボタンを押す。

図4. tracing record3

「.skp」ファイルを開く


1. Skia Debuggerを起動
install編でビルドした階層で、下記コマンドを実行する
$ open out/Debug/debugger.app


2. 「.skp」ファイルを開く
メニューにある「File」⇒Openボタンを押し、ファイルを開く

図5. Skia Debugger

(期待してた、Total Timeが表示されてない…ので、調べます…。前は表示されてたのに。。
それを元に、CSSプロパティの重みを測定しようと思ってました。


※ 筆者がハマった!
現象:
Canaryで吐き出した.skpファイルが開けない

解決:
Canaryのバージョンと、Skia Debuggerのバージョンが違うと(?)「Couldn't read file, sorry」というダイアログが表示され、.skpファイルが開けないぽい。
その場合は、Skiaの最新ソースをgit pullしてから、Skia Debuggerをビルドし直すと、Canaryで吐き出した.skpファイルが開けるようになりました。


次回は、色々測っていきたいと思います。

以上!


Skia DebuggerによるCSSプロパティの重み測定 〜install編〜

CSSプロパティの重みが測れる…ということを知ったので、どうやってやるの?

ってこと書きたいと思います。

インストールで筆者がつまづいてしまったので、まずはインストール編です。
(筆者がMacなので、Macのインストール談です。。Windowsのひと、ごめんなさいごめんなさい。

下記を参考にしてます!
http://havelog.ayumusato.com/develop/performance/e560-css_rendering_with_skia_debugger.html

はじめに

Skia Debuggerを入れなくても、レンダリング時のペイントの重みは知る手段があります。

※ペイントってなんぞ!?って方はこちら↓
http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/reflow-and-repaint-in-browser/


1. Google ChromeのDeveloper Tools 「Timeline」
Google ChromeのDeveloper Toolsで「Timeline」のタブを選択し、
左上の「●」ボタンを押すことで現在のTimelineを測定することができます。
図 Deveroper Tools Timeline

Timelineで表示されている棒グラフの色で、このようなことが分かります。
(このページはjavascriptの実行割合が多い。

Loading(青): 読み込みなど、ネットワークに関する処理
Scripting(黄): javascriptの実行に関する処理
Rendering(紫): レンダリングに関する処理
Painting(緑): 表示に関する処理←この処理が長くなってないか?多くないか?で描画に時間がかかっているかを判断することができます。

Developer Toolsの説明は、こちら詳しいです↓
http://www.slideshare.net/yoshikawa_t/chrome-devtoolsnext?ref=http://www.studio-kingdom.com/backbone-js/743


2. Google ChromeのDeveloper Tools 「Enable continuous page repainting」
Google ChromeのDeveloper Toolsで「画面を強制的に再描画し続けるモード」があり、
図1の「Enable continuous page repainting」チェックボックスをチェックすることでモードが切り替わります。
図1. Enable continuous page repainting

すると、
画面右上に緑色のボックス(描画の処理時間を表すメーター)が出てきます。
図2. 画面を強制的に再描画し続けるモード

このボックスをを表示した上で、
CSSプロパティの有効・無効を切り替えることで描画コストを高くしている原因を探ることができます。(メーターが上下するので。

Skia Debuggerって?

Skiaとは、Googleが開発しているグラフィックスライブラリで、Google Chromeでも使われいます。

そのSkiaのデバッグツールがSkia Debuggerで、このツールを使うとCSSプロパティの重みが測れます。

インストールするもの

XCODE
Google Chrome Canary
Qt
depot_tools
Skia Debugger

インストール手順

記述の順番通りインストール作業してもらえれば、たぶんスムーズに入るはず…

1. XCODEのインストール
https://itunes.apple.com/jp/app/xcode/id497799835?mt=12
App Storeからインストールする


2. Google Chrome Canaryのインストール
http://www.google.co.jp/intl/ja/chrome/browser/canary.html
上記サイトからダウンロードし、インストールする


3. Qtのインストール
http://qt-project.org/downloads
上記サイトからQt 4.8をダウンロードし、インストールする
最新バージョンを入れるとSkia Debuggerがインストールできなかったので要注意


4. depot_toolsのインストール
http://www.chromium.org/developers/how-tos/install-depot-tools

・depot_toolsをcloneする
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
・depot_toolsディレクトリにパスを通す(~/.bash_profileでもパスを通すように記述する
$ export PATH=`pwd`/depot_tools:"$PATH"
⇒ 後述するgclientコマンドを叩けるようにする


5. Skia Debuggerのインストール
https://sites.google.com/site/skiadocs/developer-documentation/contributing-code/downloading

・Skiaをcloneする
$ mkdir skia
$ cd skia/
$ gclient config --name . --unmanaged https://skia.googlesource.com/skia.git
$ gclient sync
・ビルドしてアプリを出力
$ GYP_GENERATORS="ninja,xcode"
$ GYP_DEFINES="skia_os=mac skia_arch_width=64" make debugger
⇒ すると、「out/Debug/debugger.app」にSkia Debuggerが出力される!

・起動
$ open out/Debug/debugger.app
などでdebugger.appを起動させると、↓のような画面が表示されます。

図3. Skia Debugger起動
画面中央下部の、Overviewのタブとかが表示されねえ…
という方は、画面左上の「+」で画面を最大サイズにしてみてください。

Macbook Airだと画面の縦幅が足りないようで、「+」を押さないと表示されませんでした。(筆者もハマりました。


とまあ、install編はこんな感じです。

測定編では、
Google Chrome CanaryとSkia Debuggerを使ってCSSプロパティの重みを測定していきたいと思います。

以上!