deoptimised取得することなく、高性能なJavaScriptコードを書きます

Joppy:

大きな数値配列(整数または浮動小数点数で動作する、線形代数パッケージを考える)上で動作し、JavaScriptでのパフォーマンスに敏感なコードを書くとき、人は常に可能な限り助けるためにJITを望んでいます。大雑把にこの手段:

  1. 私たちは常に配列がのSMI(小さな整数)を詰めたり、我々は、整数または浮動小数点計算をやっているかどうかに応じて、ダブルスを詰めることにしたいです。
  2. 我々は常に、彼らが「megamorphic」ラベルとdeoptimised取得しないように、機能に事の同じタイプを渡すことにしたいです。たとえば、私たちは常に呼び出すことがしたいvec.add(x, y)の両方でxy詰めSMIアレイである、またはその両方がダブル配列をパック。
  3. 私たちは、機能を可能な限りインライン展開することにしたいです。

これらの例すると1外れるの外側に、突然の大幅なパフォーマンスのドロップオフが発生します。これは、様々な無害な理由で発生することができます:

  1. あなたは相当のように、一見無害な操作を経てパックダブル配列に詰めSMI配列を回すかもしれませんmyArray.map(x => -x)パックダブル配列は非常に高速残っているので、これは、実際には「最良の」悪いケースです。
  2. あなたは(予想外に)返された機能上の配列をマッピングすることにより、例えば、一般的な箱入り配列にパックされた配列を回すかもしれませんnullundefinedこの悪い場合は、避けるために非常に簡単です。
  3. 次のような関数全体をdeoptimiseかもしれないvec.add()ものの、あまりにも多くの種類を渡すとmegamorphicに回して。あなたは「ジェネリックプログラミング」、行いたい場合に発生する可能性がありvec.add()ますが、種類について気をつけながら(それは種類がたくさんで来て見て)、あなたが最大のパフォーマンスをひねり出すしたい場合はしていない場合の両方を使用されているが(それが唯一のこれまで例えば、箱入りダブルスを受ける必要があります)。

私の質問はまだコード素晴らしく、読みやすいを維持しながら1は、上記の考察に照らして、高性能JavaScriptコードを書き込む方法については、より柔らかい質問のです。いくつかの特定のサブの質問あなたは私が目指してる種類の回答のか知っているように:

  • プログラムにパックSMIアレイ(例えば)の世界に滞在しながら、方法のガイドラインのどこかのセットがありますか?
  • 以下のようなものをインライン化するマクロシステムのようなものを使用せずにJavaScriptでの汎用高性能なプログラミングを行うことは可能であるvec.add()callsitesに?
  • どのようにモジュール化、高性能コードがmegamorphic呼び出しサイトとdeoptimisationsのようなものの光にするライブラリの中にいますか?例えば、私は喜んで線形代数パッケージを使用していた場合にA高速で、その後、私は、パッケージのインポートBに依存しAますが、B他のタイプとそれを呼び出し、自分のコードが実行遅く(私のコードを変更せずに)突然、それをdeoptimisesを。
  • 何か良いがある使いやすい JavaScriptエンジンがタイプで、内部でやっていることを確認するための測定ツールは?
jmrk:

ここでV8の開発者。この質問への関心の量、および他の回答の欠如を考えると、私はこの打撃を与えることができます。私はそれはあなたがが望んでいた答えではありません怖いです。

プログラムにパックSMIアレイ(例えば)の世界に滞在しながら、方法のガイドラインのどこかのセットがありますか?

短い答え:それはここです:const guidelines = ["keep your integers small enough"]

長い答え:ガイドラインの包括的なセットを与えるには、様々な理由から困難です。一般的には、我々の意見では、JavaScriptの開発者は彼らとそのユースケースに理にかなってコードを書く必要があり、およびJavaScriptエンジンの開発者が自分のエンジンの速いそのコードを実行する方法を見つけ出す必要があるということです。フリップ側では、いくつかの制限は、いくつかのコーディングパターンは関係なく、常にエンジンの実装の選択と最適化の努力の、他よりも高いパフォーマンスコストを持つという意味で、その理想的に明らかにあります。

我々は、パフォーマンスのアドバイスについて話すとき、私たちは心の中でそれを維持しよう、と推奨事項は、多くのエンジンと長年渡って有効な残りの高い可能性を持っているもの、慎重に推定し、また合理的に慣用的/非侵入しています。

手元の例に戻ってガイド:SMISを使用しては、内部ユーザーコードが知る必要がないことを、実装の詳細であると考えられます。これは、いくつかの例をより効率的にするだろう、それ以外の場合に傷つけるべきではありません。私はいくつかのケースのために、彼らは、これらの日のSMIを使用行うことを聞いた;しかし、私はすべての詳細を知らないと、上の任意の権威をもって話すことができないすべてのエンジンは、(例えば、私の知る限りのFirefox / SpiderMonkeyのは、歴史的にしていないSMISを使用しません問題)。V8において、SMISの大きさは、内部の詳細であり、実際経時及びバージョンにわたって変更されています。大部分のユースケースであるように使用される32ビットプラットフォーム上で、SMISは常に31ビットの符号付き整数となっています。64ビットプラットフォーム上で彼らはクローム80で、我々は「ポインタの圧縮」を出荷するまで、最近最も一般的なケースのように思えた32ビット符号付き整数、にするために使用しました 32ビットプラットフォームから知られて31ビットのSMIサイズを低下させるに必要な64ビットアーキテクチャのため。あなたはSMISは、一般的に32ビットであることを前提に実装をベースとしているために起こった場合は、次のような不幸な状況を取得したいですこれ

あなたが述べたようにありがたいことに、二重の配列はまだ非常に高速です。数値重いコードの場合、それはおそらく/標的二の配列を想定することは理にかなって。JavaScriptでダブルスの有病率を考えると、すべてのエンジンは、ダブル、ダブル配列のための良いサポートを持っていると仮定することが合理的です。

callsitesにvec.add()のようなものをインライン化するマクロシステムのようなものを使用せずにJavaScriptでの汎用高性能なプログラミングを行うことは可能ですか?

「汎用」「高性能」とオッズで一般的です。これはJavaScriptに、または特定のエンジンの実装とは無関係です。

決定は、実行時に行わなければならない「一般的な」コード手段。あなたが関数を実行するたびに、コードを決定するために実行する必要があり、たとえば、「あるxもしそうなら、そのコードパスを取る?整数。ですx?文字列が続いてこっちにジャンプします。それはオブジェクトですか?それを持っているの.valueOf?いいえ?そして、多分.toString()?たぶん、そのプロトタイプチェーン上の?コール「こと、およびその結果に最初から再スタート。「高性能」に最適化されたコードは、本質的にすべてのこれらの動的チェックをドロップするという考えに基づいて構築されます。それが証明する(または十分に高い確率で想定する)ことができるかどうかという:エンジン/コンパイラは事前に推論種類にいくつかの方法がある場合にのみ可能だということをx常に整数になるだろう、それだけで(その場合のコードを生成する必要があります根拠のない仮定が関与していた場合)型チェックによって守ら。

インライン化は、このすべてに直交しています。「ジェネリック」機能はまだインライン化することができます。いくつかのケースでは、コンパイラは、そこに多型を減らすためにインライン関数に型情報を伝播することができるかもしれません。

(比較のために:。。C ++、静的にコンパイル言語であること、関連する問題を解決するためのテンプレートを持っているでは短い、彼らは与えられた型にパラメータ化機能(またはクラス全体の専門コピー)を作成するようにコンパイラに指示明示的にプログラマを聞かせているのです素敵なあなたが使用することができ、いくつかのケースではなく、欠点の独自のセットを含まない溶液、例えば長いコンパイル時間と大きなバイナリ。JavaScriptは、もちろん、テンプレートのようなものを持っていません。evalその後、やや似てシステムを構築することはできます同様の欠点に「Dラン:あなたは、実行時にC ++コンパイラの仕事の同等の操作を行う必要があるだろう、とあなたがしている生成コードの膨大な量を心配する必要があるだろう)。

どのようにモジュール化、高性能コードがmegamorphic呼び出しサイトとdeoptimisationsのようなものの光にするライブラリの中にいますか?例えば、私は喜んで高速で線形代数パッケージAを使用していた場合、その後、(変更私のコードなしで)突然、私はAに依存したパッケージBをインポートしますが、Bは、他のタイプとそれを呼び出し、それをdeoptimises私のコードの実行が遅くなります。

はい、それはJavaScriptを使用して、一般的な問題です。V8は、特定のビルトイン(のようなものを実装するために使用されるArray.sort内部JavaScriptで)、そして(私たちは、「型フィードバック汚染」と呼ぶ)は、この問題は、我々は完全にその技術から離れて移動してきた主な理由の一つでした。

それは数値コードのために、存在しない、と述べたすべてのこと、多くの種類(のみSMISとダブルス)あなたは、彼らが型フィードバック汚染は確かに理論的な関心事であるので、一方で、実際には同様の性能を持ち、そしてべきで述べたように、いくつかのケースですることができます重大な影響を及ぼし、それはかなり可能性が高い線形代数のシナリオで使用すると、測定可能な違いを見ていないということもあります。

また、エンジン内部の「1種類==速い」と「複数の種類==遅い」よりも多くの状況があります。与えられた操作がSMISとダブルスの両方を見ている場合、それは完全に罰金です。配列の2種類から要素をロードすると、あまりにも結構です。私たちは、負荷はそれがそれらを個別に追跡をあきらめていますように、多くの異なる種類を見て、その代わりに、より汎用的なメカニズムを使用したときの状況について「megamorphic」という用語を使用してより良いタイプの多数の鱗 - ような負荷を含む機能することができますまだ最適化されます。「脱最適化は、」新しいタイプが以前に見られていないことがわかると、最適化されたコードは、したがって、ハンドルに装備されていないことをされているため、離れた機能のために最適化されたコードをスローするようになるのは非常に具体的な行為です。しかし、たとえそれは結構です。ただ、後で最適化、再び多くのタイプのフィードバックを収集するために最適化されていないコードに戻って、と。これが数回発生した場合、それは心配することは何もありません。それだけで、病理学的に悪い場合に問題となります。

あるものすべてをまとめて:それについて心配しないでくださいちょうどそれとのエンジン契約を聞かせて、合理的なコードを記述します。そして、「合理的」によって、私は意味:あなたのユースケースにとって意味のあるものを、読みやすい、保守性、効率的なアルゴリズムを使用して、配列の長さを超えて読んようなバグが含まれていません。理想的には、それがそこにある、とあなたは何もする必要はありませんすべてです。それはあなたがするより良い感じさせる場合は何かを、および/またはあなたが実際にパフォーマンスの問題を観察している場合、私は2つのアイデアを提供することができます:

活字体を使用することができます助けます。ビッグ脂肪警告:活字体のタイプは、開発者の生産を目指している、いない実行パフォーマンス(と、それは結局のところ、これらの2つの視点は、型システムから非常に異なる要件があります)。それはいくつかの重複がある、言った:例えば、あなた一貫注釈の事などあればnumber、あなたが誤って入れた場合は、その後、TSコンパイラは警告を表示しますnull数字だけを操作/含んになっています配列または関数に。もちろん、規律は必要です:シングルnumber_func(random_object as number)エスケープハッチは静かにすべてを弱体化させることができ、型注釈の正しさはどこにも施行されていないため。

TypedArraysを使用することもできます。彼らはより多くのオーバーヘッドがほとんどない、と彼らは成長できないので、彼らはあまり柔軟だ(あなたはその後、通常の配列は、おそらく、より効率的であり、多くの小さな配列を必要とするのであれば)通常のJavaScript配列に比べアレイあたり(メモリ消費量と配分スピード)または割り当て後に縮小し、彼らはすべての要素が1つだけの型を持っていることを保証を提供します。

JavaScriptエンジンがタイプで、内部でやっていることを確認するための測定ツールを使用して簡単に任意の良いはありますか?

いいえ、それは意図的なものです。上で説明したように、私たちは望んでいないあなたV8は今日特によく最適化することができ、そして私たちは、あなたが本当にどちらかそれをやりたいとは思わないどんなパターンに特に合わせてコードをします。物事のそのセットはどちらの方向に変更することができます:あなたが使用してみたいパターンがありますならば、我々は将来のバージョンでは、そのために最適化するかもしれません(私たちは以前に配列要素として箱なし32ビット整数を格納するアイデアをおもちゃにしています。.. 。それに仕事は)ノー約束ので、まだ開始されていません。私たちは過去のために最適化するために使用するパターンがあるかどう時には、我々はそれが他の、より重要/インパクトの最適化の邪魔になる場合ということをドロップすることを決定するかもしれません。また、インライン化ヒューリスティックのようなものは、権利を取得することが難しいことで知らあります その適切なタイミングで適切なインライン化の決定は、現在進行中の研究およびエンジン/コンパイラの動作に対応した変更の面積で作ります。これはこれ、それは誰にとっても不幸になる別のケース(あなたなりますそして私たちに)現在のブラウザのバージョンのいくつかのセットは約あなたが考える(あるいは知っている?)インライン化決定はそれだけで、その後、現在のブラウザを実現するために半年後に戻ってきて、最高ですんまで、あなたのコードを微調整に多くの時間を費やしている場合自分の経験則を変更しました。

最終的な選択は、特にエンジンが内部的に行われていないものを、重要なものだ - あなたは、もちろん、常に全体として、アプリケーションのパフォーマンスを測定することができます。彼らは誤解されているため、マイクロベンチマークに注意:あなたが唯一のコードとベンチマークこれらの2行を抽出する場合、チャンスはシナリオエンジンは非常に異なる決定を下すだろうということ(例えば、異なるタイプのフィードバック)十分に異なるものになるということです。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=369846&siteId=1