<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[201957] trunk/PerformanceTests</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/201957">201957</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-06-10 17:48:43 -0700 (Fri, 10 Jun 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Air.js should have some documentation
https://bugs.webkit.org/show_bug.cgi?id=158648

Reviewed by Keith Miller.
        
I want to be able to point people at a document if they want to know more about this
benchmark.

* Air.js/README.md: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsAirjsREADMEmd">trunk/PerformanceTests/Air.js/README.md</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsAirjsREADMEmd"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/Air.js/README.md (0 => 201957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Air.js/README.md                                (rev 0)
+++ trunk/PerformanceTests/Air.js/README.md        2016-06-11 00:48:43 UTC (rev 201957)
</span><span class="lines">@@ -0,0 +1,147 @@
</span><ins>+# All about Air.js
+
+Air.js is an ES6 benchmark. It tries to faithfully use new features like arrow
+functions, classes, for-of, and Map/Set, among others. Air.js doesn't avoid any
+features out of fear that they might be slow, in the hope that we might learn
+how to make those features fast by looking at how Air.js and other benchmarks
+use them.
+
+This documents the motivation, design, and license of Air.js.
+
+## Motivation
+
+At the time that Air.js was written, most JavaScript benchmarks used ES5 or
+older versions of the language. ES6 testing mostly relied on microbenchmarks or
+conversions of existing tests to ES6. We try to use larger benchmarks to avoid
+over-optimizing for small pieces of code, and we avoid making changes to
+existing benchmarks because that approach has no limiting principle: if it's OK
+to change a benchmark to use a feature, does that mean we can also change it to
+remove the use of a feature we don't like? We feel that the best way to avoid
+falling into the trap of creating benchmarks that reinforce what some JS engine
+is already good at is to create a new benchmark from first principles.
+
+We only recently completed our new JavaScript compiler, called
+[B3](https://webkit.org/blog/5852/introducing-the-b3-jit-compiler/). B3's
+backend, called
+[Air](https://webkit.org/docs/b3/assembly-intermediate-representation.html), is
+very CPU-intensive and uses a combination of object-oriented and functional
+idioms in C++. Additioally, it relies heavily on high speed maps and sets. It
+goes so far as to use customized map/set implementations - even more so than
+the rest of WebKit. This makes Air a great candidate for ES6 benchmarking.
+Air.js is a faithful ES6 implementation of Air. It pulls no punches: just as
+the original C++ Air was written with expressiveness as a top priority, Air.js
+is liberal in its use of modern ES6 idioms whenever this helps make the code
+more readable. Unlike the original C++ Air, Air.js doesn't exploit a deep
+understanding of compilers to make the code easy to compile.
+
+## Design
+
+Air.js runs one of the more expensive Air phases, Air::allocateStack(). This
+turns abstract stack references into concrete stack references, by selecting
+how to lay out stack slots in the stack frame. This requires liveness analysis
+and an interference graph.
+
+Air.js relies on three major ES6 features more so than most of the others:
+
+- Arrow functions. Like the C++ Air, Air.js uses a functional style of
+  iterating most non-trivial data-structures:
+
+        inst.forEachArg((arg, role, type, width) =&gt; ...)
+  
+  This is because the functional style allows the callbacks to mutate the data
+  being iterated: if the callback returns a non-null value, forEachArg() will
+  replace the argument with that value. This would not have been possible with
+  for-of.
+
+- For-of. Many Air data structures are amenable to for-of iteration. While the
+  innermost loops tend to use functional iteration, pretty much all of the
+  outer logic uses for-of heavily. For example:
+
+        for (let block of code) // Iterate over the basic blocks
+            for (let inst of block) // Iterate over the instructions in a block
+                ...
+
+- Map/Set. The liveness analysis and Air::allocateStack() rely on maps and
+  sets. For example, we use a liveAtHead map that is keyed by basic block. Its
+  values are sets of live stack slots. This is a relatively crude way of doing
+  liveness, but it is exactly how the original Air::LivenessAnalysis worked, so
+  we view it as being quite faithful to how a sensible programmer might use Map
+  and Set.
+
+Air.js also uses some other ES6 features. For example, it uses a Proxy
+in one place, though we doubt that it's on a critical path. Air.js uses classes
+and let/const extensively, as well a symbols. Symbols are used as enumeration
+elements, and so they frequently show up as cases in switch statements.
+
+The workflow of an Air.js run is pretty simple: we do 150 runs of allocateStack
+on four IR payloads.
+
+Each IR payload is a large piece of ES6 code that constructs an Air.js Code
+object, complete with blocks, temporaries, stack slots, and instructions. These
+payloads are generated by running Air::dumpAsJS() phase just prior to the
+native allocateStack phase on the largest hot function in four major JS
+benchmarks according to JavaScriptCore's internal profiling:
+
+- Octane/GBEmu, the executeIteration function.
+- Kraken/imaging-gaussian-blur, the gaussianBlur function.
+- Octane/Typescript, the scanIdentifier function,
+- Air.js, an anonymous closure identified by our profiler as ACLj8C.
+
+These payloads allow Air.js to precisely replay allocateStack on those actual
+functions.
+
+The payload is executable code that allocates the IR, and about 15% of
+benchmark execution time is spent in that code. This is significant, but having
+learned this, we don't feel that it would be honest to try to change the
+efficiency of payload initialization. What if the payload initialization was
+more expensive on our engine than others? If it was, then such a change would
+not be fair.
+
+Most of the time in Air.js is spent running the allocateStack phase, which is
+reproduced faithfully in ES6, including its use of an abstract liveness
+analysis. It's abstract in the sense that the same liveness algorithm can be
+reused for temporaries, registers, or stack slots.
+
+Air.js validates its results. We added a Code hashing capability to both the
+C++ Air and Air.js, and we assert each payload looks identical after
+allocateStack to what it would have looked like after the original C++
+allocateStack. We also validate that payloads hash properly before
+allcoateStack, to help catch bugs during payload initialization. We have not
+measured how long hashing takes, but it's a O(N) operation, while allocateStack
+is closer to O(N^2). We suspect that barring some engine pathologies, hashing
+should be much faster than allocateStack, and allocateStack should be where the
+bulk of time is spent.
+
+## License
+
+Copyright (C) 2016 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+## Summary
+
+At the time that Air.js was written, we weren't happy with the ES6 benchmarks
+that were available to us. Air.js uses some ES6 features in anger, in the hope
+that we can learn about possible optimization strategies by looking at this and
+other benchmarks.
</ins></span></pre></div>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (201956 => 201957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2016-06-11 00:21:16 UTC (rev 201956)
+++ trunk/PerformanceTests/ChangeLog        2016-06-11 00:48:43 UTC (rev 201957)
</span><span class="lines">@@ -1,5 +1,17 @@
</span><span class="cx"> 2016-06-10  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Air.js should have some documentation
+        https://bugs.webkit.org/show_bug.cgi?id=158648
+
+        Reviewed by Keith Miller.
+        
+        I want to be able to point people at a document if they want to know more about this
+        benchmark.
+
+        * Air.js/README.md: Added.
+
+2016-06-10  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Rename JSAir to Air.js.
</span><span class="cx"> 
</span><span class="cx">         Rubber stamped by Mark Lam.
</span></span></pre>
</div>
</div>

</body>
</html>