<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://robcasloz.github.io/blog/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://robcasloz.github.io/blog/blog/" rel="alternate" type="text/html" /><updated>2024-04-07T05:41:34+00:00</updated><id>https://robcasloz.github.io/blog/blog/feed.xml</id><title type="html">Roberto’s programming language implementation blog</title><subtitle>This blog focuses on programming language implementation (compilers, program analysis, etc.)... read at your own risk ;)</subtitle><author><name>Roberto Castañeda Lozano</name><email>rcas@acm.org</email></author><entry><title type="html">When should a compiler expand garbage collection barriers?</title><link href="https://robcasloz.github.io/blog/blog/2024/02/14/when-should-a-compiler-expand-garbage-collection-barriers.html" rel="alternate" type="text/html" title="When should a compiler expand garbage collection barriers?" /><published>2024-02-14T00:00:00+00:00</published><updated>2024-02-14T00:00:00+00:00</updated><id>https://robcasloz.github.io/blog/blog/2024/02/14/when-should-a-compiler-expand-garbage-collection-barriers</id><content type="html" xml:base="https://robcasloz.github.io/blog/blog/2024/02/14/when-should-a-compiler-expand-garbage-collection-barriers.html"><![CDATA[<p>Most compiler engineers I know (including myself) believe it is a good thing to
expose as much information about the program under compilation as possible to
the compiler. The hope is that, in return, the compiler will perform more
precise analysis and more powerful optimizations. Great deal, isn’t it? Well, as
in any sufficiently complex software product, there are trade-offs to consider.
For example, additional program information might increase compilation times or
make the compiler less maintainable. This post describes a case in a production
compiler
(<a href="http://www.usenix.org/events/jvm01/full_papers/paleczny/paleczny.pdf">C2</a>, the
<a href="https://openjdk.java.net/">JDK</a>’s optimizing JIT compiler) where we have
figured out that the right trade-off is to actually <em>reduce</em> the amount of
program information fed to the compiler.</p>

<h4 id="expanding-barriers-early">Expanding barriers early</h4>

<p>Our case concerns the internal representation of <a href="https://www.iecc.com/gclist/GC-algorithms.html">garbage collection (GC)
barriers</a> in C2. These are
additional instructions inserted around the memory accesses of an application to
inform the garbage collector about details of the access, such as what value is
held in the accessed memory position before and after a memory write. There are
multiple ways in which a compiler can handle GC barriers. One way (“the right
way” if you ask a compiler engineer) is to treat barrier operations explicitly
and uniformly, as if they were any other program operation, in the compiler’s
<a href="http://cr.openjdk.java.net/~jrose/draft/code-media.html">intermediate
representation</a> (IR).
The argument for doing this is that it allows the compiler to apply its regular
analysis and transformation mechanisms to turn the GC barriers into
highly-optimized assembly code. We call this approach “early barrier expansion”
because it translates barriers into IR operations at the beginning of the
compilation chain.</p>

<h4 id="the-cost-of-early-barrier-expansion-for-g1">The cost of early barrier expansion for G1</h4>

<p>Early barrier expansion is the current choice in C2 to deal with the barriers
required by the JVM’s default collector (called
<em><a href="https://dl.acm.org/doi/10.1145/1029873.1029879">G1</a></em>). Some collectors require
barriers for both memory reads and writes. G1 requires barriers for writes
only… but not just any barriers! A G1 write barrier is represented by more
than 100 IR operations, and results in around 50 x64 instructions. Since memory
writes are fairly common operations, this just bloats up the IR. Remember <a href="https://robcasloz.github.io/blog/assets/pdg-cfg-method.png">C2’s
IR of a factorial
method</a>? Well, here
is an apparently simpler method that just stores an object <code class="language-plaintext highlighter-rouge">bar</code> into the field
<code class="language-plaintext highlighter-rouge">f</code> of another object <code class="language-plaintext highlighter-rouge">foo</code>, requiring a G1 write barrier:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void write(Foo foo, Bar bar) {
 foo.f = bar;
}
</code></pre></div></div>

<p>and here is the corresponding IR, in <a href="https://robcasloz.github.io/blog/2022/05/24/a-friendlier-visualization-of-javas-jit-compiler-based-on-control-flow.html">control-flow graph
form</a>:</p>

<p><img src="https://robcasloz.github.io/blog/assets/write-barrier.png" alt="CFG of a G1 write barrier" width="55%" class="center-image" /></p>

<p class="image-caption"><em>Control-flow graph of a G1 write barrier in C2</em></p>

<p>A larger IR imposes inevitably a higher compilation overhead: in preliminary
experiments running the <a href="https://www.dacapobench.org/">DaCapo 9.12-bach benchmark
suite</a> on different platforms (Linux/x64,
macOS/aarch64), G1 barrier IR operations account for around 20% of C2’s total
execution time.</p>

<h4 id="the-opposite-approach-late-barrier-expansion">The opposite approach: late barrier expansion</h4>

<p>What can be done? A radically different way of dealing with GC barriers in a
compiler is to simply hide them from the compiler through the entire compilation
time, and just “paste” the corresponding instructions around their memory access
instructions at code emission time. This apparently naive approach (which we
call “late barrier expansion”) has an undeniable advantage: simplicity. Because
it is so simple, it can be implemented very cheaply, which gives <a href="https://robcasloz.github.io/blog/assets/c2-speed-results.html">a noticeable
C2 speedup in our preliminary
experiments</a>. And, perhaps more
importantly, it frees GC maintainers from a task they never signed up for:
dealing with the intricacies and quirks of a <a href="https://en.wikipedia.org/wiki/HotSpot_(virtual_machine)#History">25-year
old</a> compiler
in order to tune and optimize their precious barriers.</p>

<h4 id="wait-what-about-performance">Wait, what about performance?</h4>

<p>At this point, the compiler engineer in the room has no option but to point out
that late barrier expansion surely produces code of worse quality, since it is
not analyzed and optimized together with the rest of the application, just
“pasted” into the final assembly code. While this is true on paper, we have not
observed any significant performance degradation by moving from early to late G1
barrier expansion in C2. It seems there isn’t just that much room for
optimization within G1’s barriers, and the potential negative effects of
remaining inefficiencies, if any, are covered up by the mercifulness of modern
processors.</p>

<h4 id="but-what-if-our-compiler-targets-fifteen-different-platforms">But, what if our compiler targets fifteen different platforms?</h4>

<p>Our compiler engineer might patiently argue that the late barrier expansion
model is less maintainable, because it requires a handwritten implementation for
each platform targeted by the compiler. This is definitely a problem in the
general case, but luckily for us, the JDK already includes <a href="https://github.com/openjdk/jdk/blob/232d13688596e9a3c1145ee456dd5a6f7cd1223d/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp#L163-L341">platform-dependent
G1 barrier
implementations</a>
for bytecode interpretation, and with a bit of plumbing we can reuse them for
C2.</p>

<p>Hopefully, at this point everyone in the room agrees that late barrier expansion
is a sensible choice for G1. Sometimes one has to swallow the urge to optimize
every detail of the program under compilation and put into the balance the many
other dimensions involved in compiler design: compilation time, modularity,
maintainability, etc. This is one of the lessons I (like to think) have learnt
in my transition from academia to industry.</p>

<p>By the way, have a look at our <a href="https://bugs.openjdk.org/browse/JDK-8322295">JDK Enhancement
Proposal</a> description if you are
interested in the gory details of the story.</p>

<p class="acks"><strong>Acknowledgements</strong>: thanks to Daniel Lundén for proofreading an earlier version of this post.</p>]]></content><author><name>Roberto Castañeda Lozano</name><email>rcas@acm.org</email></author><summary type="html"><![CDATA[Most compiler engineers I know (including myself) believe it is a good thing to expose as much information about the program under compilation as possible to the compiler. The hope is that, in return, the compiler will perform more precise analysis and more powerful optimizations. Great deal, isn’t it? Well, as in any sufficiently complex software product, there are trade-offs to consider. For example, additional program information might increase compilation times or make the compiler less maintainable. This post describes a case in a production compiler (C2, the JDK’s optimizing JIT compiler) where we have figured out that the right trade-off is to actually reduce the amount of program information fed to the compiler.]]></summary></entry><entry><title type="html">A friendlier visualization of Java’s JIT compiler based on control flow</title><link href="https://robcasloz.github.io/blog/blog/2022/05/24/a-friendlier-visualization-of-javas-jit-compiler-based-on-control-flow.html" rel="alternate" type="text/html" title="A friendlier visualization of Java’s JIT compiler based on control flow" /><published>2022-05-24T00:00:00+00:00</published><updated>2022-05-24T00:00:00+00:00</updated><id>https://robcasloz.github.io/blog/blog/2022/05/24/a-friendlier-visualization-of-javas-jit-compiler-based-on-control-flow</id><content type="html" xml:base="https://robcasloz.github.io/blog/blog/2022/05/24/a-friendlier-visualization-of-javas-jit-compiler-based-on-control-flow.html"><![CDATA[<p>The <a href="https://robcasloz.github.io/blog/2021/04/22/improving-the-ideal-graph-visualizer.html">previous
post</a>
introduced the <a href="https://github.com/openjdk/jdk/tree/master/src/utils/IdealGraphVisualizer">Ideal Graph
Visualizer</a>
(IGV), a tool to visualize the inner workings of
<a href="https://openjdk.java.net/">OpenJDK</a>’s main just-in-time compiler. This post
focuses on a new IGV feature, to be released in OpenJDK 19, to make it easier
for compiler experts to maintain and extend the compiler and for advanced Java
users to get a grasp of it.</p>

<h4 id="the-rough-sea-of-nodes">The rough sea of nodes</h4>

<p>OpenJDK’s main just-in-time (JIT) compiler, called
<a href="http://www.usenix.org/events/jvm01/full_papers/paleczny/paleczny.pdf">C2</a>,
represents the program under compilation using a <a href="https://dl.acm.org/doi/10.1145/24039.24041">program dependence
graph</a> (PDG). In a PDG, nodes
correspond to operations and edges correspond to dependencies among operations.
The distinguishing feature of PDGs is that they unify data and control: nodes
correspond to ordinary arithmetic/logic operations but also to control
operations such as conditional jumps and loops. The PDG flavor used in C2 is
often referred to as the
<a href="https://dl.acm.org/doi/10.1145/202530.202534">“sea-of-nodes”</a>. This is the PDG
of a simple loop with two exits:</p>

<p><img src="https://robcasloz.github.io/blog/assets/pdg-loop.png" alt="PDG of a simple loop with two exits" width="55%" class="center-image" /></p>

<p class="image-caption"><em>PDG of a simple loop with two exits</em></p>

<p>The unified nature of the sea-of-nodes representation <a href="https://dl.acm.org/doi/10.1145/202530.202534">eases the implementation
of a number of optimizations</a>, but
has a significant drawback: even graphs corresponding to relatively small
programs turn quickly into a tangle (a “sea of nodes”) that is quite difficult
to grasp. In the <a href="http://cr.openjdk.java.net/~jrose/draft/code-media.html">words of John
Rose</a>, one of the main
architects of the OpenJDK’s virtual machine: <em>“Engineers (…) usually cannot
read PDG graphs directly without assistance; this affects debugging speed”</em>.</p>

<h4 id="from-program-dependence-graphs-to-control-flow-graphs">From program dependence graphs to control-flow graphs</h4>

<p>The most commonly used program representation in compilers is probably the good
old control-flow graph (CFG). In a CFG, nodes correspond to basic blocks
(sequences of operations that are always executed together) and edges correspond
to control jumps across basic blocks. Unlike PDGs, CFGs explicitly assign a
basic block to each operation and order the operations within each basic block.
This increases the complexity of several compiler optimizations, but yields a
structured, sequential view of the program that is easier to understand and
debug. Furthermore, CFGs are a familiar abstraction for many systems engineers,
whereas PDGs remain an obscure topic in advanced compiler courses.</p>

<p>Inspired by feedback gathered from many C2 engineers across different
organizations and by <a href="http://cr.openjdk.java.net/~jrose/draft/code-media.html">John Rose’s call to
arms</a> (<em>“Even in a PDG,
debugging presentations can easily include trial schedules to be competitive
with CFG presentations”</em>), I have developed a <a href="https://github.com/openjdk/jdk/pull/7817">new IGV
view</a> that presents C2’s PDG-based
program representation as a CFG. The new IGV view computes its own “trial
schedule”, including an assignment of operations to basic blocks (global
schedule) and an ordering of operations within each basic block (local
schedule). The trial schedule is replaced by C2’s actual schedule when this
becomes available during the last compilation phases of C2. This is the classic
PDG view and the new CFG view of a simple method:</p>

<p><img src="https://robcasloz.github.io/blog/assets/pdg-cfg-method.png" alt="PDG and CFG of a tiny Java method" /></p>

<p class="image-caption"><em>PDG (left) and CFG (right) of a tiny Java method</em></p>

<h4 id="trying-it-out">Trying it out</h4>

<p>If you want to explore further, you can try out the new view using the above
example in a few simple steps:</p>

<ol>
  <li>
    <p>Download the <a href="https://github.com/openjdk/jdk">OpenJDK source code</a> (IGV
builds are not distributed with the JDK):</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://github.com/openjdk/jdk/archive/refs/heads/master.zip
unzip master.zip
</code></pre></div>    </div>
  </li>
  <li>
    <p>Build IGV using Maven:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd jdk-master/src/utils/IdealGraphVisualizer
mvn install
</code></pre></div>    </div>
  </li>
  <li>
    <p>Run IGV:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sh igv.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p>Open <a href="https://robcasloz.github.io/blog/assets/example.xml">this IGV graph file</a> (<code class="language-plaintext highlighter-rouge">File</code> → <code class="language-plaintext highlighter-rouge">Open...</code>).</p>

    <p>To produce your own graph file <code class="language-plaintext highlighter-rouge">foo.xml</code> instead, run a debug build of the
virtual machine with the options <code class="language-plaintext highlighter-rouge">-XX:PrintIdealGraphLevel=3
-XX:PrintIdealGraphFile=foo.xml</code>. See <a href="https://github.com/openjdk/jdk/blob/master/src/utils/IdealGraphVisualizer/README.md#usage">IGV’s usage
instructions</a>
for more detail.</p>
  </li>
  <li>
    <p>In the <code class="language-plaintext highlighter-rouge">Outline</code> window, expand the <code class="language-plaintext highlighter-rouge">example graphs</code> group and double-click
on <code class="language-plaintext highlighter-rouge">graph</code>. By default, the PDG view is shown.</p>
  </li>
  <li>
    <p>Switch to the CFG view by clicking on the following Toolbar button:</p>
  </li>
</ol>

<p><img src="https://robcasloz.github.io/blog/assets/cfg-button.png" alt="CFG button" class="center-image" /></p>

<p>Now that you have a copy of IGV’s source code on your hands, it is a good moment
to remind that there are multiple <a href="https://bugs.openjdk.java.net/issues/?jql=labels%20%3D%20c2-igv%20AND%20labels%20%3D%20starter%20AND%20%28status%20%3D%20open%20OR%20status%20%3D%20new%29%20AND%20assignee%20%3D%20null">“starter”
tasks</a>
proposed to improve the tool, and <a href="https://youtu.be/bHcKTYy_Nec">contributions are
welcome</a>! Hacking IGV is a friendly way of
learning how C2 works and getting your hands on the OpenJDK project in general.</p>

<h4 id="possible-extensions">Possible extensions</h4>

<p>Are CFGs the final word in compiler visualization? Hardly! There are many ways
in which IGV could be extended to make it more useful for compiler developers.
Here are some ideas:</p>

<ul>
  <li>
    <p><em>Visualizing program regions.</em> Programs have more structure than raw
basic blocks. IGV could improve top-down exploration by clustering basic blocks
into (nested) loops, if-then-else structures, etc.</p>
  </li>
  <li>
    <p><em>Estimating execution frequencies.</em> Basic block execution frequencies can
provide a very powerful visual aid to quickly identify the program regions that
“matter” (basic blocks that are executed most often). Currently, IGV colors
blocks by execution frequency only if the information is provided as part of the
input, but it could be extended to perform the analysis itself, similarly to how
it is done with scheduling information.</p>
  </li>
</ul>

<p><img src="https://robcasloz.github.io/blog/assets/cfg-frequencies.png" alt="CFG colored by execution frequency (cold blocks in blue, hot blocks in red)" width="60%" class="center-image" /></p>

<p class="image-caption"><em>CFG colored by execution frequency (cold blocks in blue, hot blocks in red)</em></p>

<ul>
  <li><em>Visualizing CFG-based compilers.</em> Until now, IGV had been limited to
compilers using a PDG representation, but thanks to the new view, CFG-based
compilers (for example C1, OpenJDK’s lightweight JIT compiler), could also
benefit from it.</li>
</ul>

<h4 id="other-improvements-in-jdk-19">Other improvements in JDK 19</h4>

<p>Besides introducing the new CFG view, IGV has been <a href="https://github.com/openjdk/jdk/pull/7347">upgraded to JDK
17</a> and made faster than ever
(bringing in average speedups of 15x and 2.4x for
<a href="https://github.com/openjdk/jdk/pull/8037">scheduling</a> and
<a href="https://github.com/openjdk/jdk/pull/8073">viewing</a> graphs).</p>

<p>If you have feedback, questions, or want to discuss any of the above ideas,
<a href="https://robcasloz.github.io/contact.html">talk to me</a>!</p>

<p class="acks"><strong>Acknowledgements</strong>: thanks to Jesper Wilhelmsson and Vladimir Kozlov for
providing feedback on an earlier version of this post.</p>]]></content><author><name>Roberto Castañeda Lozano</name><email>rcas@acm.org</email></author><summary type="html"><![CDATA[The previous post introduced the Ideal Graph Visualizer (IGV), a tool to visualize the inner workings of OpenJDK’s main just-in-time compiler. This post focuses on a new IGV feature, to be released in OpenJDK 19, to make it easier for compiler experts to maintain and extend the compiler and for advanced Java users to get a grasp of it.]]></summary></entry><entry><title type="html">Improving the Ideal Graph Visualizer for better comprehension of Java’s main JIT compiler</title><link href="https://robcasloz.github.io/blog/blog/2021/04/22/improving-the-ideal-graph-visualizer.html" rel="alternate" type="text/html" title="Improving the Ideal Graph Visualizer for better comprehension of Java’s main JIT compiler" /><published>2021-04-22T00:00:00+00:00</published><updated>2021-04-22T00:00:00+00:00</updated><id>https://robcasloz.github.io/blog/blog/2021/04/22/improving-the-ideal-graph-visualizer</id><content type="html" xml:base="https://robcasloz.github.io/blog/blog/2021/04/22/improving-the-ideal-graph-visualizer.html"><![CDATA[<p>Hello, world! This first post describes a tool to visualize the inner workings
of Java’s main JIT compiler, and our work to make this tool more useful for
current and potential users.</p>

<h4 id="making-sense-out-of-a-large-complex-jit-compiler">Making sense out of a large, complex JIT compiler</h4>

<p>Program comprehension is one of the main challenges in maintaining large and
complex software systems. After a few months trying to find my way around
<a href="http://www.usenix.org/events/jvm01/full_papers/paleczny/paleczny.pdf">C2</a> (the
main JIT compiler in <a href="https://openjdk.java.net/">OpenJDK</a>, the reference Java
implementation), I can attest to that! Luckily, optimizing compilers like C2 are
often designed around a well-specified representation of the code under
compilation: an <a href="http://cr.openjdk.java.net/~jrose/draft/code-media.html">Intermediate
Representation</a>, or
just “IR”. Understanding the structure and main invariants of the IR is often
the gateway to understanding the compiler itself. As Eric Raymond <a href="http://www.catb.org/~esr/writings/cathedral-bazaar/">put
it</a> (paraphrasing Fred
Brooks): <em>“Show me your code and conceal your data structures, and I shall
continue to be mystified. Show me your data structures, and I won’t usually need
your code; it’ll be obvious”</em>.</p>

<h4 id="ideal-graph-visualizer-is-our-friend">Ideal Graph Visualizer is our friend</h4>

<p>Luckily for those of us who maintain and improve C2, a tool is available to
explore the IR of a program through its different C2 compilation phases: <a href="https://github.com/openjdk/jdk/tree/master/src/utils/IdealGraphVisualizer">Ideal
Graph
Visualizer</a>
(IGV). IGV is not only “visual”, but also interactive, making it possible to
disentangle, with a few mouse clicks, the complex graph that lies at the core of
C2’s IR. Created in 2007 by Thomas Wuerthinger as part of his <a href="https://ssw.jku.at/Research/Papers/Wuerthinger07Master/Wuerthinger07Master.pdf">master’s
thesis</a>,
IGV is used today as much by C2 newcomers (like me) as by the most experienced
engineers. Time saved by using IGV means more time can be spent improving C2
itself!</p>

<h4 id="improvements-in-jdk-17">Improvements in JDK 17</h4>

<p>Given the value provided by IGV, we have recently set about improving the tool
so that it can support even better the needs of both experienced and new C2
engineers. Among <a href="https://github.com/openjdk/jdk/pulls?q=IGV+in%3Atitle+author%3Arobcasloz">other
improvements</a>,
we have <a href="https://github.com/openjdk/jdk/pull/2607">fixed the most frequent
crashes</a>, <a href="https://github.com/openjdk/jdk/pull/3361">simplified the build
process</a>, <a href="https://github.com/openjdk/jdk/pull/3361">introduced support for the
latest JDK versions</a>, <a href="https://github.com/openjdk/jdk/pull/2285">made it easier
to search for specific nodes in the IR
graph</a>, and <a href="https://github.com/openjdk/jdk/pull/2499">introduced more intuitive
coloring schemes and default filters to focus on different aspects of the
IR</a>.</p>

<p><img src="https://robcasloz.github.io/blog/assets/before-after-jdk-improvements.png" alt="IGV before and after JDK 17 improvements" /></p>

<p class="image-caption"><em>IGV before (left) and after (right) JDK 17 improvements</em></p>

<p>These improvements have already made it into <a href="https://github.com/openjdk/jdk">OpenJDK’s main
repository</a>, and will be part of <a href="https://openjdk.java.net/projects/jdk/17/">JDK
17</a>. Even thought IGV, as an internal
development tool, is typically not distributed with the virtual machine, we have
made it <a href="https://github.com/openjdk/jdk/blob/master/src/utils/IdealGraphVisualizer/README.md#building-and-running">very
simple</a>
to build it if you want to give it a try.</p>

<h4 id="future-work">Future work</h4>

<p>In the future, we would like to consolidate the functionality already supported
by IGV as well as extend IGV with new use cases. After talking with a fair
number of C2 engineers from different organizations, it is clear that there is
interest and no shortage of ideas for improving IGV! For example, a recurring
theme is that, while IGV has good support for exploring and tracking the
neighborhood of an IR node through the compilation phases (“bottom-up
exploration”), it could do a better job at presenting the overall structure and
components (e.g. loops) of the program under compilation for top-down
exploration.</p>

<h4 id="getting-involved">Getting involved</h4>

<p>If you have ever used IGV, it is never too late to tell us about your experience
with the tool and what could be improved in general. Even better, if you want to
get further involved in the improvement work, there is always something to be
done, from reporting issues at the <a href="https://bugs.openjdk.java.net">JDK Bug
System</a> to actually picking up <a href="https://bugs.openjdk.java.net/issues/?jql=labels%20%3D%20c2-igv%20AND%20%28status%20%3D%20open%20OR%20status%20%3D%20new%29%20AND%20assignee%20%3D%20null">IGV improvement
tasks</a>.
Some of these tasks, <a href="https://bugs.openjdk.java.net/issues/?jql=labels%20%3D%20c2-igv%20AND%20labels%20%3D%20starter%20AND%20%28status%20%3D%20open%20OR%20status%20%3D%20new%29%20AND%20assignee%20%3D%20null">marked with the label
“starter”</a>,
are particularly suitable for newcomers who want to learn and contribute to
OpenJDK: improving IGV is a more fun and less intimidating path towards learning
the internals of a large and complex compiler than hacking the compiler itself.</p>

<p class="acks"><strong>Acknowledgements</strong>: thanks to David Therkelsen for providing feedback on an
earlier version of this post.</p>]]></content><author><name>Roberto Castañeda Lozano</name><email>rcas@acm.org</email></author><summary type="html"><![CDATA[Hello, world! This first post describes a tool to visualize the inner workings of Java’s main JIT compiler, and our work to make this tool more useful for current and potential users.]]></summary></entry></feed>