RSSAmplifier

Blog

ivo's awfully random tech blog

where i document my tech hacks, experiments and discoveries

ivoanjo.meRSS feed ↗62 posts

Latest posts

Low-level Ruby observability APIs

When we need to understand what s going on with our application, it s common to ( beyond using puts 😉 ) turn to observability tools: tools such as debuggers, profilers, and monitoring tools. But have you ever wondered how they work? These tools often require access to Ruby internals that regular Ruby libraries or applications don t have (or need). Language runtimes such as the CRuby VM (or the…

Talking Ruby GVL, Scheduling and Performance on the Dead Code podcast

I m pretty happy that I got to go on the Dead Code podcast. In this episode, we discussed how the Ruby Global VM Lock (GVL) got to be and why it s needed, went deep into scheduling how to tweak how much time Ruby gives each thread; how M:N scheduling changes the behavior of threads in Ruby; and how Ruby may need a full scheduler and why. We also discuss how tools such as gvl-tracing can be used to…

native-filenames: Find out where native methods are defined in Ruby

I ve just released the first version of the native-filenames Ruby gem. This gem can be used to probe where a native extension was defined. Here s a quick example of how to use it: [ 1 ] pry(main)> require ' native-filenames ' # Modern versions of bigdecimal use a native extension: [ 2 ] pry(main)> require ' bigdecimal ' [ 3 ] pry(main)> NativeFilenames .filename_for( BigDecimal .singleton_class,…

I wrote another weird ruby gem: direct-bind

I ve written another weird Ruby gem: direct-bind . It solves a very specific problem I keep running into. It s oddly specific, so I may actually be alone in this ;) As I find myself working on Ruby observability tools such as the profiler in the datadog gem , or the "show your Ruby threads in a timeline" gvl-tracing gem or the "build richer stack traces" backtracie gem I often mentally ask: Ok, so…

M:N scheduling and how the (Ruby) global vm lock impacts app performance

A while back I created the gvl-tracing gem as an experiment to help understand what was going on inside Ruby when multiple threads are in use. But Ruby is not standing still! Ruby 3.3 saw the introduction of M:N scheduling (off by default) which is a feature I ve been quite looking forward to. What is M:N scheduling, you ask? It s a new execution strategy for Ruby threads that is similar/borrows…

Building an always-on (Ruby) production profiler

For the past few years, I ve been working at Datadog on a new open-source Ruby profiler. This profiler is shipped as part of the datadog Ruby gem . Why spend all this time and effort on building a new profiler? The key detail is that we want (and need) something that is built to be always-on in production. That translates to having really low overhead in several dimensions, including low cpu…

Backtracie and the quest for prettier Ruby backtraces

A backtrace is one of those Ruby features that is extremely useful, but we never think about it. They re just always there in our time of need be it when an error happens, when exploring our code inside a irb or a debugger, or even when profiling our app. For a while now, I ve been thinking about, and working on, possible improvements for Ruby s backtraces I ve blogged about it [ 1 , 2 ], and even…

Look out! Gotchas of using threads in Ruby

Threads (along with fibers and ractors) are all extremely powerful and useful tools for Ruby developers. Yet, they often seem to be surrounded by this aura of mystery, as if they are something for wizards to employ in their magicks and not for mere mortals to make use of. I recently spoke at EuRuKo 2023 about this topic with the aim of demystifying Ruby threads. You can find the video and slides…

Understanding the Ruby Global VM Lock by observing it

The Global VM Lock (GVL), also known as Global Interpreter Lock (GIL), is an implementation detail of the Ruby VM. At a high-level, it prevents Ruby code across multiple threads from running in parallel (while still allowing concurrency!). The GVL is an extremely important implementation detail, as it can have a big impact on the performance and responsiveness of any Ruby application that uses…

Ruby's unexpected I/O vs CPU unfairness

Recently, while benchmarking a test application, I observed that if I mixed threads doing input/output (such as reading files or network/database requests) and threads doing CPU work, the I/O work would be slowed down massively. It took me a while to realize this was caused by how (and when) Ruby switches between threads. For instance consider querying a web server (here I m using google as an…

Talking Ruby Performance Tooling at the Ruby Rogues podcast

I was recently invited to the Ruby Rogues podcast for a second time. We talked about the pitfalls of Ruby performance, when and why you should profile, and the tools I ve been working on to better explore and optimize Ruby performance. These include: Tracing the Ruby Global VM Lock using the gvl-tracing gem The Datadog Continuous Profiler for Ruby included in the ddtrace gem A gem for…

Ruby reuses native OS threads after Ruby Threads die

Since Ruby 1.9, each Ruby Thread gets executed on its own native operating system thread. But, as a performance optimization, Ruby will try to reuse native operating system threads if it can. When a Ruby Thread terminates, Ruby will not immediately terminate the operating system thread that was hosting it. Instead, it will keep it around for a few seconds, and if in that time period the…

Hunting production memory leaks at RubyKaigi 2022

Existing Ruby tooling is quite helpful when investigating memory leaks if and when we can reproduce them on our development machine or staging environment. But what about those cases when the memory leak only really shows up in Production? Perhaps over a long time period? Me and @KJ Tsanaktsidis recently presented a talk at RubyKaigi 2022 about two new Ruby gems ruby_memprofiler_pprof and…

Tracing Ruby's (Global) VM Lock

( 🇯🇵 Japanese translation thanks to @hachi8833 ) ( 🇰🇷 Korean translation thanks to @heka1024 ) I recently created a new Ruby gem: the gvl-tracing gem . This gem can be used to generate a visualization of what your Ruby threads are up to: Click Open Example 1 to explore this example. Alternatively, download example1.json.gz and open it with the Perfetto UI . Example code is from example1.rb .…

Talking Ruby Ractors and Concurrency at the Ruby Rogues podcast

I was recently invited to the Ruby Rogues podcast to talk about Ractors (the new Ruby concurrency primitive added in Ruby 3), as well as Ruby concurrency in general. You can download the episode as an mp3 or listen to it online at https://topenddevs.com/podcasts/ruby-rogues/ractors-ft-ivo-anjo-ruby-527 . As usual, all feedback is welcome! Get in touch if you d like to talk about Ractors and Ruby…

The unexpected cost of Ruby's NoMethodError exception

💡 A fix for this performance gotcha has been merged for Ruby 3.3! See https://github.com/ruby/ruby/pull/6950 and https://bugs.ruby-lang.org/issues/18285 for details! The NoMethodError exception is how Ruby signals that the code tried to call a method that does not exist. class Example end Example .new.foo # => NoMethodError: undefined method `foo' for #<Example:0x00005636879ce398> Now, raising…

Sunday Lol: Embedding images in commit logs

Recently, I discovered the notcurses library, the latest in a long line of weird ways of abusing a terminal emulator. It provides a tool called ncplayer which can be used to preview images and videos from the terminal. And then I decided to see if I could pipe its result into git , and turn it into a commit message. Turns out that it works! (P.s.: You ll need a recent version of ncplayer ) Of…

Ruby Ractor Experiments: Safe async communication

(This post is also available in 🇯🇵 Japanese thanks to @hachi8833 .) Ractors ( api documentation , design documentation ) are a new concurrency abstraction for Ruby 3.0 inspired on the actor model. From the point of view of a Ractor that wants to send some information to another, communication can either be: asynchrous (or non-blocking ): a Ractor can send information to another using Ractor#send…

Looking into Array memory usage in Ruby

What s the memory impact of keeping a number of objects in a Ruby array? To answer this question, I decided to look into how exactly arrays are internally represented by Ruby. Note that because we ll be looking at the Ruby internals, these results may and do change between Ruby versions; Nevertheless, the techniques used to measure overheads should be reusable for newer Ruby versions. Note also…

What I've been reading: December+January 2021 Edition

This blog post is a continuation of my ongoing experiment with collecting and summing up the best technical (with a bit of non-technical) stuff I ve read and watched recently. (P.s.: You can now receive my blog as a newsletter! ) Happy reading! 1. Painting a Selfie Girl, with Maths (YouTube Video): Inigo Quilez is a master computer graphics artist, and in this video he paints a picture of a girl…

What I've been reading: November 2020 Edition

This blog post is a continuation of my ongoing experiment with collecting and summing up the best technical (with a bit of non-technical) stuff I ve read and watched this past month. I m still experimenting with the format, so feedback is definitely welcome. (P.s.: You can now subscribe to my newsletter too! ) This month I ve gone a bit down the rabbit hole of the GDC (Game Developers Conference)…

Creating a newsletter!

I ve been listening to Company of One (which I do recommend) and that got me thinking that it may be cool to allow readers to subscribe to the blog via e-mail. So I ve decided to setup a newsletter! You can sign up by clicking here . Or, if you re a RSS feeds person, you can subscribe via https://ivoanjo.me/feed.xml as well. That s it for today! :)

What I've been reading: October 2020 Edition

A few years ago, I acquired the habit of regularly collecting and sharing with my work colleagues the highlights of what I was reading from week to week. As I m preparing to start working at a new company soon, I ve been wondering if it would be useful to share this with a wider audience, and how I would do it. I ve decided that the easiest way to start is to use this blog. I m not sure how often…

Better backtraces in Ruby using TracePoint

In a previous blog post Ruby Experiment: Include class names in backtraces I shared the beginning of my experiments into improving Ruby backtraces. That got me thinking of a few things: What information would I want to show in backtraces? What format would I display that information in? Is it possible (and reasonable?) to extract the needed information during backtrace collection? To allow me to…

Snippet: Getting a dynamically-generated method name on the Java stack using Javassist

Have you ever found yourself in need to include a certain string or method name on your stack traces, for debugging or metrics? The following snippet shows how easy that can be done with the javassist library. The snippet is written in Kotlin, but can be easily converted into Java or any other JVM language. For the example, we want to see "iLikePie" as one of our method names. Here s how it looks:…

Ruby Experiment: Include class names in backtraces

As a weekend experiment, I decided to write a few prototypes to answer the following question: Is it possible to improve Ruby backtraces by including the class where a given method was defined, similar to how Java and other languages do it? Turns out that it can be done with a handful of changes in the implementation of backtraces:…

Quick tip: Unsafe concurrent Ruby hash access

On my talk on spotting unsafe concurrent ruby patterns I documented a few common Ruby code patterns that may trigger issues when executed concurrently across multiple threads. I just bumped into another such example! This specific one seems not to affect MRI Ruby (aka the default Ruby implementation), but I was able to clearly trigger it on both JRuby and TruffleRuby using some_hash[key] = value…

Kotlin Hack: Transparently replace class with interface

While working on an experiment using Kotlin recently, I ran into the following issue: I had a class let s call it FooInteractor that I wanted to be able to replace with an implementation that did nothing in some cases. I had other classes that referenced it, which I did not want to have to change. I also had several places where FooInteractor was instanced directly, via FooInteractor( ) which I…

Kotlin for Rubyists

Although I ve never seen Ruby cited as an inspiration for Kotlin, ever since I first ran into it, I couldn t but notice how closely it resembles Ruby. Kotlin shares many of Ruby s niceties: you can do a lot with a very small amount of code; its standard library includes many useful tools that help you express your intent clearly; it can be used to create beautiful domain specific languages; it has…

Spotting unsafe Ruby patterns - Talk recording

Writing Ruby code that uses multiple threads is a great way to get better performance and to take advantage of modern laptops and servers. It can also be quite daunting due to the often-feared “concurrency bugs”. In this talk, recorded at the Fullstack LX Ruby meetup, I introduce a number of pitfalls to watch out for, presenting correct (and fast!) alternatives for each. Slide deck:

Writing to a Java TreeMap concurrently can lead to an infinite loop during reads

The java.util.TreeMap documentation warns that the underlying implementation for this Map is not synchronized and thus it is not thread-safe. But have you ever wondered what happens if you ignore that warning and you write an application that concurrently writes to the map from different threads? Intuitively, I d probably expect some entries to be lost, or to sometimes get a NullPointerException .…

TIL: Java hides lambda frames in stack traces

While playing around with Java stack traces today, I noticed something that I had never noticed before: lambda frames do not show up in stack traces! For instance, consider the following pre-Java 8 example: public class VisibleLambda { public static void main( String [] args) { foo( new Runnable () { public void run() { bar(); } }); } static void foo( Runnable lambda) { lambda.run(); } static void…

My thoughts on, and how I approach code reviews

A few weeks back while I was having very interesting conversations with colleagues about code reviews I sat down and wrote some topics on how (and why) I take them on. There are already a lot of awesome articles online on what you should be on the look out when reviewing code such as this great one by thoughtbot but my objective on this exercise is to focus on improving the code reviews…

Is this ok…​? Or, spotting unsafe concurrent Ruby patterns

The past weekend I had the enormous pleasure to speak at the Ruby on Ice 2018 conference in Tegernsee, Germany. Figure 1. All Ruby conferences should have a view like this 😁 I decided to give the talk I wish I had seen about four years ago before I joined Talkdesk, on a number of gotchas and common mistakes one can do when working with Ruby and concurrency. You can find the video for this talk,…

Lightning Talk - Warm-Blanket: Goodbye crappy after-boot performance

Back in September, at the EuRuKo 2017 Ruby conference, I decided to submit a lightning talk on the warm-blanket gem. If you re curious for a bite-sized introduction and motivation on why you should care about it, you can find the presentation and slides below 😁

persistent-💎: a new ruby gem for beautiful immutable data structures

After a few weeks of work, I ve just released version 1.0 of my new gem: persistent-💎 ! The objective of this gem is to make programming with immutable data structures in Ruby as joyful and frictionless as using the built-in Array and Hash classes. So easy, in fact, that using immutable structures becomes the norm, rather than the exception. Ruby has no immutable data structures in the standard…

asciidoc: an awesome markdown alternative

Yesterday while reading through the twitters, I came upon a reference to a markup format called AsciiDoc which I had never heard about before. Oh wow. Just read up on asciidoc and asciidoctor and woooow. This just made my life. Mind. Blown. &mdash; Ivo Anjo (@KnuX) October 21, 2017 I started reading about both AsciiDoc and the AsciiDoctor tool and they completely blew my mind, so I immediately…

Why I always use attr_reader to access instance variables

Ruby’s attr_reader method can be used to automatically generate a “getter” for a given instance variable. In simple terms, doing attr_reader :engine is the same as writing def engine @engine end I’ve adopted a programming style where I always try to use attr_reader to access instance variables (or getters , if you prefer to call them that 😁). I’ve been asked about the reasons that led me to adopt…

Introducing the WarmBlanket gem

Optimizing runtimes are a very hot topic for Ruby development right now: Historically, both JRuby and Rubinius dynamically optimized Ruby code as they ran it, but soon they will soon be joined by the likes of TruffleRuby , ruby+omr , mjit , llrb and topaz . Furthermore, it’s common for Ruby web services to lazily load classes and open connections to dependent systems. This allows for faster system…

Ninjas’ guide to getting started with VisualVM

VisualVM is a free Java/JVM tool that ships with most Oracle JDK/OpenJDK installs (if you’ve used Erlang’s observer previously, it’s a similar tool). It can be used to both profile and debug applications running on the JVM—including Java, JRuby, and many others. I’ve mentioned it several times before on this blog as part of my JRuby voyages, as it’s my go-to tool to start investigating any kind of…

adopting tls

Just a quick note: If you can read this, it means this blog has finally left the internet stone age and is now being successfully served using https/tls via amazon cloudfront. Thanks to Oliver Pattison for his great guide on how to do so. Join us! We have cookies! P.s.: Next step is getting HSTS and other recommended security headers going .

rubies: a look at ruby's shiny future

I m a huge fan of the Ruby programming language, but in terms of implementation Ruby still lags behind other dynamic languages such as Javascript, which have powerful optimizing runtimes capable of delivering blazing performance. Yet I think Ruby in 2017 is closer to that goal than ever: it seems like everyone in the Ruby runtime game is looking at techniques such as JIT compilation and…

quickies: heroku exec and deploying jruby

heroku exec! A few months back on my “another round of jruby goodness” post I wrote about a heroku buildpack that, combined with a reverse proxy like ngrok would allow connecting to a heroku node, and that could even be used to open up Java VisualVM and connect to it, live. This week I was pleasantly surprised to see heroku introduce this functionality out of the box with the heroku exec add-on.…

why you should be using jruby in production

On February 23rd I gave a presentation at the Fullstack LX meetup detailing why you should use JRuby and how it helped my team at Talkdesk identify complex bugs and hit our performance goals. You can find the presentation and slides below, enjoy! --> Update : Video went down and I did not have a copy 😢. I’ll update this if I can restore a copy. (Or you can just invite me over to your meetup to…

benchmarking jruby invokedynamic with a production application

As you read JRuby blog posts and other resources around the web, you may find references to JRuby’s compile.invokedynamic option, that as of 9.1.7.0 continues to ship turned off by default. So, why is it off? I asked the JRuby developers and here’s what they had to say about it: @KnuX @tom_enebo Primarily startup and warm-up time: both increase. It has improved somewhat in Java 8. &mdash; Charles…

pry-debugger-jruby gem now on rubygems!

As a followup from my psa: you can now debug with pry on jruby I have finally uploaded my fork of pry-debugger — the pry-debugger-jruby gem — onto rubygems ! The original post has been updated, but as a reminder, using it is as simple as adding gem ' pry-debugger-jruby ' to your gemfile, and then starting pry on JRuby. Feedback and issues are very welcome! :)

weekend hacking: enviado gem

On friday I started reading up on lyft’s recently-announced envoy proxy/communication bus/general awesome piece of kit. Envoy can be used in many different ways : As a reverse proxy in front of some service As a service-to-service communication provider (including service discovery) As a local proxy to some remote service This last configuration piqued my interest, as I have been interested in…

jruby's Charles Nutter on the jvm as a language platform

I just finished listening to a recent episode of the Software Engineering Radio podcast : SE-Radio Episode 266: Charles Nutter on the JVM as a Language Platform In this podcast Charles Nutter—one of JRuby’s maintainers—discusses the relationship between non-Java languages that run on the JVM and Java/the Java platform; some history on JRuby and on the recently-released 9k version, and even touches…

peek and pick at mri's heap, part 2

In part 1 of this overview I looked at a gui tool to monitor and analyze a live application’s memory usage. This time, let’s turn to a command-line tools that can look at things after-the-fact: the heapy gem . Ruby version 2.1 introduced the ability to take heap memory dumps using the ObjectSpace module . To do so, just add: require ' objspace ' ObjectSpace .trace_object_allocations_start …to your…

finding dead ruby code with debride

My recent web adventures led me to the debride gem: debride statically analyzes your ruby code, trying to find methods which are never referenced. As ruby is a very dynamic language, you’ll get some amount of false positives, but I was successful in finding several unused methods on several of our years-old codebases at Talkdesk. The output of running debride is a list of methods (and which class…