agentic examples

The Require Cost Report

The Require Cost Report: `require` is a purchase - memory, objects, and boot time, paid again by every process you fork and every worker you scale. This measures what the gem and each major dependency cost AT REQUIRE TIME, each in a clean subprocess so nobody's cost gets billed to a neighbor's account.

Scheduling & Concurrency Round 12 Richard Schneeman exit 0

source on github

bundle exec ruby examples/require_cost.rb

a real captured run

REQUIRE COST REPORT (each row measured in a pristine child process)

  require                             RSS        objects       time
  json (stdlib)                     0.2MB           3853       24ms
  zeitwerk                          0.2MB           8955       30ms  #
  async                             3.1MB          37177      167ms  ######
  dry-schema                        3.8MB          64274      142ms  ########
  agentic (require only)            0.4MB          13586       42ms  #
  agentic + first real touch        6.7MB         103091      213ms  #############

  the bill, read like a Heroku support ticket - and it's a plot
  twist: `require "agentic"` costs 0.4MB / 42ms, nearly FREE,
  because Zeitwerk (the round-1 cleanup) defers every constant.
  the first real touch is where the bill lands: 6.7MB and 213ms,
  as async and dry-schema come in through the autoloader. deferred
  is not free - it's a bill that arrives during your first
  request instead of your boot, which is either exactly what you
  want (CLI tools, tiny scripts pay only for what they touch) or
  exactly what you don't (a web worker's first request eats the
  latency). the moves this report funds: eager_load in servers +
  preload_app (pay once, share copy-on-write), stay lazy in CLIs,
  and run this script in CI so a new dependency's bill arrives in
  the PR that adds it - not in the invoice at month's end.

source

# frozen_string_literal: true

# The Require Cost Report: `require` is a purchase - memory, objects,
# and boot time, paid again by every process you fork and every
# worker you scale. This measures what the gem and each major
# dependency cost AT REQUIRE TIME, each in a clean subprocess so
# nobody's cost gets billed to a neighbor's account.
#
#   bundle exec ruby examples/require_cost.rb
#
# Runs offline; each row is an isolated child process.

require class="s">"open3"
require class="s">"rbconfig"

RUBY = RbConfig.ruby
LIB = File.expand_path(class="s">"../lib", __dir__)

# Measure inside a pristine child: RSS and allocated objects, before
# and after the require - so each row is that require's WHOLE bill,
# transitive dependencies included
PROBE = <<~'RUBY'
  def rss_kb = File.read(class="s">"/proc/self/status")[/VmRSS:\s+(\d+)/, 1].to_i
  target, touch = ARGV
  objects_before = GC.stat(class="y">:total_allocated_objects)
  rss_before = rss_kb
  t0 = Process.clock_gettime(Process:class="y">:CLOCK_MONOTONIC)
  require target
  eval(touch) if touch && !touch.empty? # standard:disable Security/Eval
  ms = (Process.clock_gettime(Process:class="y">:CLOCK_MONOTONIC) - t0) * 1000
  puts [rss_kb - rss_before, GC.stat(class="y">:total_allocated_objects) - objects_before, ms.round(1)].join(class="s">",")
RUBY

def cost_of(target, touch = class="s">"")
  out, status = Open3.capture2(RUBY, class="s">"-I", LIB, class="s">"-e", PROBE, target, touch)
  raise class="s">"probe failed for #{target}" unless status.success?

  rss_kb, objects, ms = out.strip.split(class="s">",")
  {rss_mb: rss_kb.to_f / 1024, objects: objects.to_i, ms: ms.to_f}
end

TARGETS = {
  class="s">"json (stdlib)" => [class="s">"json"],
  class="s">"zeitwerk" => [class="s">"zeitwerk"],
  class="s">"async" => [class="s">"async"],
  class="s">"dry-schema" => [class="s">"dry/schema"],
  class="s">"agentic (require only)" => [class="s">"agentic"],
  class="s">"agentic + first real touch" => [class="s">"agentic",
    class="s">"Agentic:class="y">:PlanOrchestrator.new; Agentic:class="y">:CapabilityValidator"]
}.freeze

puts class="s">"REQUIRE COST REPORT (each row measured in a pristine child process)"
puts
puts format(class="s">"  %-28s %10s %14s %10s", class="s">"require", class="s">"RSS", class="s">"objects", class="s">"time")
rows = TARGETS.transform_values { |target, touch| cost_of(target, touch || class="s">"") }
rows.each do |name, cost|
  puts format(class="s">"  %-28s %8.1fMB %14d %8.0fms  %s",
    name, cost[class="y">:rss_mb], cost[class="y">:objects], cost[class="y">:ms], class="s">"#" * (cost[class="y">:rss_mb] * 2).round)
end

bare = rows[class="s">"agentic (require only)"]
touched = rows[class="s">"agentic + first real touch"]

puts
puts class="s">"  the bill, read like a Heroku support ticket - and it's a plot"
puts format(class="s">"  twist: `require \"agentic\class="s">"` costs %.1fMB / %dms, nearly FREE,", bare[class="y">:rss_mb], bare[class="y">:ms])
puts class="s">"  because Zeitwerk (the round-1 cleanup) defers every constant."
puts format(class="s">"  the first real touch is where the bill lands: %.1fMB and %dms,", touched[class="y">:rss_mb], touched[class="y">:ms])
puts class="s">"  as async and dry-schema come in through the autoloader. deferred"
puts class="s">"  is not free - it's a bill that arrives during your first"
puts class="s">"  request instead of your boot, which is either exactly what you"
puts class="s">"  want (CLI tools, tiny scripts pay only for what they touch) or"
puts class="s">"  exactly what you don't (a web worker's first request eats the"
puts class="s">"  latency). the moves this report funds: eager_load in servers +"
puts class="s">"  preload_app (pay once, share copy-on-write), stay lazy in CLIs,"
puts class="s">"  and run this script in CI so a new dependency's bill arrives in"
puts class="s">"  the PR that adds it - not in the invoice at month's end."