mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-07 07:10:10 +09:00
659f95748a
* Preload only uncached messages and reduce rendering overhead * Keep benchmark summaries without raw JSON results * Use Ruby benchmark drivers and keep generated results out of the repo
75 lines
3.8 KiB
Ruby
75 lines
3.8 KiB
Ruby
#!/usr/bin/env ruby
|
|
# Compare warm production Puma/Redis requests using isolated seeded containers.
|
|
require "socket"
|
|
require_relative "support"
|
|
require_relative "http_client"
|
|
|
|
include BenchmarkSupport
|
|
options = parse_options("Compare HTTP throughput with Ruby keep-alive clients; every response must be HTTP 200.",
|
|
duration: 3.0, paths: "room,messages,sidebar,search", concurrencies: "1,16", client_cpus: "12-15",
|
|
output: File.join(WORK, "results/http"))
|
|
labels = JSON.parse(File.read(File.join(options[:seed], "labels.json")))
|
|
paths = {
|
|
"room" => "/rooms/#{labels.fetch('rooms.watercooler')}",
|
|
"messages" => "/rooms/#{labels.fetch('rooms.watercooler')}/messages?before=#{labels.fetch('messages.busy_060')}",
|
|
"sidebar" => "/users/me/sidebar", "search" => "/searches?q=coffee"
|
|
}.slice(*options[:paths].split(","))
|
|
abort "--paths must select room,messages,sidebar,search" unless paths.size == options[:paths].split(",").size && !paths.empty?
|
|
concurrencies = options[:concurrencies].split(",").map { |value| Integer(value) }
|
|
abort "--duration and --concurrencies must be positive" unless options[:duration].positive? && !concurrencies.empty? && concurrencies.all?(&:positive?)
|
|
run("taskset", "-pc", options[:client_cpus], Process.pid.to_s)
|
|
work = File.join(WORK, "http")
|
|
assets = prepare_assets(options[:image])
|
|
network = "cf-ruby-bench-#{Process.pid}"
|
|
redis = "#{network}-redis"
|
|
app = "#{network}-app"
|
|
|
|
begin
|
|
run("docker", "network", "create", network)
|
|
run("docker", "run", "-d", "--name", redis, "--network", network, "redis:7-alpine")
|
|
options[:rounds].times do |iteration|
|
|
sides = iteration.even? ? %w[before after] : %w[after before]
|
|
sides.each do |side|
|
|
remove_container(app)
|
|
data = File.join(work, "data")
|
|
prepare_storage(options[:seed], File.join(data, "storage"))
|
|
FileUtils.mkdir_p([ File.join(data, "tmp/pids"), File.join(data, "log") ])
|
|
run("docker", "exec", redis, "redis-cli", "FLUSHALL")
|
|
port = TCPServer.open("127.0.0.1", 0) { |socket| socket.addr[1] }
|
|
client = BenchmarkHTTPClient.new("http://127.0.0.1:#{port}")
|
|
source = side == "before" ? options[:baseline] : ROOT
|
|
command = [ "docker", "run", "-d", "--name", app, "--entrypoint", "", "--network", network,
|
|
"--cpuset-cpus", options[:cpus], "-p", "127.0.0.1:#{port}:3000" ]
|
|
command.concat mounts(source => "/rails", File.join(data, "storage") => "/rails/storage",
|
|
File.join(data, "tmp") => "/rails/tmp", File.join(data, "log") => "/rails/log", assets => "/rails/public/assets")
|
|
command.concat environment(RAILS_ENV: "production", SECRET_KEY_BASE: "isolated-benchmark-fixture-key", DISABLE_SSL: true,
|
|
SKIP_TELEMETRY: true, RAILS_LOG_LEVEL: "fatal", WEB_CONCURRENCY: 1, JOB_CONCURRENCY: 1, RAILS_MAX_THREADS: 5,
|
|
REDIS_URL: "redis://#{redis}:6379/0")
|
|
command.concat [ options[:image], "bundle", "exec", "puma", "-C", "config/puma.rb" ]
|
|
run(*command)
|
|
deadline = clock + 45
|
|
until client.ready?
|
|
if clock > deadline
|
|
File.write(File.join(work, "server.log"), run("docker", "logs", app))
|
|
raise "server did not become ready; see #{work}/server.log"
|
|
end
|
|
sleep 0.1
|
|
end
|
|
cookie = client.login(labels)
|
|
results = {}
|
|
paths.each do |name, path|
|
|
client.measure(path, cookie, concurrency: 1, duration: 3)
|
|
concurrencies.each do |concurrency|
|
|
results["#{name}_#{concurrency}"] = client.measure(path, cookie, concurrency: concurrency, duration: options[:duration])
|
|
end
|
|
end
|
|
write_json(File.join(options[:output], "#{side}-#{iteration + 1}.json"), results)
|
|
puts "#{iteration + 1}/#{options[:rounds]}: #{side}"
|
|
end
|
|
end
|
|
ensure
|
|
remove_container(app)
|
|
remove_container(redis)
|
|
Open3.capture3("docker", "network", "rm", network)
|
|
end
|