{"id":230058,"date":"2023-08-21T16:05:22","date_gmt":"2023-08-21T23:05:22","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/java\/?p=230058"},"modified":"2023-08-21T16:24:55","modified_gmt":"2023-08-21T23:24:55","slug":"how-tiered-compilation-works-in-openjdk","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/java\/how-tiered-compilation-works-in-openjdk\/","title":{"rendered":"How Tiered Compilation works in OpenJDK"},"content":{"rendered":"<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The OpenJDK HotSpot runtime system is a complex piece of software that employs several techniques to optimize the execution of Java programs on the fly. The system is composed of two different compilers, one interpreter and several different Garbage Collectors, among several other components. These compilers are orchestrated in a tiered compilation mechanism which tries to use the most suitable compiler for each method.\u00a0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">HotSpot has the critical goal of generating efficient machine code while keeping the runtime cost at a minimum. To achieve that it employs various strategies, such as tiered compilation, dynamic profiling, speculation, deoptimization, and various compiler optimizations, both architecturally dependent and independent. In this post, we will delve into the motivation behind tiered compilation and understand how it works.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p aria-level=\"2\"><b><span data-contrast=\"none\">The Right Tool for The Job<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The basic idea behind tiered compilation is that most of the execution time of a program is spent on a small part of the code (i.e., a few methods). Furthermore, the cost to compile a method (i.e., CPU cycles) is the same whether it executes only once or a million times. Based on these observations the VM is designed to use a &#8220;simple compiler&#8221; for methods that do not execute &#8220;many times&#8221;, i.e., <\/span><i><span data-contrast=\"auto\">cold methods<\/span><\/i><span data-contrast=\"auto\">, and use a more &#8220;optimizing&#8221; compiler for methods that run &#8220;a lot&#8221;, i.e., <\/span><i><span data-contrast=\"auto\">hot methods<\/span><\/i><span data-contrast=\"auto\">. The rationale is as follows:<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ol style=\"text-align: justify;\">\n<li data-leveltext=\"%1.\" data-font=\"Aptos\" data-listid=\"5\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559684&quot;:-1,&quot;335559685&quot;:720,&quot;335559991&quot;:480,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">We do not want to spend too many CPU cycles compiling a method that is going to be executed only once. In other words, we do not want to spend more cycles compiling a method than executing it!<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/li>\n<\/ol>\n<ol style=\"text-align: justify;\">\n<li data-leveltext=\"%1.\" data-font=\"Aptos\" data-listid=\"5\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559684&quot;:-1,&quot;335559685&quot;:720,&quot;335559991&quot;:480,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;multilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"2\" data-aria-level=\"1\"><span data-contrast=\"auto\">If a method executes a sufficiently high number of times the cost of compiling it <\/span><b><i><span data-contrast=\"auto\">plus<\/span><\/i><\/b><span data-contrast=\"auto\"> the cost of running it, in an <\/span><i><span data-contrast=\"auto\">optimized <\/span><\/i><span data-contrast=\"auto\">form, will be lower than the cost of running it in an <\/span><i><span data-contrast=\"auto\">unoptimized<\/span><\/i><span data-contrast=\"auto\"> form.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/li>\n<\/ol>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Let us use some <\/span><b><i><span data-contrast=\"auto\">hypothetical<\/span><\/i><\/b> <span data-contrast=\"auto\">values to exemplify the points above. Consider a VM that has three different compilers: <\/span><span data-contrast=\"auto\">Comp1<\/span><span data-contrast=\"auto\">, <\/span><span data-contrast=\"auto\">Comp2<\/span><span data-contrast=\"auto\">, <\/span><span data-contrast=\"auto\">Comp3<\/span><span data-contrast=\"auto\">. Each of these compilers is slower than the previous one to produce code, but the actual generated code is better than the one produced by the previous compiler. <\/span><span data-contrast=\"auto\">Comp1<\/span><span data-contrast=\"auto\"> is a fast and simple compiler that produces &#8220;slow code&#8221;. <\/span><span data-contrast=\"auto\">Comp2<\/span><span data-contrast=\"auto\"> is slower than <\/span><span data-contrast=\"auto\">Comp1, <\/span><span data-contrast=\"auto\">but it produces slightly &#8220;faster code&#8221;. <\/span><span data-contrast=\"auto\">Comp3<\/span><span data-contrast=\"auto\"> is a compiler that produces very efficient code, but it is much slower than <\/span><span data-contrast=\"auto\">Comp1<\/span><span data-contrast=\"auto\"> and <\/span><span data-contrast=\"auto\">Comp2<\/span><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Based on these descriptions, suppose we have the values shown in the table below for the compilation of a random method. The <\/span><i><span data-contrast=\"auto\">Compilation<\/span><\/i><span data-contrast=\"auto\"> column shows the cost, as the number of CPU cycles to compile the method. The <\/span><i><span data-contrast=\"auto\">Cycle Count<\/span><\/i><span data-contrast=\"auto\"> column shows the number of cycles the code produced for the method takes to execute.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<table align=\"center\" data-tablestyle=\"MsoTable15List3\" data-tablelook=\"32\" aria-rowcount=\"4\">\n<tbody>\n<tr aria-rowindex=\"1\">\n<td style=\"width: 71.1354px;\" data-celllook=\"4112\"><b><span data-contrast=\"none\">Compiler<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 91.6042px;\" data-celllook=\"0\"><b><span data-contrast=\"none\">Compilation<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 94.2708px;\" data-celllook=\"4112\"><b><span data-contrast=\"none\">Cycle Count<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"2\">\n<td style=\"width: 71.1354px;\" data-celllook=\"4369\"><span data-contrast=\"auto\">Comp1<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 91.6042px;\" data-celllook=\"257\"><span data-contrast=\"auto\">1<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 94.2708px;\" data-celllook=\"4369\"><span data-contrast=\"auto\">50<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"3\">\n<td style=\"width: 71.1354px;\" data-celllook=\"4112\"><span data-contrast=\"auto\">Comp2<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 91.6042px;\" data-celllook=\"0\"><span data-contrast=\"auto\">10<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 94.2708px;\" data-celllook=\"4112\"><span data-contrast=\"auto\">30<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"4\">\n<td style=\"width: 71.1354px;\" data-celllook=\"4369\"><span data-contrast=\"auto\">Comp3<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 91.6042px;\" data-celllook=\"257\"><span data-contrast=\"auto\">100<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td style=\"width: 94.2708px;\" data-celllook=\"4369\"><span data-contrast=\"auto\">10<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">These values mean that <\/span><span data-contrast=\"auto\">Comp1<\/span><span data-contrast=\"auto\"> can compile the method 100x faster than <\/span><span data-contrast=\"auto\">Comp3<\/span><span data-contrast=\"auto\">, however the produced code will execute 5x slower. The table below shows the <\/span><i><span data-contrast=\"auto\">total number of CPU cycles necessary to compile and execute the method<\/span><\/i><span data-contrast=\"auto\"> in four different scenarios: A) The method executes only once; B) The method executes one hundred times; C) The method executes 1000 times and, D) The method executes 1,000,000 times.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<table align=\"center\" data-tablestyle=\"MsoTable15List3\" data-tablelook=\"32\" aria-rowcount=\"4\">\n<tbody>\n<tr aria-rowindex=\"1\">\n<td data-celllook=\"4112\"><b><span data-contrast=\"none\">Compiler<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><b><span data-contrast=\"none\">A<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4112\"><b><span data-contrast=\"none\">B<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><b><span data-contrast=\"none\">C<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4112\"><b><span data-contrast=\"none\">D<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"2\">\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">Comp1<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">51<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">5,001<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">50,001<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">50,000,001<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36,&quot;335559740&quot;:259}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"3\">\n<td data-celllook=\"4112\"><span data-contrast=\"auto\">Comp2<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">40<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4112\"><span data-contrast=\"auto\">3,010<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">30,010<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4112\"><span data-contrast=\"auto\">30,000,010<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"4\">\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">Comp3<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">110<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">1,100<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">10,100<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">10,000,100<\/span><span data-ccp-props=\"{&quot;335551550&quot;:3,&quot;335551620&quot;:3,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">If we use <\/span><span data-contrast=\"auto\">Comp1<\/span><span data-contrast=\"auto\"> in Scenario A, the total number of cycles to compile and execute the method would be 51 (1 to compile + 50 to execute once). If we use <\/span><span data-contrast=\"auto\">Comp2<\/span><span data-contrast=\"auto\"> for this same scenario the total number of cycles would have been 40 (10 cycles to compile the method + 30 to execute it once). If, on the other hand, we use <\/span><span data-contrast=\"auto\">Comp3<\/span><span data-contrast=\"auto\"> the total number of cycles would be 110 (100 to compile + 10 to execute once). Therefore, the best compiler, if the method is executed only once, is <\/span><span data-contrast=\"auto\">Comp2<\/span><span data-contrast=\"auto\">.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">In scenario D, if we use <\/span><span data-contrast=\"auto\">Comp1<\/span><span data-contrast=\"auto\"> the total number of cycles would be 50,000,001 (1 to compile the method and 50,000,000 to execute). If we use <\/span><span data-contrast=\"auto\">Comp3<\/span><span data-contrast=\"auto\"> in this scenario, the total number of cycles would be 10,000,100 (100 cycles to compile the method and 10,000,000 to execute it 1,000,000 times).<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">As you can see, the numbers are quite different depending on the compiler that is used and\/or the number of times the method executes. In other words, the best compiler for compiling the method depends on how many times the method is going to execute. In the next section, we will look at how to &#8220;predict&#8221; (or guess) how many times a method will execute.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/p>\n<p aria-level=\"2\"><b><span data-contrast=\"none\">Hot Code Prediction<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">In the previous section I intentionally used terms like &#8220;a lot&#8221;, &#8220;simple&#8221;, etc. In this section I explain exactly what I mean by each of them.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">By a \u201csimple\u201d compiler, I mean one that can produce code quickly (i.e., the compilation cost is not large) but there is no stringent requirement for the machine code produced to be the most efficient possible. On the other hand, a sophisticated compiler (sometimes called an <\/span><i><span data-contrast=\"auto\">optimizing compiler<\/span><\/i><span data-contrast=\"auto\">) is one that employs many optimizations, aiming to produce the most efficient machine code possible. As you can imagine, the compilation cost is different for the two compilers. Also, note that we do not have to settle with just the two extremes, we can employ a range of different compilers with different capabilities, or we can just use the same compiler but run a different list of optimizations for different pieces of code (like GCC or Clang with the distinct levels of optimization).<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">We saw in the previous section that the number of times a method executes is a crucial factor in deciding which compiler to use. Baked in our example was the assumption that we know how many times a method is going to execute <\/span><i><span data-contrast=\"auto\">before<\/span><\/i><span data-contrast=\"auto\"> we even compile it, because we are going to use that information to decide how to compile it.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Now, how do we tell, before we even compile a method, whether it is going to execute &#8220;many times&#8221; or not? What is &#8220;many times&#8221;? The answer is: we cannot \u2013 sort of! The problem that we are trying to solve is a version of an important [undecidable] problem in Computer Science &#8211; <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Halting_problem\"><span data-contrast=\"none\">The Halting Problem<\/span><\/a><span data-contrast=\"auto\">. What we do in practice is find a workaround for the problem: we assume the method is cold and compile it using the simple compiler and then execute the method a few times, let us say <\/span><span data-contrast=\"auto\">N<\/span><span data-contrast=\"auto\">. <\/span><i><span data-contrast=\"auto\">If the method is executed <\/span><\/i><span data-contrast=\"auto\">N<\/span><i><span data-contrast=\"auto\"> times, we assume that it will execute at least <\/span><\/i><i><span data-contrast=\"auto\">N<\/span><\/i><i><span data-contrast=\"auto\"> more times in the future<\/span><\/i><span data-contrast=\"auto\"> &#8211; and therefore is a hot method. If the method does not even reach <\/span><span data-contrast=\"auto\">N<\/span><span data-contrast=\"auto\"> executions, then it is a cold method, and we already used the right compiler for it &#8211; the simple one. In other words, we use threshold <\/span><span data-contrast=\"auto\">N<\/span><span data-contrast=\"auto\"> to find when a method <\/span><i><span data-contrast=\"auto\">has become<\/span><\/i><span data-contrast=\"auto\"> hot, and we use that as an indicator that the method will continue to be hot in the future.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The question then is how to choose the value of the threshold <\/span><span data-contrast=\"auto\">N<\/span><span data-contrast=\"auto\">. If we make <\/span><i><span data-contrast=\"none\">N = 1<\/span><\/i><span data-contrast=\"auto\"> there is a good chance our assumption (the method will execute <\/span><span data-contrast=\"auto\">N<\/span><span data-contrast=\"auto\"> more times) will hold most of the time, however that does not help much to find methods that are hot. If we make <\/span><i><span data-contrast=\"none\">N = 1,000,000 <\/span><\/i><span data-contrast=\"auto\">we increase our chance of finding real hot methods, <\/span><i><span data-contrast=\"auto\">but<\/span><\/i><span data-contrast=\"auto\"> we also increase the probability that our assumption &#8211; that the method will execute N more times \u2013 will be false. Moreover, we executed a method compiled with the simple compiler <\/span><span data-contrast=\"auto\">1,000,000 <\/span><span data-contrast=\"auto\">times.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">In practice what we do is we choose <\/span><span data-contrast=\"auto\">N<\/span><span data-contrast=\"auto\"> based on empirical evidence. We consider, among other things, the compilation costs, the performance of the code produced by our compilers, the kind of workload that we have, how many compilers do we have, etc., and try to produce an educated guess for the threshold. There is hardly an ideal threshold that will work for every situation. For instance, there are programs where the execution is more spread throughout the source code (e.g., GUI programs) and other programs where the execution is much more limited to a small part of the source code (e.g., scientific programs or <\/span><i><span data-contrast=\"auto\">benchmarks<\/span><\/i><span data-contrast=\"auto\">). The behavior of a program might even go through phases where different portions of the code become hot at different moments.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">In the next section we are going to take a quick look at how HotSpot deals with this problem.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p aria-level=\"2\"><b><span data-contrast=\"none\">Tiered Compilation in HotSpot<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;335559738&quot;:200,&quot;335559739&quot;:0}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">As we will see, the Tiered Compilation process in HotSpot is a very elaborate process, but the idea is still the same one that we discussed in the previous section: use the best tool for the job.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">HotSpot has 2 compilers, C1 (<\/span><a href=\"https:\/\/github.com\/openjdk\/jdk\/blob\/c8add223a10030e40ccef42e081fd0d8f00e0593\/src\/hotspot\/share\/c1\/c1_Compilation.cpp#L429\"><span data-contrast=\"none\">source<\/span> <span data-contrast=\"none\">here<\/span><\/a><span data-contrast=\"auto\">) and C2 (<\/span><a href=\"https:\/\/github.com\/openjdk\/jdk\/blob\/c8add223a10030e40ccef42e081fd0d8f00e0593\/src\/hotspot\/share\/opto\/c2compiler.cpp#L97\"><span data-contrast=\"none\">source here<\/span><\/a><span data-contrast=\"auto\">), and an interpreter. There may be multiple threads executing each compiler and the number of such threads is adjusted dynamically based on the load of the system. That means that several methods may be compiled <\/span><i><span data-contrast=\"auto\">concurrently<\/span><\/i><span data-contrast=\"auto\">. Furthermore, the execution of a method may continue uninterrupted in its current form while another version of the method is being compiled. The compiler threads act upon two priority queues, one for each compiler, containing Compilation Tasks (<\/span><a href=\"https:\/\/github.com\/JohnTortugo\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/compiler\/compileTask.hpp#L43\"><span data-contrast=\"none\">source here<\/span><\/a><span data-contrast=\"auto\">) that describe, among other things, which method should be compiled.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The two compilers in different configurations are combined with the interpreter to produce a total of five distinct optimization levels:<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<table align=\"center\" data-tablestyle=\"MsoTable15List3\" data-tablelook=\"32\" aria-rowcount=\"6\">\n<tbody>\n<tr aria-rowindex=\"1\">\n<td data-celllook=\"4112\"><b><span data-contrast=\"none\">Level<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><b><span data-contrast=\"none\">Compiler<\/span><\/b><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"2\">\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">Interpreter<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"3\">\n<td data-celllook=\"4112\"><span data-contrast=\"auto\">1<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">C1 without profiling<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"4\">\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">2<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">C1 with basic profiling<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"5\">\n<td data-celllook=\"4112\"><span data-contrast=\"auto\">3<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">C1 with full profiling<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"6\">\n<td data-celllook=\"4369\"><span data-contrast=\"auto\">4<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<td data-celllook=\"257\"><span data-contrast=\"auto\">C2 full optimizing, no profiling<\/span><span data-ccp-props=\"{&quot;335559738&quot;:36,&quot;335559739&quot;:36}\">\u00a0<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Normally the execution of a method starts in the <\/span><i><span data-contrast=\"auto\">interpreter,<\/span><\/i><span data-contrast=\"auto\"> which is the simplest\/cheapest mechanism that HotSpot has available to execute code. During the execution of the method via interpretation, or in compiled form, the dynamic profile of the method is collected using <\/span><i><span data-contrast=\"auto\">instrumentation<\/span><\/i><span data-contrast=\"auto\">. The method\u2019s profile is then used by several heuristics that will decide, among other things, if the method should be compiled, recompiled at a different level, which optimizations should be performed, etc.\u00a0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The two most fundamental pieces of information collected by HotSpot during the execution of a method are how many times the method has been executed and how many times the loops in a method have iterated. That information is used by a Compilation Policy (<\/span><a href=\"https:\/\/github.com\/JohnTortugo\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/compiler\/compilationPolicy.hpp#L36\"><span data-contrast=\"none\">source here<\/span><\/a><span data-contrast=\"auto\">) to decide whether to compile a method or not, and at which level. HotSpot also has a feature called On-Stack-Replacement (OSR) that makes it possible to compile hot loops independently of their containing method. This is an interesting feature to work around cases where a hot loop is inside a method that has not itself become hot.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The following formula (see source <\/span><a href=\"https:\/\/github.com\/JohnTortugo\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/compiler\/compilationPolicy.cpp#L268\"><span data-contrast=\"none\">here<\/span><\/a><span data-contrast=\"auto\"> and <\/span><a href=\"https:\/\/github.com\/JohnTortugo\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/compiler\/compilationPolicy.hpp#L105\"><span data-contrast=\"none\">here<\/span><\/a><span data-contrast=\"auto\">) is used by the Compilation Policy to decide whether to create a compilation request at level 3, for a method that is currently being interpreted. The same formula is used to decide if a request should be created to compile a method at level 4 if the method is currently executing as a level 3 compilation. A similar formula is used to control OSR compilations.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<blockquote><p><span data-contrast=\"auto\">(Executions &gt; TierXInvocationThreshold * Scale)<\/span><\/p><\/blockquote>\n<p><b><span data-contrast=\"auto\">OR\u00a0<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<blockquote><p><span data-contrast=\"auto\">(Executions\u00a0&gt; TierXMinInvocationThreshold * Scale\u00a0<\/span><b><span data-contrast=\"auto\">AND <\/span><\/b><span data-contrast=\"auto\">Executions + Iterations &gt; TierXCompileThreshold * Scale)<\/span><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p><\/blockquote>\n<p><span data-contrast=\"auto\">Where:<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul>\n<li data-leveltext=\"\uf0a7\" data-font=\"Wingdings\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Wingdings&quot;,&quot;469769242&quot;:[9642],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0a7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">TierXInvocationThreshold <\/span><\/b><span data-contrast=\"auto\">\u2013 compile the method at level X if the number of invocations crosses this threshold. Defaults to 200 for level 3 and 5000 for level 4.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0a7\" data-font=\"Wingdings\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Wingdings&quot;,&quot;469769242&quot;:[9642],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0a7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"2\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">TierXMinInvocationThreshold <\/span><\/b><span data-contrast=\"auto\">&#8211; minimum number of executions needed to compile the method at level X. Defaults to 100 for level 3 and 600 for level 4.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0a7\" data-font=\"Wingdings\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Wingdings&quot;,&quot;469769242&quot;:[9642],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0a7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"3\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">TierXCompileThreshold <\/span><\/b><span data-contrast=\"auto\">&#8211; compile the method at level X if the method plus the number of its loops\u2019 iterations have executed more than this threshold. Defaults to 2,000 for level 3 and 15,000 for level 4.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0a7\" data-font=\"Wingdings\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Wingdings&quot;,&quot;469769242&quot;:[9642],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0a7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"4\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Executions &#8211; <\/span><\/b><span data-contrast=\"auto\">is the number of times the method has been executed.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0a7\" data-font=\"Wingdings\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Wingdings&quot;,&quot;469769242&quot;:[9642],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0a7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"4\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Iterations &#8211; <\/span><\/b><span data-contrast=\"auto\">is the accumulated number of iterations that loops inside the method have been executed.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0a7\" data-font=\"Wingdings\" data-listid=\"3\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Wingdings&quot;,&quot;469769242&quot;:[9642],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0a7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"4\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">Scale &#8211; <\/span><\/b><span data-contrast=\"auto\">is a scaling factor applied to keep the load in the compilation queues stable. It is periodically dynamically adjusted based on the number of entries in the compilation queues and the number of compiler threads.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">HotSpot also takes into consideration the effect of the compilation in other parts of the system and how much load the system is currently handling.\u00a0 Assuming a method is being interpreted, and the above formula is satisfied to compile the method at level 3, the Compilation Policy may actually decide to compile it at level 2 (C1 with basic profiling) instead of level 3 (C1 with full profiling). The decision is based on the following factors:<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ol>\n<li style=\"text-align: justify;\" data-leveltext=\"%1.\" data-font=\"Aptos\" data-listid=\"4\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559684&quot;:-1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b><span data-contrast=\"auto\">The length of the C2 queue. <\/span><\/b><span data-contrast=\"auto\">The observation is that a method compiled at level 3 is generally slower than the same method compiled at level 2, therefore we would want to minimize the time a method spends at level 3. We should only spend the time at level 3 that is necessary to gather adequate profiling. So, if the C2 queue is long enough it is more beneficial to go first to level 2, because if we transitioned to level 3, we would be executing 30% slower until the C2 compile request makes its way through the long queue. Instead, the decision is made to compile the method at level 2 and when the load on C2\u2019s queue recedes we are going to <\/span><i><span data-contrast=\"auto\">recompile<\/span><\/i><span data-contrast=\"auto\"> the method at level 3 and start gathering profiling information.\u00a0<\/span><\/li>\n<li style=\"text-align: justify;\" data-leveltext=\"%1.\" data-font=\"Aptos\" data-listid=\"4\" data-list-defn-props=\"{&quot;335552541&quot;:0,&quot;335559684&quot;:-1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769242&quot;:[65533,0],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;%1.&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"1\" data-aria-level=\"1\"><b style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\"><span data-contrast=\"auto\">The length of C1 queue<\/span><\/b><span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\" data-contrast=\"auto\"> is used to dynamically adjust the thresholds, to introduce additional filtering if the compiler is overloaded. The rationale is that if the compiler queue is too long the method may not be executed anymore by the time its compilation finishes.<\/span><span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\" data-ccp-props=\"{&quot;201341983&quot;:1,&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200,&quot;335559740&quot;:300}\">\u00a0<\/span><\/li>\n<\/ol>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Once a method compiled at level 3 has been executed enough times to satisfy the formula for transition to level 4, a request is created to recompile the method at that level. At this level, HotSpot compiles the code using the C2 compiler for maximum long-term performance. Given that level 4 code is considered fully optimized, the JVM stops collecting profiling information.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">When a method is first compiled by C1 some basic information is collected about its structure, like the number of instructions and loops. Based on that information it can be decided that a method is trivial \u2013 it returns a constant or is a getter or setter (<\/span><a href=\"https:\/\/github.com\/openjdk\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/oops\/method.cpp#L883\"><span data-contrast=\"none\">see source here<\/span><\/a><span data-contrast=\"auto\">) &#8211; and compiling it with C1 will yield the same code. In this case the method is always compiled at level 1.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The description above is a simplified version of the compilation policy. There are several other points that HotSpot considers when deciding to compile or recompile a method, and several flags that the user of the JVM can use to customize the policy. For our discussion here <\/span><i><span data-contrast=\"auto\">Deoptimizations <\/span><\/i><span data-contrast=\"auto\">are probably the most relevant topic.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559739&quot;:200}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">C2 uses the information about the dynamic profile of a method to guide several optimizations. Here are a few examples, to name just a few: Inlining, Class Hierarchy Analysis (CHA), basic block ordering, some loop optimizations, etc.\u00a0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul style=\"text-align: justify;\">\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"1\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">The profile shows that an \u201cif-else\u201d statement has only executed the \u201cthen\u201d part in the past. C2 may assume that that will continue to happen in the future and decide to not compile the \u201celse\u201d block at all.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"1\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"2\" data-aria-level=\"1\"><span data-contrast=\"auto\">The profile shows that a reference variable was never null. C2 may then assume that the variable will likely continue to not be null in future executions and optimize the code using that assumption.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"1\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"3\" data-aria-level=\"1\"><span data-contrast=\"auto\">The profile shows that a loop usually iterates thousands of times. C2 may decide to unroll and\/or vectorize the loop based on that information.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"1\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"4\" data-aria-level=\"1\"><span data-contrast=\"auto\">The profile shows that a class has no subclasses. C2 may decide to inline or do other kinds of optimization in method calls using objects of that class.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">There is a catch, though: the dynamic profile of a method is, well, dynamic. There is no guarantee that a method&#8217;s profile will be stable during the application&#8217;s execution. To give a few examples:<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<ul style=\"text-align: justify;\">\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"21\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:1080,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"1\" data-aria-level=\"1\"><span data-contrast=\"auto\">A condition used in an \u201cif-else\u201d statement that during most of the execution of the program was true, suddenly starts returning false.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"21\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:1080,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"2\" data-aria-level=\"1\"><span data-contrast=\"auto\">An exception that was never triggered starts triggering.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"21\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:1080,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"3\" data-aria-level=\"1\"><span data-contrast=\"auto\">A reference variable that was never null starts showing up as null.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"21\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:1080,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"4\" data-aria-level=\"1\"><span data-contrast=\"auto\">A new class is loaded in the system and a previously simple class hierarchy now is more complex.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<li data-leveltext=\"\uf0b7\" data-font=\"Symbol\" data-listid=\"21\" data-list-defn-props=\"{&quot;335552541&quot;:1,&quot;335559684&quot;:-2,&quot;335559685&quot;:1080,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;\uf0b7&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}\" aria-setsize=\"-1\" data-aria-posinset=\"5\" data-aria-level=\"1\"><span data-contrast=\"auto\">A loop that usually iterates thousands of times now starts iterating just a few times.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">To account for this dynamic behavior C2 will insert \u201cpredicates\u201d into the compiled code to check if the assumptions that it made based on the profile information are still valid in future executions. If the predicate is false, a Trap (a call to JVM internals) will be executed to notify HotSpot which assumption was false. With the information provided by the Trap, HotSpot will decide what needs to be done. The current compilation of the method may need to be discarded and the method reprofiled and recompiled, or it may just be necessary to switch the execution to the interpreter. Look <\/span><a href=\"https:\/\/github.com\/openjdk\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/runtime\/deoptimization.hpp%22%20\/l%20%22L76\"><span data-contrast=\"none\">here<\/span><\/a><span data-contrast=\"auto\"> for a list of the possible reasons that a Trap may execute and <\/span><a href=\"https:\/\/github.com\/openjdk\/jdk\/blob\/8eed7dea7b92dd98b74277e8521100f7f807eabb\/src\/hotspot\/share\/runtime\/deoptimization.hpp#L144\"><span data-contrast=\"none\">here<\/span><\/a><span data-contrast=\"auto\"> for a list of the necessary actions to be taken.<\/span><span data-ccp-props=\"{&quot;201341983&quot;:0,&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Let us see in the next section how to examine the list of compilations produced by HotSpot.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p aria-level=\"2\"><b><span data-contrast=\"none\">Controlling Compilation<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;201341983&quot;:0,&quot;335559738&quot;:200,&quot;335559739&quot;:0,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">In this section we are going to see a few basic flags used to control compilations in HotSpot. I should mention, first, that these flags are not meant to \u201ctune\u201d the application performance. They are more intended for investigating the root cause of bugs.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The \u201c-Xcomp\u201d and \u201c-Xint\u201d options instruct the JVM that methods must only be compiled (-Xcomp) or that they should only be interpreted (-Xint). In other words, if you pass the \u201c-Xint\u201d to the JVM then all JIT compilers will be disabled and the only mechanism that HotSpot will use to execute the program is interpretation. On the other hand, if you pass \u201c-Xcomp\u201d, HotSpot will not use the Interpreter and methods will be always compiled.\u00a0<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The \u201c-Xcomp\u201d option, however, does not force HotSpot to compile a method at a certain optimization level. Other options can be used to do that, among them are -XX:TieredStopAtLevel and -XX:-TieredCompilation. The first one is used to set the maximum compilation level. The most common use case for this is probably to force HotSpot to only use the C1 compiler in order to bypass some C2 bug or to stress test C1. The second option will cause HotSpot to not use the Tiered Compilation heuristics to guide the transitions between the compilations and instead it will use another heuristic to choose between C1 and C2 for all compilations.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">To illustrate the impact of Tiered Compilation on program execution time let us do some quick experiments using the options that we just saw. This is not going to be a comprehensive experiment; it is intended to just give an idea of the impact that these different compilation strategies can have on the JVM and application performance.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The table below shows the average wall time to execute \u201cjava-17.07 [FLAGS] HelloWorld\u201d on an AMD Ryzen 7 1800X machine running Ubuntu 20.04. The HelloWorld program just prints the \u201cHello World\u201d message on the console.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<table align=\"center\" data-tablestyle=\"MsoTable15Grid4\" data-tablelook=\"1184\" aria-rowcount=\"4\">\n<tbody>\n<tr aria-rowindex=\"1\">\n<td data-celllook=\"4369\"><b><span data-contrast=\"none\">FLAGS<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<td data-celllook=\"4369\"><b><span data-contrast=\"none\">Average Wall Time<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"2\">\n<td data-celllook=\"0\"><b><span data-contrast=\"auto\">\u201cDefault\u201d<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">0.020s<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"3\">\n<td data-celllook=\"0\"><b><span data-contrast=\"auto\">-Xint<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">0.020s<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<\/tr>\n<tr aria-rowindex=\"4\">\n<td data-celllook=\"0\"><b><span data-contrast=\"auto\">-Xcomp<\/span><\/b><span data-ccp-props=\"{&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<td data-celllook=\"0\"><span data-contrast=\"auto\">0.890s<\/span><span data-ccp-props=\"{&quot;335551550&quot;:2,&quot;335551620&quot;:2,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"text-align: justify; font-size: 1rem;\" data-contrast=\"auto\">These results show that, for this example, disabling the interpreter (i.e., -Xcomp) causes a huge increase in the execution time when compared to the default JVM options. The reason, as explained above, is that many methods will not be executed enough to amortize the cost of their compilation. On the other hand, <\/span><b style=\"text-align: justify; font-size: 1rem;\"><i><span data-contrast=\"auto\">for this example<\/span><\/i><\/b><span style=\"text-align: justify; font-size: 1rem;\" data-contrast=\"auto\">, if you configure the JVM to use only the interpreter the performance will be like when you do not do any customization at all; that is because this example does not have long running methods, and therefore interpreting is the best choice anyway.<\/span><span style=\"text-align: justify; font-size: 1rem;\" data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p aria-level=\"2\"><b><span data-contrast=\"none\">Conclusion<\/span><\/b><span data-ccp-props=\"{&quot;134245418&quot;:true,&quot;134245529&quot;:true,&quot;201341983&quot;:0,&quot;335559738&quot;:200,&quot;335559739&quot;:0,&quot;335559740&quot;:259}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Tiered compilation is a technique used by many virtual machines to make execution of programs more efficient. The core idea is finding the sweet spot between the cost of compiling a method and performance of the compiled code. To achieve that, the VM uses optimizing compilers only on methods that execute often and use non-optimizing compilers (or an interpreter) on methods that do not execute much. In other words, the VM uses a combination of compiled and interpreted code to execute the client program.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">The OpenJDK JVM employs two JIT compilers and an interpreter to implement a sophisticated form of tiered compilation. The JVM initially uses the interpreter to execute methods, and when the execution count of a method satisfies a heuristic, the method is enqueued for compilation using the C1 compiler. If the execution count of the method is large enough it will meet another condition and the method will be compiled using the C2 optimizing compiler. Profiling information collected from the interpreted and C1 compiled version of the method is used by C2 to drive many optimizations.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p style=\"text-align: justify;\"><span data-contrast=\"auto\">Most methods in a program are executed only a few times, sometimes just once. Other methods are executed millions of times. There is an informal saying that programs spend 90% of their execution time executing only 10% of the methods. Spending CPU time compiling a method not critical for the program&#8217;s execution will result in unnecessary overhead. Tiered Compilation is a practical approach that combines engineering and heuristics to enable a VM to infer if a method will execute often or not and use that information to decide if the method should be interpreted or compiled. As a case in point, executing a \u201cHello World\u201d Java program using only compilation results in an execution time 40x greater than executing it using only interpretation.<\/span><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n<p><span data-ccp-props=\"{&quot;335551550&quot;:6,&quot;335551620&quot;:6,&quot;335559738&quot;:180,&quot;335559739&quot;:180}\">\u00a0<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The OpenJDK HotSpot runtime system is a complex piece of software that employs several techniques to optimize the execution of Java programs on the fly. The system is composed of two different compilers, one interpreter and several different Garbage Collectors, among several other components. These compilers are orchestrated in a tiered compilation mechanism which tries [&hellip;]<\/p>\n","protected":false},"author":125793,"featured_media":227205,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,249],"tags":[248,802,319],"class_list":["post-230058","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","category-openjdk","tag-java","tag-jit","tag-openjdk"],"acf":[],"blog_post_summary":"<p>The OpenJDK HotSpot runtime system is a complex piece of software that employs several techniques to optimize the execution of Java programs on the fly. The system is composed of two different compilers, one interpreter and several different Garbage Collectors, among several other components. These compilers are orchestrated in a tiered compilation mechanism which tries [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/230058","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/users\/125793"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/comments?post=230058"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/230058\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media\/227205"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media?parent=230058"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/categories?post=230058"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/tags?post=230058"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}