RSSAmplifier

Blog

Posts on Romain Guy

Recent content in Posts on Romain Guy

romainguy.devRSS feed ↗21 posts

Latest posts

Things 2

Here is a list of tings I read/watched/played/etc. this week that you might find interesting or enjoyable: Things to read Link to heading The fastest double-to-string algorithm you’ve never heard of — I always enjoy reading about how floating point formats work. Neural Super Sampling and Denoising — Interesting deep-dive about super sampling and denoising from Arm. Moving integer division to…

Things 1

Here is a list of tings I read/watched/played/etc. this week that you might find interesting or enjoyable: Things to read Link to heading A Deep Dive into C++26 std::hive: The Ultimate Container for Active Data — Some details about the internals of C++ 26’s new data structure. How fast is C++26’s std::hive? — Pretty self-explanatory and useful numbers to keep in mind. A Spectral BSSRDF for…

Tap Detection on Arbitrary Shapes with Compose

Detecting whether a user tapped on an arbitrary shape represented by a Path is an unfortunately difficult task on Android. The Path 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. Thankfully, Jetpack Compose a simple way to…

Finger Shadows in Compose

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 RuntimeShader 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’s finger (or stylus/pointing…

Merge Your Computations

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…

Eliminating Array Bounds Checks

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 ArrayIndexOutOfBoundsException when the index is invalid. Here is a simple Kotlin example: 1 fun scaleZ ( values :…

Naming is Hard

Before we dive into today’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. If you have read my previous articles, you should know by now that seemingly small or irrelevant changes can have a large impact on…

The Path Not Taken

In the last post, we saw that benchmarks don’t always measure what we think they measure . Let’s look at another instance of this problem today, starting with this rather simple benchmark: 1 @RunWith ( AndroidJUnit4 :: class ) 2 class DataBenchmark { 3 @get : Rule 4 val benchmarkRule = BenchmarkRule () 5 6 // Generate data in [0..255] 7 private val data = IntArray ( 65 _536 ) { 8 it %…

You Are Going to Need It

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. Let’s imagine you are trying to optimize code, and you notice the use of a value.pow(2f) . One obvious way to optimize this is to replace the…

Optimization, Step by Step

BlurHash 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 “blurry” version of the source image. The way it works remind me of how spherical harmonics are used in 3D rendering engines to efficiently encode irradiance. I recently remembered that I had been meaning to look at the…

A Micro-optimization You Will Never Need

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’s an interesting trick that you should never bother to use, nor worry about. 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):

Down Another Rabbit Hole

Jake Wharton recently caused me to go down yet another silly optimization rabbit hole when he nonchalantly linked to a piece of code used to count the number of digits in a Long during a Slack conversation about Kotlin’s lack of ternary operator. This of course triggered folks like Madis Pink and me to want to optimize it… Counting digits Link to heading The simplest way to count the number…

Down a Rabbit Hole

I recently discussed an optimization that I worked on following Leland ’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: 1 // A rectangle is defined by its left (l), top (t), 2 // right (r), and bottom (b) coordinates 3 data class Rect ( val l : Int ,…

Practical Optimizations at Android Makers 2024

I recently gave a talk called Practical Optimizations at Android Makers 2024 . The talk is focused on some of the low-level optimizations we implemented in Jetpack Compose , their impact on performance, and the programming techniques behind them. You will likely find this talk interesting if you’ve been enjoying the articles about performance and optimizations on this blog. Enjoy!

Readability of Optimized Kotlin Code

Leland 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 nerd sniped me in the process. The problem was to efficiently encode the occupancy of an 8x8 grid represented as a Long (each bit representing a cell in the grid). After coming up with the bit twiddling code that quickly…

Speeding up isBlank()

I was recently optimizing a small part of the Jetpack Compose runtime when I stumbled upon a seemingly harmless API, isBlank() . This API return true if the string it’s called on is empty or consists solely of whitespace characters. But is it truly harmless? Let’s look at the JVM implementation to get a better sense of what it does: 1 public actual fun CharSequence . isBlank ():…

Micro-optimizations in Kotlin — 3

The Kotlin standard library is a wonderful set of APIs, but it sometimes hides… interesting surprises. So today let’s took at the innocent looking minOf() and maxOf() functions. These functions let you perform a min/max on a series of values, instead of just two with the more common min() and max() functions. Both min() and max() are straightforward and simply delegate — on Android and JVM —…

Going Old School

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 cubic Bézier easing curves and when interpolating colors through the OkLab color space. Working on graphics projects taught me that approximations can often be powerful…

A Better Hash Map — 1

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 mutableMapOf() 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…

Micro-optimizations in Kotlin — 2

In the previous post , we saw how we could micro-optimize Int.sign to save a few instructions. We are now going to turn to Float.sign (and by extension Double.sign ). Float.sign returns the sign of single-precision float value as a single-precision float value. While similar to Int.sign , this API must handle a special cases: Not-a-Number ( NaN ). The exact behavior of the API is that it will…

Micro-optimizations in Kotlin — 1

While my work responsibilities do not leave me much time to write code nowadays, I have managed to make a few small contributions to Jetpack Compose in the last few months, mostly focusing on performance. If you are an Android app developer, your performance concerns probably start and stop at a fairly high level 1 . I find working on large scale libraries like Compose fascinating because you need…