Balázs' blog

Posts

Handling forks in threaded code in Ruby

In MRI Ruby, when calling a Process.fork, only the main thread gets copied into the child process, while the other threads will appear as ‘dead’. In my case, it was a Thread::Queue serviced by a Thread worker loop initialized in puma which then forked b/c it was set up in cluster mode, and I saw things not being processed as they should. However, it turns out that this is a documented behavior, and I’m probably not alone getting caught off-guard by this.

What's the time?

I’ve been running some profiling on the PlainApm agent and one of the things that sometimes popped up in the stackprof output were calls to (Date)Time#iso8601. I used them to get an idea of the overall pipeline latency from the moment the event gets collected until it gets written to the DB. It turns out that these calls are indeed quite slow, so depending on the use case, Time.now.to_f or Process.

How Not to Benchmark a Rails App

It starts with “I’m just going to use benchmark/ips and openuri, its just a couple lines of code”. So you copy over config/environments/production.rb to config/environments/benchmark.rb to have the same settings, disable SSL, add a prefix to assets path to avoid interfering w/ development, add a DB configuration for the new env, run RAILS_ENV=benchmark rails db:setup and RAILS_ENV=benchmark rails assets:precompile. Whip up a trivial rake task: require 'benchmark/ips' namespace :traffic do desc "Benchmark the app" task :benchmark do Benchmark.

Ruby Internal Types

While working on PlainAPM’s object allocation tracing callback, I needed a way to determine classes of arbitrary objects returned by rb_tracearg_object. The naive way, calling rb_obj_classname was segfaulting, though, so I decided to handle this type-by-type, and either avoid the problem, or narrow down the scope of the issue, to understand it better. Here are some notes that might save fifteen minutes to a future me, or to someone who’s starting to look into which types of objects are there in Ruby:

DTracing the Ruby GVL

Nate Berkopec posted an interesting question on twitter: Puma office hours: we want to measure what % of the time the global VM lock is held in a Ruby process. anyone got an idea on how to even start to observe that, performantly? #railsconf I thought about using ‘dtrace’ immediately, since I already experimented with adding custom probes to MRI Ruby a few years back. With that I set out to patch MRI to allow for this.

Notes from RubyConf 2017 AU talks

Reinvesting in Ruby by Tim Riley Video Rails was defining the Ruby ecosystem, time to explore other alternatives Introduces dry-rb gems on a blog post example Minimalistic, single-responsibility, composable gems for common tasks dry-validation, dry-monads, dry-matcher - pattern matching Actors in Ruby! Why let Elixir have all the fun by Marcos Matos Video Threads vs. forks (forks heavy - even with CoW optimisations). Forking does not have built-in way to communicate - some form of IPC is required, e.

Ruby tracing part two - rbtrace

In a previous post, I looked at how Linux’s eBPF framework can be used with Ruby. Of course TIMTOWTDI! So, it turns out there’s an excellent gem for Ruby tracing: rbtrace by Aman Gupta, which I encountered a few months ago, in Sam Saffron’s post when I needed to get a heap dump from a Ruby process to track down a memory leak. rbtrace Justin Weiss wrote up a summary with some cool examples of what the gem can do, but in a nutshell:

Ruby tracing part one - BPF

How many times did you need to ssh into production, and see what the Ruby app is actually doing now? How it allocates memory, which syscalls or what user-level functions is it calling? Even with centralized logging, the granularity is less than ideal for observing performance, or even bugs in the wild. What you usually get is an after-the-fact summary of state, maybe requests per second report, maybe an exception and a backtrace.

Printf debugging basics in Ruby

Sometimes, a printf is enough. Although IDEs usually integrate with a debugger and allow you to setup complex breakpoints, the power of printing out statements shouldn’t be underestimated. The learning curve is low and all the required tools are there. No need to install gems, or spend money on an IDE. Let’s look at some printf style tools that’s good to have in your debugging toolbox. We’ll be going from the simplest ones for inspecting objects, logging, going through execution context and looking up definitions of methods.