Overhead of Deoptimization Checks in the V8 Javascript Engine

Overhead of Deoptimization Checks in the V8 Javascript Engine

Overhead of Deoptimization Checks in the V8 JavaScript Engine Gabriel Southern and Jose Renau Dept. of Computer Engineering, University of California, Santa Cruz Email: fgsouther,[email protected] Abstract—Just-in-time compilation for dynamic languages uses 20 type speculation to generate optimized code for frequently executed code sections. However, even the high-performance code requires checks to ensure that assumptions made during code 15 generation are not violated. If the assumptions are violated then the program reverts to executing unoptimized code. This process is called deoptimization, and the checks are called deoptimization 10 checks. We analyzed the frequency of conditional deoptimization 5 checks and the performance impact of the associated conditional branch using the V8 Javascript engine running the Octane benchmarks. Over half of the benchmarks have at least 5 checks Checks per 100 instructions 0 per 100 instructions, and 1 benchmark has as many as 19 checks box2dcodeloadcryptodeltablueearleyboyergbemumandreelnavierstokespdfjsraytraceregexprichardssplaytypescriptzlib geomean per 100 instructions. The performance impact of the checks varies significantly depending on the microarchitecture of the CPU that is running the code. On average the conditional branch used by the checks accounts for over 6.2% of the benchmark’s dynamic instructions. Removing these checks provides only a 2.2% performance Fig. 1. Frequency of deoptimization checks for the Octane benchmarks when improvement when running on a high performance Intel CPU, executed with the V8 JavaScript engine. Eight of the 15 benchmarks have more than 5 checks per 100 instructions, and many of the checks are comprised but a 4.6% performance improvement on an Intel CPU optimized of multiple instructions. for low power consumption. I. INTRODUCTION Dynamic languages such as JavaScript, Python, and Ruby version. The process is called deoptimization1, and the checks have become extremely popular in recent years. Applications are called deoptimization (or deopt) checks. written in dynamic languages have historically executed much The cost of each conditional deoptimization check is rel- more slowly than those written in statically typed languages, atively small, typically ranging from 1 to 3 instructions. An in part because variable type information is only known at example of a common check is the comparison of an object’s runtime, and not at compile time. However, in recent years pointer to its type with a pointer to the expected type. The the performance of JavaScript runtime and compilers has comparison is followed by a conditional branch that branches improved dramatically and JavaScript is widely used in client to deoptimization code in case the pointers do not match. and server applications that require high performance. Although the cost of each check is small, the checks can occur JavaScript implementations attain their high performance very frequently for applications that run mostly in optimized by using multi-tiered just-in-time (JIT) compilation combined mode. Figure 1 shows the frequency of deoptimization checks with type speculation [6], [12], [16], [17]. The initial tier for the Chrome V8 JavaScript engine when running the Octane quickly parses JavaScript source code and executes it with benchmark suite [1]. Over half of the benchmarks execute at an interpreter or a fast compiler that does not perform any least 5 checks per 100 instructions, and many of the checks optimizations. As this code runs it stores the types of variables are comprised of more than 1 instruction. used by a function in inline-caches using techniques first devel- In this paper we analyze the type and frequency of deop- oped for Smalltalk [7] and Self [9]. After type information has timization checks used in the Chrome V8 JavaScript engine, been collected, frequently executed code is recompiled with an as well as the performance overhead associated with these optimizing compiler, which assumes that variable types will checks. Although our analysis focuses on Google’s Chrome not change even though this is not guaranteed by the language V8 JavaScript engine, all major JavaScript engines including semantics. In order to guarantee that these assumptions are those from Apple, Mozilla, and Microsoft have deoptimization not violated, the compiler inserts checks to ensure that the checks, and deoptimization checks are present in JITs for assumptions about types still hold. If the condition expected Python, Ruby, and other dynamic languages. We believe by the checks fails to hold then the function stops running the optimized code and switches back to the unoptimized 1Also sometimes called “bailout” that the insights gained from studying deoptimization check then it chooses the correct operation to perform based on this overhead for a specific JIT implementation can be useful in type. other contexts since speculative optimization is a widely used technique in JITs for dynamic languages. Listing 1. JavaScript dynamic dispatch example function twice(arg) { We identified four main types of deoptimization checks return arg + arg; that are used in Chrome V8 and characterized the frequency } of checks when running the Octane Benchmark suite. We res = twice(1); // res is number 2 also analyzed the performance overhead of the conditional res = twice("1"); // res is string ’11’ branches used for the checks by running the benchmarks on In general interpreted languages suffer a large performance four different real systems with checks enabled and disabled. overhead compared to statically typed compiled languages. We found that modern wide issue out-of-order processors Part of the overhead is associated with the dispatch loop, which are usually able to absorb the overhead of executing the must continually check the type of each variable and then extra check instructions with minimal performance overhead. execute the correct functionality based on the variable type. However, narrower issue systems suffer a larger slowdown that The other part of the overhead is caused by the fact that the corresponds with the instruction count overhead. type checks prevent many common compiler optimizations. This paper’s contributions are: Despite the fact that these languages allow variables to • Characterizing the performance overhead of deoptimiza- change their type at runtime, often the runtime behavior tion checks for the Chrome V8 JavaScript engine on four is very predictable. Smalltalk [7] and SELF [9] pioneered different machines, techniques using inline caches and dynamic compilation to • Showing that performance overhead does not always improve performance, and these techniques are used in the correlate with instruction count overhead, but rather de- most popular JavaScript systems today [6], [12], [16], [17]. pends on a combination of the workload and the system To understand how this works, consider the example in micorarchitecture; and Listing 2 and imagine that the array input contains many • Categorizing the types of deoptimization checks and integers. During the first iteration of the for loop the runtime characterize their execution frequency when running op- system looks up the appropriate operation (addition) for the timized code. twice function based on the fact that its input parameter is a The rest of this paper is organized as follows: Section II numeric type. At the same time the runtime system saves this provides background information about JITs for dynamic lan- information in an in-line cache to simplify the method lookup guages, the V8 JavaScript engine, and the Octane benchmark process in case the twice function is called with an integer suite that we used for our experiments; Section III shows argument again. the types of frequency of deoptimization checks that we During future iterations of the for loop the runtime observed; Section IV provides an analysis of performance system will be able to use information cached in the in- overhead associated with deoptimization checks; Section V line cache when determining how to execute the twice surveys related work; and Section VI concludes. function. However, even with this optimization there is a significant performance overhead compared to the code that II. BACKGROUND a statically compiled language like C++ could generate given A. Dynamic Languages the knowledge that the parameter for the function is always an integer. Dynamically typed languages do not require developers to declare types of variables in the program source code; instead, To further improve performance the runtime system can twice types are determined at runtime based on the state of the generate an optimized version of the function that arg running program. These languages are often used to improve assumes that the parameter is always an integer. This programmer productivity [11], [15], even though they can have optimized code does not need to check the inline cache a significant performance overhead. to determine what method to execute; instead, the compiler The simplest way of implementing a runtime system for a can perform integer addition using a single machine code dynamic language is to use an interpreter that directly executes instruction. statements in the program source code. Each time an operation Listing 2. Inline cache example is performed, the interpreter checks the type of the variables function twice(arg) { used in the operation and selects the method that is appropriate return arg + arg; } based on the variable types. var input = [1,2,3,4, . .]; To make this more

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    10 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us