埓来のJavaScriptベンチマヌクに関する真実

画像



おそらく、JavaScriptは゜フトりェア開発で最も重芁な最新テクノロゞヌであるず蚀っおも十分でしょう。 プログラミング蚀語、コンパむラヌ、および仮想マシンを研究した倚くの人々にずっお、JavaScript蚀語の構造ずいう点でその優雅さがすべおコンパむルに関しおただ十分に最適化されおおらず、玠晎らしい暙準ラむブラリを誇るこずができないずいう事実は䟝然ずしお驚くべきこずです。 察話者が誰であるかに応じお、JavaScriptの欠陥を数週間にわたっおリストしおも、聞いたこずがないような奇劙なものを芋぀けるこずができたす。 しかし、明らかな欠陥にもかかわらず、今日、JavaScriptはWebの重芁な技術であり、サヌバヌ/クラりド領域での優䜍性に向かっおいたすNode.jsのおかげです。たた、モノのむンタヌネットにも浞透しおいたす。



質問は-なぜJavaScriptはそんなに人気があるのですか 包括的な答えがないのではないかず心配しおいたす。 今日、この蚀語を䜿甚する倚くの理由がありたすが、最も重芁なのはおそらく、JavaScriptず無数のリ゜ヌスを䞭心に構築された巚倧な゚コシステムです。 しかし、これはすべおある皋床の結果です。 そしお、なぜこの蚀語は最初に普及したのですか あなたは蚀うこずができたすなぜなら圌は長い間、りェブの共通語だったからです。 しかし、それはかなり前のこずであり、開発者はJavaScriptを情熱的に嫌っおいたした。 振り返っおみるず、JavaScriptの人気は2000幎代埌半に始たりたした。 ちょうどその頃、JavaScript゚ンゞンはさたざたな負荷ではるかに高速に動䜜し始め、おそらくこの蚀語に察する倚くの人々の態床に圱響を䞎えたした。



圓時、すべおのJSマむクロベンチマヌクの 先駆けであるApple SunSpiderからMozilla KrakenずGoogle V8たで、いわゆる䌝統的なJavaScriptベンチマヌクが速床の枬定に䜿甚されおいたした。 その埌、GoogleベンチマヌクはOctaneに取っお代わり、AppleはJetStreamをリリヌスしたした。 これらの埓来のベンチマヌクは、JavaScriptのパフォヌマンスを䞖玀の倉わり目に誰も予想しなかったような高さにするために、信じられないほどの努力をしおきたした。 数千の加速が蚘録され、突然<script>



䜿甚が悪魔ずのダンスでなくなり、クラむアント偎での蚈算の実行が可胜になっただけでなく、奚励されたした。







出兞 V8およびWeb Assemblyを䜿甚した高床なJSパフォヌマンス 、Chrome Developer Summit 2016、 @ s3ththompson



2016幎には、すべおの重芁なJS゚ンゞンが信じられないほどのパフォヌマンスを達成し、Webアプリケヌションはネむティブのものず同じくらい高速になりたしたたたは高速になりたす。 ゚ンゞンには、高床に最適化されたマシンコヌドの短いシヌケンスを生成する掗緎された最適化コンパむラが付属しおいたす。 これは、さたざたなタむプ/フォヌムで利甚可胜な統蚈に応じお、各操䜜プロパティ、バむナリ操䜜、比范、呌び出しなどぞのアクセスのタむプ/フォヌムタむプ/圢状を慎重に遞択するこずで実珟されたす。 これらの最適化の倧郚分は、SunSpiderやKrakenなどのマむクロベンチマヌク、およびOctaneやJetStreamなどの統蚈パッケヌゞによっお決定されたした。 asm.jsやEmscriptenなどのJavaScriptベヌスのテクノロゞヌのおかげで、今日ではJavaScriptで倧芏暡なC ++アプリケヌションをコンパむルし、ダりンロヌドやむンストヌルなしでブラりザヌで実行できたす。 たずえば、 AngryBotsでは簡単にオンラむンで簡単にプレむできたすが、以前はAdobe FlashやChrome PNaClなどの特別なプラグむンが必芁でした。



これらすべおの成果の倧郚分は、マむクロベンチマヌクずパフォヌマンス枬定パッケヌゞの存圚、および埓来のJSベンチマヌク間で生じた競争のおかげで可胜になりたした。 SunSpiderに぀いおは䜕でも蚀うこずができたすが、それなしではJavaScriptのパフォヌマンスが今日ずほずんど倉わらないこずは明らかです。



しかし、十分な賞賛、それはコむンの裏を芋おみる時間です。 すべおの枬定テストは、マむクロベンチマヌクであれ倧きなパッケヌゞであれ、時間が経぀に぀れお無関係になる運呜にありたす なんで ベンチマヌクは、あなたがそれで遊んで始めるたで、あなたに䜕かを教えるこずができるからです。 特定のしきい倀を超えるたたは超えないずすぐに、特定のベンチマヌクで埗られる最適化の䞀般的な適甚性は指数関数的に䜎䞋したす。



たずえば、Octaneをプロキシずしお䜿甚しお、実際のWebアプリケヌションのパフォヌマンスを枬定したした。 そしおしばらくの間、圌はこの仕事に非垞にうたく察凊したした。 しかし、今日では、Octaneず実際のアプリケヌションでの時間の分垃は倧きく異なるため、Octaneをさらに最適化しおも、実際のアプリケヌションNode.jsを含むが倧幅に改善されるこずはほずんどありたせん。







出兞 Real-World JavaScript Performance 、BlinkOn 6 Conference、 @ tverwaes



JetStreamずOctaneの最新バヌゞョンを含むJavaScriptパフォヌマンスを枬定するための埓来のベンチマヌクのすべおが時代遅れになっおいるようになったこずがたすたす明らかになったため、プロファむリングずV8およびChrome甚の新しいむンタヌセプタヌを远加しお、実際のアプリケヌションを枬定する新しい方法を探し始めたしたトレヌス。 たた、スクリプトの実行、ガベヌゞコレクション、コンパむルなど、サむトの閲芧により倚くの時間を費やすこずを理解するためにツヌルを䜿甚したした。 研究結果は非垞に興味深く、予想倖でした。 前の図からわかるように、Octaneを起動するず、70以䞊の時間がJavaScriptずガベヌゞコレクションに費やされたすが、JavaScriptを䜿甚したサむトの閲芧にかかる時間は垞に30未満であり、ガベヌゞコレクションにかかる時間は5以䞋です。 しかし、解析ずコンパむルには倚くの時間がかかり、Octaneに぀いおは蚀えたせん。 そのため、JavaScriptの実行を最適化するための盞圓な努力により、Octaneのオりムが倧幅に増加したすが、サむトの読み蟌みはそれほど速くありたせん。 さらに、JavaScriptの実行を最適化する趣味は、コンパむルに時間がかかるため、実際のアプリケヌションのパフォヌマンスを損なう可胜性がありたす。たたは、コンパむル、IC、ランタむムを拡匵する远加のパラメヌタヌを远跡する必芁がありたす。







JavaScript や DOMを含む、ブラりザ党䜓のパフォヌマンスを枬定しようずする別のベンチマヌクパッケヌゞがありたす Speedometer 。 圌は、さたざたな人気のあるWebフレヌムワヌクに実装されたシンプルなTodoMVCアプリケヌションを起動するこずで、より珟実的に枬定にアプロヌチしようずしたす今日は少し時代遅れですが、新しいバヌゞョンがすでに䜜成されおいたす。 パッケヌゞには、新しいテスト角床、゚ンバヌ、反応、バニラ、フラむト、バックボヌンが含たれおいたす。 今日たで、スピヌドメヌタヌは実際のアプリケヌションのパフォヌマンスを枬定するための最も奜たしいプロキシの圹割のようです。 ただし、これは2016幎半ばのデヌタであり、Webで䜿甚されるパタヌンが開発されるず、すべおが既に倉曎される可胜性があるこずに泚意しおくださいたずえば、ICシステムをリファクタリングしおコストを倧幅に削枛し、パヌサヌを再蚭蚈したす 。 䞊蚘の状況はサむトの閲芧にのみ関係しおいるようですが、実際のNode.jsアプリケヌションの堎合、埓来のピヌクパフォヌマンスのベンチマヌクはプロキシロヌルに察しおあたりうたく機胜しないずいう非垞に説埗力のある蚌拠を受け取りたした。







出兞 Real-World JavaScript Performance 、BlinkOn 6 Conference、 @ tverwaes



おそらくこれはすべお幅広い読者にすでに知られおいるので、JSコミュニティが有甚である理由を説明するいく぀かの具䜓的な䟋だけを取り䞊げたすが、ある時点でピヌクパフォヌマンスの静的ベンチマヌクに泚意を払わないこずが非垞に重芁です。 JS゚ンゞンがどのようにベンチマヌクに合栌し、実際にどのようにそれを行うかの䟋から始めたしょう。



悪名高いSunSpiderの䟋



埓来のJSベンチマヌクに関する蚘事は、SunSpiderの明らかな問題に぀いお蚀及しおいなければ䞍完党です。 実際の状況での適甚性が制限されおいるパフォヌマンステスト、 bitops-bitwise-and.jsから始めたしょう。







特にC / C ++からJavaScriptぞのトランスパむルコヌドでは、高速なビット単䜍のAND挔算を必芁ずするアルゎリズムがいく぀かありたす。 ただし、Webペヌゞが、゚ンゞンが他の゚ンゞンの2倍の速床でビット単䜍のAND挔算を実行できるかどうかを考慮するこずはほずんどありたせん。 おそらく、サむクルの最初の反埩の埌、bitwiseAndValueが0に等しくなり、次の599,999の反埩の間はその倀のたたになるこずに気づいたでしょう。 したがっお、良奜なパフォヌマンスで、぀たりたずもなハヌドりェアで5ミリ秒を超えお実行するずすぐに、このサむクルの最初の反埩のみが必芁であり、残りはすべお時間の無駄぀たり、デッドコヌド埌であるこずを理解しようずしお、このベンチマヌクの远跡を開始できたす切断サむクル 。 このJavaScriptぞの倉換を実行するには、以䞋を確認する必芁がありたす。





しかし、本圓にベンチマヌクに勝ちたいず思っおおり、このための準備ができおいる堎合は、1 ms未満でテストを実行できたす。 しかし、最適化の適甚可胜性はこの特定のケヌスによっおのみ制限され、テストぞの小さな倉曎はおそらく動䜜に぀ながりたせん。



぀たり、 bitops-bitwise-and.jsテストは、 マむクロベンチマヌクの最悪の䟋でした。 より実甚的な䟋に移りたしょう-string-tagcloud.js test 。 実際、json.js json.js



非垞に初期のバヌゞョンをjson.js



たす。 おそらく、このテストは以前のテストよりもはるかに合理的に芋えるでしょう。 しかし、ベンチマヌクプロファむルを詳しく芋るず、圌が単䞀のeval



匏に倚くの時間を費やしおいるこずが明らかになりたす解析およびコンパむルの合蚈実行時間の最倧20、コンパむルされたコヌドの実際の実行でも10たで。







よく芋おみたしょう eval



は䞀床だけ実行され、 tag



ずpopularity



フィヌルドを持぀2501オブゞェクトの配列を含むJSON文字列に枡されたす



  ([ { "tag": "titillation", "popularity": 4294967296 }, { "tag": "foamless", "popularity": 1257718401 }, { "tag": "snarler", "popularity": 613166183 }, { "tag": "multangularness", "popularity": 368304452 }, { "tag": "Fesapo unventurous", "popularity": 248026512 }, { "tag": "esthesioblast", "popularity": 179556755 }, { "tag": "echeneidoid", "popularity": 136641578 }, { "tag": "embryoctony", "popularity": 107852576 }, ... ])
      
      





明らかに、これらのオブゞェクトリテラルを解析し、ネむティブコヌドを生成しお実行するのは高䟡です。 入力文字列をJSONずしお解析し、察応するオブゞェクトグラフを生成する方がはるかに安䟡です。 ベンチマヌクの結果を改善するには、最初にeval



をJSONずしお解釈し、JSONずしお読み取れない堎合にのみ実際に解析、コンパむル、および実行を詊みるこずができたすただし、括匧をスキップするには远加の魔法が必芁です。 2007幎には、 JSON.parseがただ存圚しおいなかったため、これは悪いハックではなかったでしょう。 そしお、2017幎たでに、これはJavaScript゚ンゞンの技術的矩務に倉わり、 eval



の䜿甚を遅くする可胜性がありたした。 基本的に最新のJavaScriptにベンチマヌクを曎新する



 --- string-tagcloud.js.ORIG 2016-12-14 09:00:52.869887104 +0100 +++ string-tagcloud.js 2016-12-14 09:01:01.033944051 +0100 @@ -198,7 +198,7 @@ replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(:?[eE][+\-]?\d+)?/g, ']'). replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - j = eval('(' + this + ')'); + j = JSON.parse(this); return typeof filter === 'function' ? walk('', j) : j; }
      
      





生産性の即時向䞊に぀ながりたす。珟圚、V8 LKGRのランタむムは36ミリ秒から26ミリ秒に短瞮され、30の改善がありたす。



 $ node string-tagcloud.js.ORIG Time (string-tagcloud): 36 ms. $ node string-tagcloud.js Time (string-tagcloud): 26 ms. $ node -v v8.0.0-pre $
      
      





これは、静的ベンチマヌクずパフォヌマンステストパッケヌゞの䞀般的な問題です。 今日、誰も真剣にeval



を䜿甚しおJSONデヌタを解析したせんパフォヌマンスだけでなくセキュリティのため。 代わりに、過去5幎間に蚘述されたすべおのコヌドはJSON.parseを䜿甚したす 。 さらに、実皌働環境でJSONを解析するためにeval



を䜿甚するこずはバグず芋なすこずができたす したがっお、この叀代のベンチマヌクでは、比范的最近䜜成されたコヌドの生産性を高めるための゚ンゞンの䜜成者の努力は考慮されおいたせん。 代わりに、 string-tagcloud.js



で良い結果を埗るために、 eval



䞍必芁に耇雑にするこずが有甚でしょう。



別の䟋-3d-cube.jsに進みたしょう。 このベンチマヌクは、倚くの行列挔算を実行したす。これにより、最もむンテリゞェントなコンパむラヌでさえ、単に実行するこずしかできたせん。 ベンチマヌクは、ルヌプ関数ずそれが呌び出す関数の実行に倚くの時間を費やしたす。







興味深い芳察関数RotateX



、 RotateY



RotateZ



垞に定数パラメヌタヌPhi



呌び出されたす。







これは、 Math.sinずMath.cosに察しお垞に204回同じ倀を蚈算するこずを意味したす。 入力倀は3぀のみです。





同じ正匊倀ず䜙匊倀の䞍必芁な蚈算を避けるために、以前に蚈算された倀をキャッシュできたす。 以前は、V8はたさにそれを行いたしたが、他のすべおの゚ンゞンはただそうしおいたす。 V8から超越キャッシュず呌ばれるものを削陀したした。これは、連続した同じ倀を垞に蚈算するずは限らないずきに、実際の負荷の䞋で冗長性が顕著だったためです。 SunSpiderベンチマヌクの結果で倚く倱敗し、この特定の最適化を削陀したしたが、ベンチマヌク甚に最適化するず同時に、実際のプロゞェクトの結果を悪化させるこずは意味がないず確信しおいたす。







゜ヌス arewefastyet.com



明らかに、そのような定数を䜿甚する最良の方法-入力正匊/䜙匊-は、通垞のむンラむンヒュヌリスティックヒュヌリスティックです。これは、眮換のバランスを取り、定数フォヌルディングが有甚な堎合に呌び出しポむントでの眮換蚭定などのさたざたな芁因を考慮しようずしたす定数フォヌルディング RotateX



、 RotateY



、 RotateZ



の堎合ずRotateZ



。 しかし、いく぀かの理由から、これはクランクシャフトコンパむラには適しおいたせんでした。 ただし、これはIgnitionおよびTurboFanの堎合の合理的なオプションであり、代替ヒュヌリスティックの改善に既に取り組んでいたす。



ガベヌゞコレクションは有害ず芋なされたす



特定のケヌスに加えお、SunSpiderには別の基本的な問題がありたす。それは、合蚈実行時間です。 珟圚、適切なIntelハヌドりェアでは、V8゚ンゞンは玄200ミリ秒でベンチマヌク党䜓を実行したす新しいスペヌスの生きおいるオブゞェクトず叀いスペヌスの断片化に䟝存したすが、ガベヌゞコレクションの䞻芁な䞀時停止は簡単に30ミリ秒に達したす。 たた、むンクリメンタルマヌキングのコストは考慮されおいたせん。これは、SunSpiderパッケヌゞの合蚈実行時間の10以䞊です。 したがっお、ガベヌゞコレクションのために゚ンゞンの速床が10〜20䜎䞋したくない堎合は、SunSpiderの実行䞭に゚ンゞンが開始されないようにする必芁がありたす。







このために、さたざたなトリックが䜿甚されたすが、それらすべおは、私が知る限り、実際のタスクにプラスの効果はありたせん。 V8はそれを行いたす各SunSpiderテストは、新しいネむティブコンテキストに察応する新しい<iframe>



で実行されるため、 <iframe>



の䜜成ず配眮を登録するだけです各SunSpiderテストに費やす時間は50ミリ秒未満です。 そしお、テスト䞭ではなく、配眮手順ず䜜成手順の間でガベヌゞコレクションが実行されたす。 このトリックはうたく機胜し、99.99のケヌスでは実際のプロゞェクトには圱響したせん。 しかし、V8がアプリケヌションがSunSpiderテストのように芋えるず刀断した堎合、ガベヌゞコレクタヌが匷制的に実行され、これが䜜業速床に悪圱響を及がしたす。 したがっお、アプリケヌションをSunSpiderのように芋せないでください 。



SunSpiderに関連する他の䟋を挙げるこずはできたすが、圹に立぀ずは思いたせん。 優れたパフォヌマンスの結果を䞊回るためにSunSpiderを最適化するこずは、実際のアプリケヌションには意味がないこずは、すでに明らかであるこずを願っおいたす。 ゚ンゞンはこのパッケヌゞにのみ有甚で、実際の状況では有害になる可胜性のある奇劙なハックを䜿甚できるため、SunSpiderがもうなかったら䞖界は恩恵を受けるず思いたす。



残念ながら、蚘者がブラりザのパフォヌマンスをどのように考えおいるかを比范するずき、SunSpiderは䟝然ずしおマスコミで非垞に頻繁に䜿甚されおいたす。 たたは、さらに悪いこずに、スマヌトフォンを比范したす もちろん、メヌカヌの関心もここに瀺されおいたす。 Androidキャンプは、ChromeがSunSpiderおよびその他の無意味なベンチマヌクで良奜な結果を瀺すこずが重芁です。 スマヌトフォンメヌカヌは補品を販売するこずで皌ぐ必芁があり、これには良いレビュヌが必芁です。 䞀郚の䌁業は、V8の叀いバヌゞョンをスマヌトフォンに搭茉しお出荷しおいるため、SunSpiderでより良い結果を瀺しおいたす。 その結果、ナヌザヌは閉じられおいないセキュリティホヌルに陥りたすが、これは埌のバヌゞョンで修正されおいたす。 さらに、実際にはV8の叀いバヌゞョンはより遅く動䜜したす







出兞Galaxy S7およびS7 Edgeのレビュヌサムスンの最高の技術をさらに磚き䞊げるwww.engadget.com



JavaScriptコミュニティが客芳的なパフォヌマンスデヌタを取埗するこずに本圓に関心がある堎合、ゞャヌナリストがブラりザヌずスマヌトフォンを比范するずきに埓来のベンチマヌクの䜿甚を停止する必芁がありたす。 各ブラりザでベンチマヌクを実行し、取埗した数倀を比范する方が簡単であるこずを理解しおいたすが、その堎合は、どうかお問い合わせください。 -少なくずも䜕らかの圢で珟圚の状況に察応するベンチマヌクに泚意しおください。 それが本圓のりェブペヌゞです。 ブラりザのベンチマヌクで2台のスマヌトフォンを比范する必芁がある堎合は、少なくずもSpeedometerを䜿甚しおください 。



クラヌケンずのそれほど明癜でない状況



Krakenベンチマヌクは、2010幎9月にMozillaによっおリリヌスされたした 。 コヌドの断片ず実際のアプリケヌションのコアが含たれおいるず䞻匵されたした。 クラヌケンは、SunSpiderやOctaneほどJavaScriptのパフォヌマンスに圱響を䞎えおいないため、あたり時間をかけたせん。 audio-oscillator.jsテストの䟋のみを説明したす。







テストは500回、 calcOsc



関数を呌び出したす。 最初に、 sine Oscillator



グロヌバルに察しおgenerate



を呌び出し、次に新しいOscillator



䜜成し、それに察しおgenerateを呌び出しお、それをsine Oscillator



远加したす。 ここでこれが行われる理由に぀いお詳しくは説明したせんが、 Oscillator



プロトタむプのgenerate



メ゜ッドを芋おみたしょう。







コヌドを芋るず、倧郚分の時間は配列ぞのアクセス、乗算、たたはMath.roundの埪環呌び出しで占められおいるず想定できたす。 runtime Oscillator.prototype.generate



offset % this.waveTableLength



. Intel-, , 20 % idiv



, (modulus). : waveTableLength



Oscillator 2048, Oscillator



.







, — , Intel idiv



. calcOsc



/. sine Oscillator



, calcOsc



.



, . V8 - , +



, *



%



, , , (. Fast arithmetic for dynamic languages ).



fullcodegen Crankshaft, BinaryOpIC



MOD



. V8 (c Crankshaft fullcodegen)



 $ ~/Projects/v8/out/Release/d8 --trace-ic audio-oscillator.js [...SNIP...] [BinaryOpIC(MOD:None*None->None) => (MOD:Smi*2048->Smi) @ ~Oscillator.generate+598 at audio-oscillator.js:697] [...SNIP...] $
      
      





, BinaryOpIC



(constant feedback) , , ( Smi



V8), . --print-opt-code --code-comments



, , Crankshaft Oscillator.prototype.generate



:



  [...SNIP...] ;;; <@80,#84> load-named-field 0x133a0bdacc4a 330 8b4343 movl rax,[rbx+0x43] ;;; <@83,#86> compare-numeric-and-branch 0x133a0bdacc4d 333 3d00080000 cmp rax,0x800 0x133a0bdacc52 338 0f85ff000000 jnz 599 (0x133a0bdacd57) [...SNIP...] ;;; <@90,#94> mod-by-power-of-2-i 0x133a0bdacc5b 347 4585db testl r11,r11 0x133a0bdacc5e 350 790f jns 367 (0x133a0bdacc6f) 0x133a0bdacc60 352 41f7db negl r11 0x133a0bdacc63 355 4181e3ff070000 andl r11,0x7ff 0x133a0bdacc6a 362 41f7db negl r11 0x133a0bdacc6d 365 eb07 jmp 374 (0x133a0bdacc76) 0x133a0bdacc6f 367 4181e3ff070000 andl r11,0x7ff [...SNIP...] ;;; <@127,#88> deoptimize 0x133a0bdacd57 599 e81273cdff call 0x133a0ba8406e [...SNIP...]
      
      





, this.waveTableLength



( rbx



this



), , 2048 ( 0x800). , idiv



( r11



i



), .





, , , , : ! , ( , ). idiv



, BinaryOpIC



Smi*Smi->Smi



. , Oscillator



, waveTableLength



generate



. 20 % , Oscillator



'; (non-local penalization).



 --- audio-oscillator.js.ORIG 2016-12-15 22:01:43.897033156 +0100 +++ audio-oscillator.js 2016-12-15 22:02:26.397326067 +0100 @@ -1931,6 +1931,10 @@ var frequency = 344.53; var sine = new Oscillator(Oscillator.Sine, frequency, 1, bufferSize, sampleRate); +var unused = new Oscillator(Oscillator.Sine, frequency, 1, bufferSize, sampleRate); +unused.waveTableLength = 1024; +unused.generate(); + var calcOsc = function() { sine.generate();
      
      





audio-oscillator.js



, Oscillator



waveTableLength



, :



 $ ~/Projects/v8/out/Release/d8 audio-oscillator.js.ORIG Time (audio-oscillator-once): 64 ms. $ ~/Projects/v8/out/Release/d8 audio-oscillator.js Time (audio-oscillator-once): 81 ms. $
      
      





. , , , . , , . , - - BinaryOpIC



, 20- ( , ). , , .



JavaScript. , , JavaScript . , , () . , idiv



, , ( ). TurboFan, Crankshaft, runtime , , () ():



 if 0 < rhs then msk = rhs - 1 if rhs & msk != 0 then lhs % rhs else if lhs < 0 then -(-lhs & msk) else lhs & msk else if rhs < -1 then lhs % rhs else zero
      
      





( TurboFan):



 $ ~/Projects/v8/out/Release/d8 --turbo audio-oscillator.js.ORIG Time (audio-oscillator-once): 69 ms. $ ~/Projects/v8/out/Release/d8 --turbo audio-oscillator.js Time (audio-oscillator-once): 69 ms. $
      
      





, , , , , . , JS- , Kraken , TurboFan. TurboFan Crankshaft, , , , ! , , , , . . . , , , .



Kraken , JS- — Octane.



Octane



Octane — V8. Google 2012 , Octane 2.0 — 2013- . 15 , — Splay Mandreel — (throughput) . , Microsofts TypeScript, asm.js zlib, (ray tracer), . . JavaScript, 2012 .



, Octane JavaScript 2012—2013-. . Octane (, TypeScript zlib Emscripten , Mandreel ).



, Ember AngularJS , JavaScript, Octane () . JavaScript , JS- , , Octane. , , Octane .



Octane, . , ! , Octane — JavaScript, . , JS- , , Octane — ! , , !



Box2D, Box2DWeb , , JavaScript. , JS- . , , , ( ). D.prototype.UpdatePairs



():



 D.prototype.UpdatePairs = function(b) { var e = this; var f = e.m_pairCount = 0, m; for (f = 0; f < e.m_moveBuffer.length; ++f) { m = e.m_moveBuffer[f]; var r = e.m_tree.GetFatAABB(m); e.m_tree.Query(function(t) { if (t == m) return true; if (e.m_pairCount == e.m_pairBuffer.length) e.m_pairBuffer[e.m_pairCount] = new O; var x = e.m_pairBuffer[e.m_pairCount]; x.proxyA = t < m ? t : m; x.proxyB = t >= m ? t : m; ++e.m_pairCount; return true }, r) } for (f = e.m_moveBuffer.length = 0; f < e.m_pairCount;) { r = e.m_pairBuffer[f]; var s = e.m_tree.GetUserData(r.proxyA), v = e.m_tree.GetUserData(r.proxyB); b(s, v); for (++f; f < e.m_pairCount;) { s = e.m_pairBuffer[f]; if (s.proxyA != r.proxyA || s.proxyB != r.proxyB) break; ++f } } };
      
      





, , e.m_tree.Query



:



 function(t) { if (t == m) return true; if (e.m_pairCount == e.m_pairBuffer.length) e.m_pairBuffer[e.m_pairCount] = new O; var x = e.m_pairBuffer[e.m_pairCount]; x.proxyA = t < m ? t : m; x.proxyB = t >= m ? t : m; ++e.m_pairCount; return true }
      
      





, , . 4—7 % runtime- Compare , (abstract relational comparison).







runtime- CompareICStub , :



 x.proxyA = t < m ? t : m; x.proxyB = t >= m ? t : m;
      
      





99 % ! どうしお , JavaScript, . t



m



— L



, . Symbol.toPrimitive



, "toString"



, "valueOf"



Symbol.toStringTag



, . t < m



, :



  1. ToPrimitive ( t



    , hint Number



    ).
  2. OrdinaryToPrimitive ( t



    , "number"



    ), Symbol.toPrimitive



    .
  3. t.valueOf()



    , t



    , Object.prototype.valueOf .
  4. t.toString()



    , "[object Object]"



    , Object.prototype.toString , Symbol.toStringTag L



    .
  5. ToPrimitive ( m



    , hint Number



    ).
  6. OrdinaryToPrimitive ( m



    , "number"



    ), Symbol.toPrimitive.
  7. m.valueOf()



    , m, Object.prototype.valueOf .
  8. m.toString()



    , "[object Object]"



    , Object.prototype.toString , Symbol.toStringTag L



    .
  9. "[object Object]" < "[object Object]"



    ,
。



t >= m



, true



. , . : , :



 --- octane-box2d.js.ORIG 2016-12-16 07:28:58.442977631 +0100 +++ octane-box2d.js 2016-12-16 07:29:05.615028272 +0100 @@ -2021,8 +2021,8 @@ if (t == m) return true; if (e.m_pairCount == e.m_pairBuffer.length) e.m_pairBuffer[e.m_pairCount] = new O; var x = e.m_pairBuffer[e.m_pairCount]; - x.proxyA = t < m ? t : m; - x.proxyB = t >= m ? t : m; + x.proxyA = m; + x.proxyB = t; ++e.m_pairCount; return true },
      
      





13 %, :



 $ ~/Projects/v8/out/Release/d8 octane-box2d.js.ORIG Score (Box2D): 48063 $ ~/Projects/v8/out/Release/d8 octane-box2d.js Score (Box2D): 55359 $
      
      





? , , CompareIC



: (map) (known receiver map tracking) ( V8 map — + ). . :



 $ ~/Projects/v8/out/Release/d8 --trace-ic octane-box2d.js [...SNIP...] [CompareIC in ~+557 at octane-box2d.js:2024 ((UNINITIALIZED+UNINITIALIZED=UNINITIALIZED)->(RECEIVER+RECEIVER=KNOWN_RECEIVER))#LT @ 0x1d5a860493a1] [CompareIC in ~+649 at octane-box2d.js:2025 ((UNINITIALIZED+UNINITIALIZED=UNINITIALIZED)->(RECEIVER+RECEIVER=KNOWN_RECEIVER))#GTE @ 0x1d5a860496e1] [...SNIP...] $
      
      





CompareIC



, « » « » RECEIVER



' (JavaScript- V8). (map) 0x1d5a860493a1



, L



. false



true



, : — 0x1d5a860493a1



. L



, the Symbol.toPrimitive



, "valueOf"



"toString"



. Symbol.toStringTag



. Crankshaft Symbol.toStringTag



:







:







: , . , , , JS- . , ! , ( , true



false



, ). , , . ES2015, , (ES2015 — !).



Mandreel. C/C++ JavaScript. asm.js , Emscripten , ( ). Octane Bullet , Mandreel . MandreelLatency, . , Mandreel , . , . , . , .







Mandreel global_init



, . , ( ), , , ( ). V8 . , , , . global_init



Mandreel , + + . global_init



, .







: arewefastyet.com .



global_init



, 200- . , , , , ( ).



, — splay.js . , (splay trees) ( ). : . (buckets) , . ! 理論的には。 , :







, , , , SplayLatency. なんで , , . , (generational garbage collector), V8: ( generational hypothesis ), . V8 :



 $ out/Release/d8 --trace-gc --noallocation_site_pretenuring octane-splay.js [20872:0x7f26f24c70d0] 10 ms: Scavenge 2.7 (6.0) -> 2.7 (7.0) MB, 1.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 12 ms: Scavenge 2.7 (7.0) -> 2.7 (8.0) MB, 1.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 14 ms: Scavenge 3.7 (8.0) -> 3.6 (10.0) MB, 0.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 18 ms: Scavenge 4.8 (10.5) -> 4.7 (11.0) MB, 2.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 22 ms: Scavenge 5.7 (11.0) -> 5.6 (16.0) MB, 2.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 28 ms: Scavenge 8.7 (16.0) -> 8.6 (17.0) MB, 4.3 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 35 ms: Scavenge 9.6 (17.0) -> 9.6 (28.0) MB, 6.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 49 ms: Scavenge 16.6 (28.5) -> 16.4 (29.0) MB, 8.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 65 ms: Scavenge 17.5 (29.0) -> 17.5 (52.0) MB, 15.3 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 93 ms: Scavenge 32.3 (52.5) -> 32.0 (53.5) MB, 17.6 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 126 ms: Scavenge 33.4 (53.5) -> 33.3 (68.0) MB, 31.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 151 ms: Scavenge 47.9 (68.0) -> 47.6 (69.5) MB, 15.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 183 ms: Scavenge 49.2 (69.5) -> 49.2 (84.0) MB, 30.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 210 ms: Scavenge 63.5 (84.0) -> 62.4 (85.0) MB, 14.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 241 ms: Scavenge 64.7 (85.0) -> 64.6 (99.0) MB, 28.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 268 ms: Scavenge 78.2 (99.0) -> 77.6 (101.0) MB, 16.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 298 ms: Scavenge 80.4 (101.0) -> 80.3 (114.5) MB, 28.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 324 ms: Scavenge 93.5 (114.5) -> 92.9 (117.0) MB, 16.4 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 354 ms: Scavenge 96.2 (117.0) -> 96.0 (130.0) MB, 27.6 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 383 ms: Scavenge 108.8 (130.0) -> 108.2 (133.0) MB, 16.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 413 ms: Scavenge 111.9 (133.0) -> 111.7 (145.5) MB, 27.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 440 ms: Scavenge 124.1 (145.5) -> 123.5 (149.0) MB, 17.4 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 473 ms: Scavenge 127.6 (149.0) -> 127.4 (161.0) MB, 29.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 502 ms: Scavenge 139.4 (161.0) -> 138.8 (165.0) MB, 18.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 534 ms: Scavenge 143.3 (165.0) -> 143.1 (176.5) MB, 28.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 561 ms: Scavenge 154.7 (176.5) -> 154.2 (181.0) MB, 19.0 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 594 ms: Scavenge 158.9 (181.0) -> 158.7 (192.0) MB, 29.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 622 ms: Scavenge 170.0 (192.5) -> 169.5 (197.0) MB, 19.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 655 ms: Scavenge 174.6 (197.0) -> 174.3 (208.0) MB, 28.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 683 ms: Scavenge 185.4 (208.0) -> 184.9 (212.5) MB, 19.4 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 715 ms: Scavenge 190.2 (213.0) -> 190.0 (223.5) MB, 27.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 743 ms: Scavenge 200.7 (223.5) -> 200.3 (228.5) MB, 19.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 774 ms: Scavenge 205.8 (228.5) -> 205.6 (239.0) MB, 27.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 802 ms: Scavenge 216.1 (239.0) -> 215.7 (244.5) MB, 19.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 833 ms: Scavenge 221.4 (244.5) -> 221.2 (254.5) MB, 26.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 861 ms: Scavenge 231.5 (255.0) -> 231.1 (260.5) MB, 19.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 892 ms: Scavenge 237.0 (260.5) -> 236.7 (270.5) MB, 26.3 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 920 ms: Scavenge 246.9 (270.5) -> 246.5 (276.0) MB, 20.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 951 ms: Scavenge 252.6 (276.0) -> 252.3 (286.0) MB, 25.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 979 ms: Scavenge 262.3 (286.0) -> 261.9 (292.0) MB, 20.3 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1014 ms: Scavenge 268.2 (292.0) -> 267.9 (301.5) MB, 29.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1046 ms: Scavenge 277.7 (302.0) -> 277.3 (308.0) MB, 22.4 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1077 ms: Scavenge 283.8 (308.0) -> 283.5 (317.5) MB, 25.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1105 ms: Scavenge 293.1 (317.5) -> 292.7 (323.5) MB, 20.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1135 ms: Scavenge 299.3 (323.5) -> 299.0 (333.0) MB, 24.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1164 ms: Scavenge 308.6 (333.0) -> 308.1 (339.5) MB, 20.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1194 ms: Scavenge 314.9 (339.5) -> 314.6 (349.0) MB, 25.0 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1222 ms: Scavenge 324.0 (349.0) -> 323.6 (355.5) MB, 21.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1253 ms: Scavenge 330.4 (355.5) -> 330.1 (364.5) MB, 25.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1282 ms: Scavenge 339.4 (364.5) -> 339.0 (371.0) MB, 22.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1315 ms: Scavenge 346.0 (371.0) -> 345.6 (380.0) MB, 25.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1413 ms: Mark-sweep 349.9 (380.0) -> 54.2 (305.0) MB, 5.8 / 0.0 ms (+ 87.5 ms in 73 steps since start of marking, biggest step 8.2 ms, walltime since start of marking 131 ms) finalize incremental marking via stack guard GC in old space requested [20872:0x7f26f24c70d0] 1457 ms: Scavenge 65.8 (305.0) -> 65.1 (305.0) MB, 31.0 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1489 ms: Scavenge 69.9 (305.0) -> 69.7 (305.0) MB, 27.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1523 ms: Scavenge 80.9 (305.0) -> 80.4 (305.0) MB, 22.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1553 ms: Scavenge 85.5 (305.0) -> 85.3 (305.0) MB, 24.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1581 ms: Scavenge 96.3 (305.0) -> 95.7 (305.0) MB, 18.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1616 ms: Scavenge 101.1 (305.0) -> 100.9 (305.0) MB, 29.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1648 ms: Scavenge 111.6 (305.0) -> 111.1 (305.0) MB, 22.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1678 ms: Scavenge 116.7 (305.0) -> 116.5 (305.0) MB, 25.0 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1709 ms: Scavenge 127.0 (305.0) -> 126.5 (305.0) MB, 20.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1738 ms: Scavenge 132.3 (305.0) -> 132.1 (305.0) MB, 23.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1767 ms: Scavenge 142.4 (305.0) -> 141.9 (305.0) MB, 19.6 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1796 ms: Scavenge 147.9 (305.0) -> 147.7 (305.0) MB, 23.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1825 ms: Scavenge 157.8 (305.0) -> 157.3 (305.0) MB, 19.9 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1853 ms: Scavenge 163.5 (305.0) -> 163.2 (305.0) MB, 22.2 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1881 ms: Scavenge 173.2 (305.0) -> 172.7 (305.0) MB, 19.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1910 ms: Scavenge 179.1 (305.0) -> 178.8 (305.0) MB, 23.0 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1944 ms: Scavenge 188.6 (305.0) -> 188.1 (305.0) MB, 25.1 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 1979 ms: Scavenge 194.7 (305.0) -> 194.4 (305.0) MB, 28.4 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 2011 ms: Scavenge 204.0 (305.0) -> 203.6 (305.0) MB, 23.4 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 2041 ms: Scavenge 210.2 (305.0) -> 209.9 (305.0) MB, 23.8 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 2074 ms: Scavenge 219.4 (305.0) -> 219.0 (305.0) MB, 24.5 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 2105 ms: Scavenge 225.8 (305.0) -> 225.4 (305.0) MB, 24.7 / 0.0 ms allocation failure [20872:0x7f26f24c70d0] 2138 ms: Scavenge 234.8 (305.0) -> 234.4 (305.0) MB, 23.1 / 0.0 ms allocation failure [...SNIP...] $
      
      





: ( ). , allocation site pretenuring . (allocation sites), , . , — pretenure .



 $ out/Release/d8 --trace-gc octane-splay.js [20885:0x7ff4d7c220a0] 8 ms: Scavenge 2.7 (6.0) -> 2.6 (7.0) MB, 1.2 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 10 ms: Scavenge 2.7 (7.0) -> 2.7 (8.0) MB, 1.6 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 11 ms: Scavenge 3.6 (8.0) -> 3.6 (10.0) MB, 0.9 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 17 ms: Scavenge 4.8 (10.5) -> 4.7 (11.0) MB, 2.9 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 20 ms: Scavenge 5.6 (11.0) -> 5.6 (16.0) MB, 2.8 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 26 ms: Scavenge 8.7 (16.0) -> 8.6 (17.0) MB, 4.5 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 34 ms: Scavenge 9.6 (17.0) -> 9.5 (28.0) MB, 6.8 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 48 ms: Scavenge 16.6 (28.5) -> 16.4 (29.0) MB, 8.6 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 64 ms: Scavenge 17.5 (29.0) -> 17.5 (52.0) MB, 15.2 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 96 ms: Scavenge 32.3 (52.5) -> 32.0 (53.5) MB, 19.6 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 153 ms: Scavenge 61.3 (81.5) -> 57.4 (93.5) MB, 27.9 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 432 ms: Scavenge 339.3 (364.5) -> 326.6 (364.5) MB, 12.7 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 666 ms: Scavenge 563.7 (592.5) -> 553.3 (595.5) MB, 20.5 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 825 ms: Mark-sweep 603.9 (644.0) -> 96.0 (528.0) MB, 4.0 / 0.0 ms (+ 92.5 ms in 51 steps since start of marking, biggest step 4.6 ms, walltime since start of marking 160 ms) finalize incremental marking via stack guard GC in old space requested [20885:0x7ff4d7c220a0] 1068 ms: Scavenge 374.8 (528.0) -> 362.6 (528.0) MB, 19.1 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 1304 ms: Mark-sweep 460.1 (528.0) -> 102.5 (444.5) MB, 10.3 / 0.0 ms (+ 117.1 ms in 59 steps since start of marking, biggest step 7.3 ms, walltime since start of marking 200 ms) finalize incremental marking via stack guard GC in old space requested [20885:0x7ff4d7c220a0] 1587 ms: Scavenge 374.2 (444.5) -> 361.6 (444.5) MB, 13.6 / 0.0 ms allocation failure [20885:0x7ff4d7c220a0] 1828 ms: Mark-sweep 485.2 (520.0) -> 101.5 (519.5) MB, 3.4 / 0.0 ms (+ 102.8 ms in 58 steps since start of marking, biggest step 4.5 ms, walltime since start of marking 183 ms) finalize incremental marking via stack guard GC in old space requested [20885:0x7ff4d7c220a0] 2028 ms: Scavenge 371.4 (519.5) -> 358.5 (519.5) MB, 12.1 / 0.0 ms allocation failure [...SNIP...] $
      
      





SplayLatency 250 %!







: arewefastyet.com .



SIGPLAN , , allocation site pretenuring . , . ( 1 , 2 , 3 ), allocation site pretenuring . , Ember.js (, - allocation site pretenuring).



allocation site pretenuring, , — , ( - , ). , , , (-) (-) (allocation site) tenured , . - , , , (incremental marking).



. , , Orinoco . (unified heap), , . : , , . , SplayLatency , . . (concurrent marking) , (throughput).



おわりに



, , , - . , , , ! , . , , .







: 2016-: Chrome vs. Firefox vs. Edge, venturebeat.com .



, — . , JavaScript . , , . , Node.js ( V8, ChakraCore)!







: JavaScript- . , . JavaScript , . Chrome , . , , Speedometer , - .



よろしくお願いしたす



All Articles