/
benchmark.rb
executable file
·129 lines (96 loc) · 2.84 KB
/
benchmark.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env ruby
# ---------------------------------------------------------
# Configuration
seconds = 30
# total_requests = 400
CONCURRENCY_LEVELS = [1, 10, 20, 30, 40, 50]
if !defined?(seconds) && !defined?(total_requests)
exit "You must either define the duration of the test or the number of requests"
end
# ---------------------------------------------------------
# Benchmarking tools
#
# Apache Bench:
# stop after 400 requests:
# ab -c 30 -n 400
# stop after 30 seconds:
# ab -c 30 -t 30
#
@base_cmd = "ab -r -c %{concurrency_level}"
if defined?(seconds) && seconds
@base_cmd << " -t #{seconds}"
elsif defined?(total_requests) && total_requests
@base_cmd << " -n #{total_requests}"
end
@base_cmd << " %{url} 2> /dev/null"
# ---------------------------------------------------------
def blank?(str)
str.nil? || str.strip.empty?
end
# ---------------------------------------------------------
# Alternate CPU intensive and IO intesive jobs, otherwise
# my CPU will catch fire
#
ENDPOINTS = [
"/fibonacci/32", # 0.34 seconds on average on my machine
"/pause/2",
"/template-render",
"/network-io",
"/template-render-no-response",
"/network-io-and-render",
"/pause-and-render/2"
]
BASE_URL = "http://127.0.0.1:3000"
require 'uri'
def url_for(path)
URI.join(BASE_URL, path).to_s
end
# ---------------------------------------------------------
require 'csv'
output_file_path = File.expand_path("../../results/bench_results.csv", __FILE__)
@out_file = File.open(output_file_path, "w")
# def log(str)
# @out_file.puts str
# @out_file.puts "\n"
# end
def write_row(target, type, results)
str = CSV.generate_line([target, type, *results])
@out_file.puts str
end
REQ_P_S_REGEX = %r{Requests per second\:\s+(\d+\.\d*) \[\#\/sec\] \(mean\)}
T_P_REQ_REGEX = %r{Time per request\:\s+(\d+\.\d*) \[ms\] \(mean\)}
def extract_data(str)
return nil if blank?(str)
req_p_s = REQ_P_S_REGEX.match(str)&.[](1).to_s
t_p_req = T_P_REQ_REGEX.match(str)&.[](1).to_s
[req_p_s, t_p_req]
end
def run_test(conc_requests, target)
cmd = sprintf(@base_cmd, concurrency_level: conc_requests, url: target)
print cmd
output = `#{cmd}`
end
def maybe_cooldown(path, seconds)
if path =~ /fibonacci|render/
puts "cooling down for #{seconds}s..."
sleep seconds
end
end
write_row("path", "metric", CONCURRENCY_LEVELS)
ENDPOINTS.each do |path|
target = url_for(path)
req_p_s_results = []
resp_time_results = []
CONCURRENCY_LEVELS.each do |conc_req|
results = run_test(conc_req, target)
req_p_s, resp_time = extract_data(results)
puts " | req/s: #{req_p_s}, resp ms: #{resp_time}"
req_p_s_results << req_p_s
resp_time_results << resp_time
maybe_cooldown(path, 5)
end
write_row(path, "req/s", req_p_s_results)
write_row(path, "resp_time", resp_time_results)
maybe_cooldown(path, 20)
end
@out_file.close