<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Romain Guy</title><link>https://www.romainguy.dev/posts/</link><description>Recent content in Posts on Romain Guy</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 20 Aug 2026 20:02:07 -0700</lastBuildDate><atom:link href="https://www.romainguy.dev/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Things 3</title><link>https://www.romainguy.dev/posts/2026/things-3/</link><pubDate>Thu, 20 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2026/things-3/</guid><description>&lt;p&gt;Here is a list of tings I read/watched/played/etc. this week that you might find interesting or enjoyable:&lt;/p&gt;
&lt;h1 id="things-to-read"&gt;
 Things to read
 &lt;a class="heading-link" href="#things-to-read"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pikuma.com/blog/programming-intel-pentium-mmx-simd" class="external-link" target="_blank" rel="noopener"&gt;SIMD in the 90s&lt;/a&gt; — Great article explaining what Intel&amp;rsquo;s MMX was all about.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linear.axler.net/" class="external-link" target="_blank" rel="noopener"&gt;Linear algebra done right&lt;/a&gt; — Contains a lot of stuff that I feel like I have to relearn every few years.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marekfiser.com/blog/double-double-arithmetic/" class="external-link" target="_blank" rel="noopener"&gt;Double-double: 31 digits of precision without leaving the FPU&lt;/a&gt; — I &lt;em&gt;really&lt;/em&gt;, &lt;em&gt;really&lt;/em&gt; like reading about floaing points :)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://acko.net/blog/curvature-beziers/" class="external-link" target="_blank" rel="noopener"&gt;Curvature Béziers&lt;/a&gt; — Yet another fascinating article on Bézier curves, this time with a focus on curvature.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.shadertoy.com/view/ffcSRl" class="external-link" target="_blank" rel="noopener"&gt;Blackbody: 4 rational fits&lt;/a&gt; — A set of analytical fits for blackbody colors, from 798 to 5772 K. I have used &lt;a href="https://google.github.io/filament/Filament.md.html#mjx-eqn%3AseriesDtoxyY" class="external-link" target="_blank" rel="noopener"&gt;a common fit&lt;/a&gt; before, but these fits look more useful in some situations.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.doubleword.ai/what-happens-when-a-gpu-reads-memory" class="external-link" target="_blank" rel="noopener"&gt;What happens when a GPU reads memory&lt;/a&gt; — More information about how GPUs work is always welcome.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="things-to-watch"&gt;
 Things to watch
 &lt;a class="heading-link" href="#things-to-watch"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=469J8UVCbAA" class="external-link" target="_blank" rel="noopener"&gt;How the Game Boy Advance&amp;rsquo;s graphics modes made it so advanced&lt;/a&gt; — A tour of the GameBoy Advance&amp;rsquo;s graphics modes. I had a blast programming for the GBA back then, I kind of miss this style of graphics programming.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Things 2</title><link>https://www.romainguy.dev/posts/2026/things-2/</link><pubDate>Thu, 13 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2026/things-2/</guid><description>&lt;p&gt;Here is a list of tings I read/watched/played/etc. this week that you might find interesting or enjoyable:&lt;/p&gt;
&lt;h1 id="things-to-read"&gt;
 Things to read
 &lt;a class="heading-link" href="#things-to-read"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vitaut.net/posts/2026/yy-dtoa/" class="external-link" target="_blank" rel="noopener"&gt;The fastest double-to-string algorithm you&amp;rsquo;ve never heard of&lt;/a&gt; — I always enjoy reading about how floating point formats work.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-20-66/2026_2D00_mmg_2D00_liam_2D00_nssd.pdf" class="external-link" target="_blank" rel="noopener"&gt;Neural Super Sampling and Denoising&lt;/a&gt; —
Interesting deep-dive about super sampling and denoising from Arm.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marc-b-reynolds.github.io/math/2026/08/10/IntDivByFP.html" class="external-link" target="_blank" rel="noopener"&gt;Moving integer division to floating-point is trivial&lt;/a&gt; — I &lt;em&gt;really&lt;/em&gt; like reading about floaing points :)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://theorangeduck.com/page/inverse-kinematics-foot-locking" class="external-link" target="_blank" rel="noopener"&gt;Inverse kinematics and foot locking&lt;/a&gt; —
I never had the chance to work on an IK system, and it&amp;rsquo;s something I&amp;rsquo;d love to do some day. This article describes in depth some of the details that can greatly improve the quality of the results.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linebender.org/blog/hyperbezier/" class="external-link" target="_blank" rel="noopener"&gt;The mathematical beauty of hyperbezier curves&lt;/a&gt; — Another one of my obsessions: Bézier curves. Raph strikes again with yet another fascinating article on the topic.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fr.wikipedia.org/wiki/La_Horde_du_Contrevent" class="external-link" target="_blank" rel="noopener"&gt;La horde du contrevent&lt;/a&gt; — La horde is finally going to be &lt;a href="https://www.amazon.com/dp/141979258X" class="external-link" target="_blank" rel="noopener"&gt;available in English&lt;/a&gt;. I am truly curious to see how well it will preserve the original style. This book is definitely a translation challenge.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="things-to-watch"&gt;
 Things to watch
 &lt;a class="heading-link" href="#things-to-watch"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Bureau_%28TV_series%29" class="external-link" target="_blank" rel="noopener"&gt;The Bureau&lt;/a&gt; — An espionage thriller that feels much more grounded than most shows and movies.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=rE75WvOtcu8" class="external-link" target="_blank" rel="noopener"&gt;We need to talk about Leopold&lt;/a&gt; — Sigh. Wtf. Also, lol.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=srht2WdXuWI" class="external-link" target="_blank" rel="noopener"&gt;Turbocharging the worst VESA local bus graphics card&lt;/a&gt; — This will either bring you fond memories, or nightmares about the MS-DOS days.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=UXXVNt4fQVI" class="external-link" target="_blank" rel="noopener"&gt;Île de Pâques&lt;/a&gt; — A short documentary that goes beyond the superficial and common trope about what happened to the Rapa Nui. In French.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=aQv9pUl9PBM" class="external-link" target="_blank" rel="noopener"&gt;Reducing graphics API complexity&lt;/a&gt; — Seb&amp;rsquo;s must-watch take on graphics APIs and a possible path forward.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="things-i-did"&gt;
 Things I did
 &lt;a class="heading-link" href="#things-i-did"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/google/filament/pull/10302" class="external-link" target="_blank" rel="noopener"&gt;Second roughness&lt;/a&gt; — This PR adds a second, optional, specular lobe to Filament&amp;rsquo;s materials. This feature can be used to create more realistic metallic surfaces or, in general, any material with a hazy appearance. An implementation of &lt;a href="https://www.youtube.com/watch?v=uz8PIi3ELJg" class="external-link" target="_blank" rel="noopener"&gt;Forgotten metal knowledge&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Things 1</title><link>https://www.romainguy.dev/posts/2026/things-1/</link><pubDate>Thu, 06 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2026/things-1/</guid><description>&lt;p&gt;Here is a list of tings I read/watched/played/etc. this week that you might find interesting or enjoyable:&lt;/p&gt;
&lt;h1 id="things-to-read"&gt;
 Things to read
 &lt;a class="heading-link" href="#things-to-read"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://towardsdev.com/cpp26-std-hive-deep-dive-tutorial-5bdaa44f4d94" class="external-link" target="_blank" rel="noopener"&gt;A Deep Dive into C++26 std::hive: The Ultimate Container for Active Data&lt;/a&gt; — Some details about the internals of C++ 26&amp;rsquo;s new data structure.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lemire.me/blog/2026/08/02/how-fast-is-c26s-stdhive/" class="external-link" target="_blank" rel="noopener"&gt;How fast is C++26’s std::hive?&lt;/a&gt; —
Pretty self-explanatory and useful numbers to keep in mind.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://graphics.ucsd.edu/~henrik/papers/skin_bssrdf/skin_bssrdf.pdf" class="external-link" target="_blank" rel="noopener"&gt;A Spectral BSSRDF for Shading Human Skin&lt;/a&gt; — A spectral shading model
that can be used to render different skin tones.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssteinberg.xyz/2026_surface_scattering_accuracy/2026_surface_scattering_accuracy.pdf" class="external-link" target="_blank" rel="noopener"&gt;On the Accuracy of Surface Scattering Theories&lt;/a&gt; —
Another reason why our rendering models are not quite good enough.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jcgt.org/published/0015/02/01/" class="external-link" target="_blank" rel="noopener"&gt;A Texture Lookup Approach to Bézier Curve Evaluation on the GPU&lt;/a&gt; — A clever use of GPU textures units to render Bézier curves efficiently.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.viz.com/shonenjump/chapters/haikyu" class="external-link" target="_blank" rel="noopener"&gt;Haikyu!!&lt;/a&gt; — I&amp;rsquo;ve been re-reading this manga. The
anime is also worth it, for the animation itself.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Annapurna_%28book%29" class="external-link" target="_blank" rel="noopener"&gt;Annapurna: First Conquest of an 8000-meter Peak&lt;/a&gt; — Maurice Herzog&amp;rsquo;s account of the first successful ascent of Annapurna. Read the French original if you can. And you might want to read &lt;em&gt;True Summit&lt;/em&gt; afterwards.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="things-to-watch"&gt;
 Things to watch
 &lt;a class="heading-link" href="#things-to-watch"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=EU_nQh8wg5A" class="external-link" target="_blank" rel="noopener"&gt;Benchmarking - It&amp;rsquo;s About Time&lt;/a&gt; — Benchmarking is
hard, but Matt Godbolt makes it fun and interesting.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Nirvanna the Band the Show the Movie&lt;/em&gt; — I watched it without knowing what it was really about.
You should do the same, it takes an unexpected turn.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="things-i-want-to-try"&gt;
 Things I want to try
 &lt;a class="heading-link" href="#things-i-want-to-try"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/wasmcomputercompany/wasmo" class="external-link" target="_blank" rel="noopener"&gt;Wasmo&lt;/a&gt; — An Open Source &amp;ldquo;cloud computer&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/morishuz/delaunay32" class="external-link" target="_blank" rel="noopener"&gt;delaunay32&lt;/a&gt; — Fast, parallel 2D Delaunay triangulation using exact integer predicates.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Tap Detection on Arbitrary Shapes with Compose</title><link>https://www.romainguy.dev/posts/2025/arbitrary-shape-tap-detection/</link><pubDate>Sun, 07 Dec 2025 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2025/arbitrary-shape-tap-detection/</guid><description>&lt;p&gt;Detecting whether a user tapped on an arbitrary shape represented by a
&lt;a href="https://developer.android.com/reference/android/graphics/Path" class="external-link" target="_blank" rel="noopener"&gt;Path&lt;/a&gt; is an unfortunately difficult
task on Android. The &lt;code&gt;Path&lt;/code&gt; class does not offer any API to do this, and the workaround I have seen
folks use (representing the tap as a small rectangle/circle and computing the intersection with
the test shape) is inefficient and sometimes fails.&lt;/p&gt;
&lt;p&gt;Thankfully, Jetpack Compose a simple way to perform this task. The video below shows how the Compose
APIs can be used to detect taps, or generally perform any test requiring to check whether a specific
2D coordinate is contained inside a &lt;code&gt;Path&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Finger Shadows in Compose</title><link>https://www.romainguy.dev/posts/2025/finger-shadows/</link><pubDate>Sat, 29 Nov 2025 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2025/finger-shadows/</guid><description>&lt;p&gt;I recently realized that I have never discussed graphics programming on this blog, and decided
it was time to correct this. A few years ago, Android 13 introduced the
&lt;a href="https://developer.android.com/reference/android/graphics/RuntimeShader" class="external-link" target="_blank" rel="noopener"&gt;RuntimeShader&lt;/a&gt; API
that allows you to write custom GPU shaders and apply them to UI elements. In this blog post
I will show you how this API can be used to simulate shadows projected by the user&amp;rsquo;s finger (or
stylus/pointing device) onto your UI.&lt;/p&gt;</description></item><item><title>Merge Your Computations</title><link>https://www.romainguy.dev/posts/2025/merge-your-computations/</link><pubDate>Thu, 15 May 2025 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2025/merge-your-computations/</guid><description>&lt;p&gt;There is a simple but often overlooked technique to optimize performance-sensitive code: merging
(or manually inlining) functions. We often build series of low-level functions that execute various
computations that we then combine to perform higher-level tasks. When taken in isolation, each of
those functions does exactly what it should and might even be perfectly optimized. However, when a
series of thosefunctions work together, unnecessary or duplicated work might appear.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at a concrete example taken from the Jetpack Compose code base. To apply the various
geometric transforms that may affect a layer, Compose needs to build a matrix that combines all
the transformations exposed by its APIs:&lt;/p&gt;</description></item><item><title>Eliminating Array Bounds Checks</title><link>https://www.romainguy.dev/posts/2025/eliminating-array-bounds-checks/</link><pubDate>Tue, 13 May 2025 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2025/eliminating-array-bounds-checks/</guid><description>&lt;p&gt;The Android Runtime (ART) offers a nice memory safety feature when accessing the content of an
array. The indices you use are automatically checked against the bounds of the array to prevent
unsafe memory accesses. To achieve this, ART generates extra machine instructions to throw an
&lt;code&gt;ArrayIndexOutOfBoundsException&lt;/code&gt; when the index is invalid.&lt;/p&gt;
&lt;p&gt;Here is a simple Kotlin example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-1"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-1"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;fun&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;scaleZ&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;values&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;FloatArray&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;scale&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Float&lt;/span&gt;) = &lt;span style="color:#e06c75"&gt;values&lt;/span&gt;[&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;] * &lt;span style="color:#e06c75"&gt;scale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After translation to arm64 assembly, we obtain the following result:&lt;/p&gt;</description></item><item><title>Naming is Hard</title><link>https://www.romainguy.dev/posts/2024/naming-is-hard/</link><pubDate>Thu, 19 Dec 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/naming-is-hard/</guid><description>&lt;p&gt;Before we dive into today&amp;rsquo;s topic, I would like to make it clear that what follows is specific to
how Android, and more precisely the Android RunTime (ART), works. Some of what follows applies to
other environments as well, but the main twist is about Android.&lt;/p&gt;
&lt;p&gt;If you have read my previous articles, you should know by now that seemingly small or irrelevant
changes can have a large impact on performance. So let&amp;rsquo;s look at another one! We&amp;rsquo;ll start our
journey with a class containing a bunch of fields. What they are and what they mean isn&amp;rsquo;t really
relevant for now, let&amp;rsquo;s just imagine we are dealing with a fairly large object&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;</description></item><item><title>The Path Not Taken</title><link>https://www.romainguy.dev/posts/2024/the-path-not-taken/</link><pubDate>Mon, 16 Dec 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/the-path-not-taken/</guid><description>&lt;p&gt;In the last post, we saw that
&lt;a href="../you-are-going-to-need-it" &gt;benchmarks don&amp;rsquo;t always measure what we think they measure&lt;/a&gt;.
Let&amp;rsquo;s look at another instance of this problem today, starting with this rather simple benchmark:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-1"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-1"&gt; 1&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@RunWith&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;AndroidJUnit4&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;::&lt;/span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-2"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-2"&gt; 2&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;DataBenchmark&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-3"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-3"&gt; 3&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#61afef"&gt;@get&lt;/span&gt;:&lt;span style="color:#e06c75"&gt;Rule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-4"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-4"&gt; 4&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;val&lt;/span&gt; &lt;span style="color:#e06c75"&gt;benchmarkRule&lt;/span&gt; = &lt;span style="color:#e06c75"&gt;BenchmarkRule&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-5"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-5"&gt; 5&lt;/a&gt;&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-6"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-6"&gt; 6&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// Generate data in [0..255]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-7"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-7"&gt; 7&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#c678dd"&gt;val&lt;/span&gt; &lt;span style="color:#e06c75"&gt;data&lt;/span&gt; = &lt;span style="color:#e06c75"&gt;IntArray&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;65&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_536&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-8"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-8"&gt; 8&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;it&lt;/span&gt; % &lt;span style="color:#d19a66"&gt;256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-9"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-9"&gt; 9&lt;/a&gt;&lt;/span&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-10"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-10"&gt;10&lt;/a&gt;&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-11"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-11"&gt;11&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#61afef"&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-12"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-12"&gt;12&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;fun&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;processData&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-13"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-13"&gt;13&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;var&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sum&lt;/span&gt; = &lt;span style="color:#d19a66"&gt;0f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-14"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-14"&gt;14&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;benchmarkRule&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;measureRepeated&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-15"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-15"&gt;15&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;d&lt;/span&gt; &lt;span style="color:#c678dd"&gt;in&lt;/span&gt; &lt;span style="color:#c678dd"&gt;data&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-16"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-16"&gt;16&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;d&lt;/span&gt; &amp;lt; &lt;span style="color:#d19a66"&gt;128&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-17"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-17"&gt;17&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sum&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;d&lt;/span&gt; / &lt;span style="color:#d19a66"&gt;128f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-18"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-18"&gt;18&lt;/a&gt;&lt;/span&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-19"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-19"&gt;19&lt;/a&gt;&lt;/span&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-20"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-20"&gt;20&lt;/a&gt;&lt;/span&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-21"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-21"&gt;21&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;BlackHole&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;consume&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;sum&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-22"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-22"&gt;22&lt;/a&gt;&lt;/span&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-23"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-23"&gt;23&lt;/a&gt;&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This benchmark tests an algorithm that processes an array of values between 0 and 255 (8-bit pixels
for instance), and computes the sum of the normalized values for pixels less than 128.&lt;/p&gt;</description></item><item><title>You Are Going to Need It</title><link>https://www.romainguy.dev/posts/2024/you-are-going-to-need-it/</link><pubDate>Fri, 13 Dec 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/you-are-going-to-need-it/</guid><description>&lt;p&gt;Optimizing code can be a difficult task because there are so many traps you need to avoid at every
step of the way. Today I want to focus on one of the (numerous) benchmarking traps, which you may
have run into, and that I myself encounter regularly.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s imagine you are trying to optimize code, and you
&lt;a href="https://bsky.app/profile/romainguy.dev/post/3lbxlo5h4qk2v" class="external-link" target="_blank" rel="noopener"&gt;notice&lt;/a&gt; the use of a &lt;code&gt;value.pow(2f)&lt;/code&gt;. One
obvious way to optimize this is to replace the function call with a multiplication (&lt;code&gt;value * value&lt;/code&gt;),
but is it worth it? Since you are a diligent engineer, you decide to write a microbenchmark to
compare before and after:&lt;/p&gt;</description></item><item><title>Optimization, Step by Step</title><link>https://www.romainguy.dev/posts/2024/optimization-step-by-step/</link><pubDate>Mon, 25 Nov 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/optimization-step-by-step/</guid><description>&lt;p&gt;&lt;a href="https://blurha.sh/" class="external-link" target="_blank" rel="noopener"&gt;BlurHash&lt;/a&gt; is a compact representation of placeholders for images. A blur hash
is encoded as a short string that can be rendered to a bitmap at runtime to display a &amp;ldquo;blurry&amp;rdquo;
version of the source image. The way it works remind me of &lt;a href="https://google.github.io/filament/Filament.html#lighting/imagebasedlights/processinglightprobes" class="external-link" target="_blank" rel="noopener"&gt;how spherical harmonics are used&lt;/a&gt;
in 3D rendering engines to efficiently encode irradiance.&lt;/p&gt;
&lt;p&gt;I recently remembered that I had been meaning to look at the Kotlin implementation of BlurHash to
see if there was a way to make it faster. I looked up the
&lt;a href="https://github.com/vanniktech/blurhash/" class="external-link" target="_blank" rel="noopener"&gt;KMP port&lt;/a&gt; and after a few changes, I was able to make
decoding a blur hash up to 4.35x faster on a Pixel 6 running Android 14. For all the measurements
mentioned in this article, I decoded a fixed blur hash to a 384x384 image. The original code took
24.4 ms to do this when running at full speed, and 41.5 ms when locking the CPU clocks. This is way
too long considering the low resolution of the image.&lt;/p&gt;</description></item><item><title>A Micro-optimization You Will Never Need</title><link>https://www.romainguy.dev/posts/2024/a-micro-optimization-you-will-never-need/</link><pubDate>Sun, 10 Nov 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/a-micro-optimization-you-will-never-need/</guid><description>&lt;p&gt;Today I would like to show you a micro-optimization I recently used more for the fun of it than for
its real impact. It&amp;rsquo;s an interesting trick that you should never bother to use, nor worry about.&lt;/p&gt;
&lt;p&gt;It starts from a piece of Kotlin code that looked a bit like this (the original version used named
constants, but I replaced them with their actual values for clarity in this context):&lt;/p&gt;</description></item><item><title>Down Another Rabbit Hole</title><link>https://www.romainguy.dev/posts/2024/down-another-rabbit-hole/</link><pubDate>Mon, 27 May 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/down-another-rabbit-hole/</guid><description>&lt;p&gt;&lt;a href="https://jakewharton.com/" class="external-link" target="_blank" rel="noopener"&gt;Jake Wharton&lt;/a&gt; recently caused me to go down yet another silly
optimization rabbit hole when he nonchalantly linked to
&lt;a href="https://github.com/square/okio/blob/c90794f83170d770eb247c56ade80c0a6661a5d6/okio/src/commonMain/kotlin/okio/internal/Buffer.kt#L464-L520" class="external-link" target="_blank" rel="noopener"&gt;a piece of code&lt;/a&gt;
used to count the number of digits in a &lt;code&gt;Long&lt;/code&gt; during a Slack conversation about Kotlin&amp;rsquo;s lack
of ternary operator. This of course triggered folks like &lt;a href="https://x.com/madisp" class="external-link" target="_blank" rel="noopener"&gt;Madis Pink&lt;/a&gt; and
me to want to optimize it…&lt;/p&gt;
&lt;h1 id="counting-digits"&gt;
 Counting digits
 &lt;a class="heading-link" href="#counting-digits"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;The simplest way to count the number of digits would be to compute &lt;code&gt;log10(n).toInt() + 1&lt;/code&gt;, where &lt;code&gt;n&lt;/code&gt;
is our input number. Unfortunately logarithmic functions like
&lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/log10.html#kotlin.math$log10%28kotlin.Double%29" class="external-link" target="_blank" rel="noopener"&gt;Kotlin&amp;rsquo;s log10&lt;/a&gt;
are only defined for floating point numbers. If our input is an &lt;code&gt;Int&lt;/code&gt; or a &lt;code&gt;Long&lt;/code&gt;, we could first
convert to &lt;code&gt;Double&lt;/code&gt; and then call &lt;code&gt;log10&lt;/code&gt;, but not all &lt;code&gt;Long&lt;/code&gt; values can be stored in a &lt;code&gt;Double&lt;/code&gt;
(any value above 2^53), and we would have to special case &lt;code&gt;0&lt;/code&gt;. We must therefore find a different
solution&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;</description></item><item><title>Down a Rabbit Hole</title><link>https://www.romainguy.dev/posts/2024/down-a-rabbit-hole/</link><pubDate>Sat, 18 May 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/down-a-rabbit-hole/</guid><description>&lt;p&gt;I &lt;a href="https://www.romainguy.dev/posts/2024/readability-of-optimized-kotlin-code/" &gt;recently discussed an optimization&lt;/a&gt;
that I worked on following &lt;a href="http://intelligiblebabble.com/" class="external-link" target="_blank" rel="noopener"&gt;Leland&lt;/a&gt;&amp;rsquo;s successful nerd snipe. That,
however, was not the end of it. He also needed to test for intersecting/overlapping rectangles. The
most obvious way to achieve this is pretty straightforward:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-1"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-1"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// A rectangle is defined by its left (l), top (t),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-2"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-2"&gt;2&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// right (r), and bottom (b) coordinates
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-3"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-3"&gt;3&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;&lt;/span&gt;&lt;span style="color:#c678dd"&gt;data&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Rect&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;val&lt;/span&gt; &lt;span style="color:#e06c75"&gt;l&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Int&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;val&lt;/span&gt; &lt;span style="color:#e06c75"&gt;t&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Int&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;val&lt;/span&gt; &lt;span style="color:#e06c75"&gt;r&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Int&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;val&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Int&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-4"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-4"&gt;4&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;fun&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;overlaps&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;other&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Rect&lt;/span&gt;) =
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-5"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-5"&gt;5&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;l&lt;/span&gt; &amp;lt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;l&lt;/span&gt; &amp;lt; &lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;t&lt;/span&gt; &amp;lt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;other&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;t&lt;/span&gt; &amp;lt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-6"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-6"&gt;6&lt;/a&gt;&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The source code is nice and tidy, but the generated assembly is less than ideal (as always,
the code was optimized with R8 first):&lt;/p&gt;</description></item><item><title>Practical Optimizations at Android Makers 2024</title><link>https://www.romainguy.dev/posts/2024/practical-optimizations-at-android-makers-2024/</link><pubDate>Mon, 06 May 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/practical-optimizations-at-android-makers-2024/</guid><description>&lt;p&gt;I recently gave a talk called &lt;a href="https://www.youtube.com/watch?v=5cxw_fdpnoA" class="external-link" target="_blank" rel="noopener"&gt;Practical Optimizations&lt;/a&gt;
at &lt;a href="https://androidmakers.droidcon.com/" class="external-link" target="_blank" rel="noopener"&gt;Android Makers 2024&lt;/a&gt;. The talk is focused on
some of the low-level optimizations we implemented in
&lt;a href="https://developer.android.com/develop/ui/compose" class="external-link" target="_blank" rel="noopener"&gt;Jetpack Compose&lt;/a&gt;, their impact on performance,
and the programming techniques behind them. You will likely find this talk interesting if you&amp;rsquo;ve been
enjoying the articles about &lt;a href="https://www.romainguy.dev/tags/performance/" &gt;performance and optimizations&lt;/a&gt; on
this blog.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/5cxw_fdpnoA?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;</description></item><item><title>Readability of Optimized Kotlin Code</title><link>https://www.romainguy.dev/posts/2024/readability-of-optimized-kotlin-code/</link><pubDate>Fri, 03 May 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/readability-of-optimized-kotlin-code/</guid><description>&lt;p&gt;&lt;a href="http://intelligiblebabble.com/" class="external-link" target="_blank" rel="noopener"&gt;Leland&lt;/a&gt; and I were recently discussing how to best implement
a new data structure to speed up a specific aspect of Jetpack Compose. He came up with a great
idea, and &lt;a href="https://xkcd.com/356/" class="external-link" target="_blank" rel="noopener"&gt;nerd sniped&lt;/a&gt; me in the process. The problem was to efficiently
encode the occupancy of an 8x8 grid represented as a &lt;code&gt;Long&lt;/code&gt; (each bit representing a cell in the
grid).&lt;/p&gt;
&lt;p&gt;After coming up with the bit twiddling code that quickly &amp;ldquo;rasterizes&amp;rdquo; a rectangle into the grid
as a bitfield, I found myself thinking about how incredibly helpful Kotlin can be at making
low-level/micro-optimized code easy to read&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; for users of an API.&lt;/p&gt;</description></item><item><title>Speeding up isBlank()</title><link>https://www.romainguy.dev/posts/2024/speeding-up-isblank/</link><pubDate>Mon, 05 Feb 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/speeding-up-isblank/</guid><description>&lt;p&gt;I was recently optimizing a small part of the Jetpack Compose runtime when I stumbled upon
a seemingly harmless API,
&lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/is-blank.html" class="external-link" target="_blank" rel="noopener"&gt;isBlank()&lt;/a&gt;. This API
return &lt;code&gt;true&lt;/code&gt; if the string it&amp;rsquo;s called on is empty or consists solely of whitespace characters.&lt;/p&gt;
&lt;p&gt;But is it truly harmless? Let&amp;rsquo;s look at the JVM implementation to get a better sense of what
it does:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-1"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-1"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#c678dd"&gt;actual&lt;/span&gt; &lt;span style="color:#c678dd"&gt;fun&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;CharSequence&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;isBlank&lt;/span&gt;(): &lt;span style="color:#e06c75"&gt;Boolean&lt;/span&gt; =
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f" id="hl-0-2"&gt;&lt;a style="outline:none;text-decoration:none;color:inherit" href="#hl-0-2"&gt;2&lt;/a&gt;&lt;/span&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;length&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;==&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;||&lt;/span&gt; &lt;span style="color:#e06c75"&gt;indices&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;all&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;[&lt;span style="color:#c678dd"&gt;it&lt;/span&gt;].&lt;span style="color:#e06c75"&gt;isWhitespace&lt;/span&gt;() }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simple and straight to the point. Unfortunately the bytecode tells a very different story:&lt;/p&gt;</description></item><item><title>Micro-optimizations in Kotlin — 3</title><link>https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-3/</link><pubDate>Wed, 31 Jan 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-3/</guid><description>&lt;p&gt;The Kotlin standard library is a wonderful set of APIs, but it sometimes hides… interesting
surprises. So today let&amp;rsquo;s took at the innocent looking &lt;code&gt;minOf()&lt;/code&gt; and &lt;code&gt;maxOf()&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;These functions let you perform a min/max on a series of values, instead of just two with the
more common &lt;code&gt;min()&lt;/code&gt; and &lt;code&gt;max()&lt;/code&gt; functions. Both &lt;code&gt;min()&lt;/code&gt; and &lt;code&gt;max()&lt;/code&gt; are straightforward and
simply delegate — on Android and JVM — to &lt;code&gt;Math.min()&lt;/code&gt;/&lt;code&gt;Math.max()&lt;/code&gt; respectively, which you
can assume to be implemented with intrinsics (and are on Android).&lt;/p&gt;</description></item><item><title>Going Old School</title><link>https://www.romainguy.dev/posts/2024/going-old-school/</link><pubDate>Thu, 25 Jan 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/going-old-school/</guid><description>&lt;p&gt;While looking for optimization opportunities in various parts of Jetpack Compose, I recently
discovered that calling the cube root function was taking a non-neligible amount of times in
two areas of the Toolkit: when evaluating
&lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/CubicBezierEasing" class="external-link" target="_blank" rel="noopener"&gt;cubic Bézier easing curves&lt;/a&gt;
and when &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/package-summary#lerp%28androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,kotlin.Float%29" class="external-link" target="_blank" rel="noopener"&gt;interpolating colors&lt;/a&gt; through the OkLab color space.&lt;/p&gt;
&lt;p&gt;Working on &lt;a href="https://github.com/google/filament" class="external-link" target="_blank" rel="noopener"&gt;graphics projects&lt;/a&gt; taught me that approximations
can often be powerful optimization tools, so I decided to come up with an approximation of
&lt;code&gt;cbrt()&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;</description></item><item><title>A Better Hash Map — 1</title><link>https://www.romainguy.dev/posts/2024/a-better-hashmap/</link><pubDate>Sat, 20 Jan 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/a-better-hashmap/</guid><description>&lt;p&gt;Hash maps are extremely common data structures, and Jetpack Compose unsurprisingly takes advantage
of them for various tasks. Kotlin makes it easy to create a new mutable hash map by calling the
&lt;code&gt;mutableMapOf()&lt;/code&gt; function. Most developer will — and should — stop there, and use the map however
they need to. Things are however a bit different when working on a toolkit like Jetpack Compose as
we need to ensure the toolkit&amp;rsquo;s behavior is as unintrusive as possible for the app.&lt;/p&gt;</description></item><item><title>Micro-optimizations in Kotlin — 2</title><link>https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-2/</link><pubDate>Tue, 16 Jan 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-2/</guid><description>&lt;p&gt;In the &lt;a href="https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-1/" &gt;previous post&lt;/a&gt;, we saw how we could
micro-optimize &lt;code&gt;Int.sign&lt;/code&gt; to save a few instructions. We are now going to turn to &lt;code&gt;Float.sign&lt;/code&gt;
(and by extension &lt;code&gt;Double.sign&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/sign.html" class="external-link" target="_blank" rel="noopener"&gt;&lt;code&gt;Float.sign&lt;/code&gt;&lt;/a&gt; returns the sign
of single-precision float value as a single-precision float value. While similar to &lt;code&gt;Int.sign&lt;/code&gt;, this
API must handle a special cases: Not-a-Number (&lt;code&gt;NaN&lt;/code&gt;). The exact behavior of the API is that it will
return:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-1.0f&lt;/code&gt; if the value is negative&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+/-0.0f&lt;/code&gt; if the value is zero (floats can encode both positive and negative zero)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.0f&lt;/code&gt; if the value is positive&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NaN&lt;/code&gt; if the value is &lt;code&gt;NaN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An easy way to implement this API ourselves is to return the input when the input equals &lt;code&gt;0.0f&lt;/code&gt; or
&lt;code&gt;NaN&lt;/code&gt;, and to return the input&amp;rsquo;s sign copied onto &lt;code&gt;1.0f&lt;/code&gt; otherwise. Translated to code, we can
write:&lt;/p&gt;</description></item><item><title>Micro-optimizations in Kotlin — 1</title><link>https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-1/</link><pubDate>Mon, 15 Jan 2024 00:00:00 +0000</pubDate><guid>https://www.romainguy.dev/posts/2024/micro-optimizations-in-kotlin-1/</guid><description>&lt;p&gt;While my work responsibilities do not leave me much time to write code nowadays, I have managed
to make a few small contributions to &lt;a href="https://developer.android.com/jetpack/compose" class="external-link" target="_blank" rel="noopener"&gt;Jetpack Compose&lt;/a&gt;
in the last few months, mostly focusing on performance.&lt;/p&gt;
&lt;p&gt;If you are an Android app developer, your performance concerns probably start and stop at a fairly
high level &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. I find working on large scale libraries like Compose fascinating because you need to
worry about performance not only at a macro level, but also at a micro level. Since parts of the
libraries can be invoked frequently (many times per frame for instance), even micro-optimizations
can make a difference &lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;</description></item></channel></rss>