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…
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…
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 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…
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…
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…
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…
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…
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…
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…
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…
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…
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…
( 🇯🇵 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 .…
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…
💡 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…
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…
(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…
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…
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…
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)…
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! :)
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…
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…
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:…
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:…
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…
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…
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…
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:
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 .…
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…
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…
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,…
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 😁
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…
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. — 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…
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…
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…
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…
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 .
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…
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.…
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…
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. — Charles…
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! :)
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…
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…
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…
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…