Skip to content

Instantly share code, notes, and snippets.

@ecaron
Last active August 29, 2015 14:14
Show Gist options
  • Select an option

  • Save ecaron/a03aa1215a22bd86082a to your computer and use it in GitHub Desktop.

Select an option

Save ecaron/a03aa1215a22bd86082a to your computer and use it in GitHub Desktop.
require "optparse"
require "uri"
require "net/http"
###
# This script is taken from http://samsaffron.com/archive/2013/11/13/live-restarts-of-a-supervised-unicorn-process
# It has been modified from the original to:
# 1) Have more intelligent validation of the URL
# 2) Support HTTPS requests
# 3) Colorized output based on type of request
# 4) Gracefully exits upon cntl-c
##
# Taken from http://stackoverflow.com/a/16363159/34340
class String
def green; "\033[32m#{self}\033[0m" end
def bg_green; "\033[42m#{self}\033[0m" end
def bg_red; "\033[41m#{self}\033[0m" end
def bg_yellow; "\033[43m#{self}\033[0m" end
end
$stdout.sync = true
duration = 10
per_second = 10
opts = OptionParser.new do |opts|
opts.banner = "Usage: bench_web [options] url"
opts.on("-t", "--time TIME", OptionParser::DecimalInteger, "Duration to run the test in seconds (default 10)") do |t|
duration = t
end
opts.on("-p", "--per-second REQUESTS", OptionParser::DecimalInteger, "Max number of requests per second (default 10)") do |t|
per_second = t.to_f
end
end
opts.parse!
if ARGV.length != 1
puts opts.banner
puts
exit(1)
end
if ARGV[0] !~ /\A#{URI::regexp(['http', 'https'])}\z/
puts opts.banner
puts
puts "Invalid URL"
puts
exit(1)
end
url = URI.parse(ARGV[0])
GC.disable
finish_time = Time.now + duration
results = []
http = Net::HTTP.new(url.host, url.port)
if url.scheme === 'https'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
request = Net::HTTP::Get.new(url.request_uri)
while (start=Time.now) < finish_time
begin
res = http.request(request)
req_duration = Time.now - start
results << {duration: req_duration, code: res.code, length: res.body.length}
GC.enable
GC.start
GC.disable
padding = (1 / per_second.to_f) - (Time.now - start)
if res.code.to_i >= 200 && res.code.to_i < 300
print ".".green
elsif res.code.to_i < 400
print res.code.bg_green + " "
elsif res.code.to_i < 400
print res.code.bg_yellow + " "
else
print res.code.bg_red + " "
end
if padding > 0
sleep padding
end
rescue Interrupt
finish_time = Time.now
puts "\nExiting..."
end
end
GC.enable
puts
puts "Results"
puts "Total duration: #{duration} second#{duration==1?"":"s"}"
puts "Total requests: #{results.length}"
summary = results.group_by{|r| r[:code]}.map{|code, array| [code, array.count]}.sort{|a,b| a[1] <=> b[1]}
failures = summary.map{|code, count| code == "200" ? 0 : count}.inject(:+)
if failures > 0
puts "Estimated downtime: #{((failures.to_f * (1.to_f / per_second)) * 1000).to_i}ms"
end
puts
puts "By status code: #{summary.map{|code,count| "[#{code}]x#{count} "}.join}"
puts ""
puts "Percentage of the successful requests served within a certain time (ms)"
good_requests = results.find_all{|r| r[:code] == "200"}.map{|r| r[:duration]}.sort
if good_requests.length > 0
[25,50,66,75,80,90,95,98,99,100].map{ |percentile|
time = good_requests[((percentile.to_f / 100.0) * (good_requests.length-1)).to_i]
puts " #{percentile}%\t\t#{(time * 1000).to_i}"
}
end
@ecaron
Copy link
Author

ecaron commented Feb 2, 2015

Run this code like:

ruby bench_web.rb http://example.com

It also supports a -t parameter for defining how long it should run (defaults to 10 seconds), and a -p parameter for the maximum requests per second (defaults to 10)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment