xref: /aosp_15_r20/external/grpc-grpc/src/ruby/stress/stress_client.rb (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/usr/bin/env ruby
2*cc02d7e2SAndroid Build Coastguard Worker
3*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2016 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker#
5*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker#
9*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker#
11*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker
17*cc02d7e2SAndroid Build Coastguard Workerrequire 'optparse'
18*cc02d7e2SAndroid Build Coastguard Workerrequire 'thread'
19*cc02d7e2SAndroid Build Coastguard Workerrequire_relative '../pb/test/client'
20*cc02d7e2SAndroid Build Coastguard Workerrequire_relative './metrics_server'
21*cc02d7e2SAndroid Build Coastguard Workerrequire_relative '../lib/grpc'
22*cc02d7e2SAndroid Build Coastguard Worker
23*cc02d7e2SAndroid Build Coastguard Workerclass QpsGauge < Gauge
24*cc02d7e2SAndroid Build Coastguard Worker  @query_count
25*cc02d7e2SAndroid Build Coastguard Worker  @query_mutex
26*cc02d7e2SAndroid Build Coastguard Worker  @start_time
27*cc02d7e2SAndroid Build Coastguard Worker
28*cc02d7e2SAndroid Build Coastguard Worker  def initialize
29*cc02d7e2SAndroid Build Coastguard Worker    @query_count = 0
30*cc02d7e2SAndroid Build Coastguard Worker    @query_mutex = Mutex.new
31*cc02d7e2SAndroid Build Coastguard Worker    @start_time = Time.now
32*cc02d7e2SAndroid Build Coastguard Worker  end
33*cc02d7e2SAndroid Build Coastguard Worker
34*cc02d7e2SAndroid Build Coastguard Worker  def increment_queries
35*cc02d7e2SAndroid Build Coastguard Worker    @query_mutex.synchronize { @query_count += 1}
36*cc02d7e2SAndroid Build Coastguard Worker  end
37*cc02d7e2SAndroid Build Coastguard Worker
38*cc02d7e2SAndroid Build Coastguard Worker  def get_name
39*cc02d7e2SAndroid Build Coastguard Worker    'qps'
40*cc02d7e2SAndroid Build Coastguard Worker  end
41*cc02d7e2SAndroid Build Coastguard Worker
42*cc02d7e2SAndroid Build Coastguard Worker  def get_type
43*cc02d7e2SAndroid Build Coastguard Worker    'long'
44*cc02d7e2SAndroid Build Coastguard Worker  end
45*cc02d7e2SAndroid Build Coastguard Worker
46*cc02d7e2SAndroid Build Coastguard Worker  def get_value
47*cc02d7e2SAndroid Build Coastguard Worker    (@query_mutex.synchronize { @query_count / (Time.now - @start_time) }).to_i
48*cc02d7e2SAndroid Build Coastguard Worker  end
49*cc02d7e2SAndroid Build Coastguard Workerend
50*cc02d7e2SAndroid Build Coastguard Worker
51*cc02d7e2SAndroid Build Coastguard Workerdef start_metrics_server(port)
52*cc02d7e2SAndroid Build Coastguard Worker  host = "0.0.0.0:#{port}"
53*cc02d7e2SAndroid Build Coastguard Worker  server = GRPC::RpcServer.new
54*cc02d7e2SAndroid Build Coastguard Worker  server.add_http2_port(host, :this_port_is_insecure)
55*cc02d7e2SAndroid Build Coastguard Worker  service = MetricsServiceImpl.new
56*cc02d7e2SAndroid Build Coastguard Worker  server.handle(service)
57*cc02d7e2SAndroid Build Coastguard Worker  server_thread = Thread.new { server.run_till_terminated }
58*cc02d7e2SAndroid Build Coastguard Worker  [server, service, server_thread]
59*cc02d7e2SAndroid Build Coastguard Workerend
60*cc02d7e2SAndroid Build Coastguard Worker
61*cc02d7e2SAndroid Build Coastguard WorkerStressArgs = Struct.new(:server_addresses, :test_cases, :duration,
62*cc02d7e2SAndroid Build Coastguard Worker                        :channels_per_server, :concurrent_calls, :metrics_port)
63*cc02d7e2SAndroid Build Coastguard Worker
64*cc02d7e2SAndroid Build Coastguard Workerdef start(stress_args)
65*cc02d7e2SAndroid Build Coastguard Worker  running = true
66*cc02d7e2SAndroid Build Coastguard Worker  threads = []
67*cc02d7e2SAndroid Build Coastguard Worker  qps_gauge = QpsGauge.new
68*cc02d7e2SAndroid Build Coastguard Worker  metrics_server, metrics_service, metrics_thread =
69*cc02d7e2SAndroid Build Coastguard Worker    start_metrics_server(stress_args.metrics_port)
70*cc02d7e2SAndroid Build Coastguard Worker  metrics_service.register_gauge(qps_gauge)
71*cc02d7e2SAndroid Build Coastguard Worker  stress_args.server_addresses.each do |address|
72*cc02d7e2SAndroid Build Coastguard Worker    stress_args.channels_per_server.times do
73*cc02d7e2SAndroid Build Coastguard Worker      client_args = Args.new
74*cc02d7e2SAndroid Build Coastguard Worker      client_args.host, client_args.port = address.split(':')
75*cc02d7e2SAndroid Build Coastguard Worker      client_args.secure = false
76*cc02d7e2SAndroid Build Coastguard Worker      client_args.test_case = ''
77*cc02d7e2SAndroid Build Coastguard Worker      stub = create_stub(client_args)
78*cc02d7e2SAndroid Build Coastguard Worker      named_tests = NamedTests.new(stub, client_args)
79*cc02d7e2SAndroid Build Coastguard Worker      stress_args.concurrent_calls.times do
80*cc02d7e2SAndroid Build Coastguard Worker        threads << Thread.new do
81*cc02d7e2SAndroid Build Coastguard Worker          while running
82*cc02d7e2SAndroid Build Coastguard Worker            named_tests.method(stress_args.test_cases.sample).call
83*cc02d7e2SAndroid Build Coastguard Worker            qps_gauge.increment_queries
84*cc02d7e2SAndroid Build Coastguard Worker          end
85*cc02d7e2SAndroid Build Coastguard Worker        end
86*cc02d7e2SAndroid Build Coastguard Worker      end
87*cc02d7e2SAndroid Build Coastguard Worker    end
88*cc02d7e2SAndroid Build Coastguard Worker  end
89*cc02d7e2SAndroid Build Coastguard Worker  if stress_args.duration >= 0
90*cc02d7e2SAndroid Build Coastguard Worker    sleep stress_args.duration
91*cc02d7e2SAndroid Build Coastguard Worker    running = false
92*cc02d7e2SAndroid Build Coastguard Worker    metrics_server.stop
93*cc02d7e2SAndroid Build Coastguard Worker    p "QPS: #{qps_gauge.get_value}"
94*cc02d7e2SAndroid Build Coastguard Worker    threads.each { |thd| thd.join; }
95*cc02d7e2SAndroid Build Coastguard Worker  end
96*cc02d7e2SAndroid Build Coastguard Worker  metrics_thread.join
97*cc02d7e2SAndroid Build Coastguard Workerend
98*cc02d7e2SAndroid Build Coastguard Worker
99*cc02d7e2SAndroid Build Coastguard Workerdef parse_stress_args
100*cc02d7e2SAndroid Build Coastguard Worker  stress_args = StressArgs.new
101*cc02d7e2SAndroid Build Coastguard Worker  stress_args.server_addresses = ['localhost:8080']
102*cc02d7e2SAndroid Build Coastguard Worker  stress_args.test_cases = []
103*cc02d7e2SAndroid Build Coastguard Worker  stress_args.duration = -1
104*cc02d7e2SAndroid Build Coastguard Worker  stress_args.channels_per_server = 1
105*cc02d7e2SAndroid Build Coastguard Worker  stress_args.concurrent_calls = 1
106*cc02d7e2SAndroid Build Coastguard Worker  stress_args.metrics_port = '8081'
107*cc02d7e2SAndroid Build Coastguard Worker  OptionParser.new do |opts|
108*cc02d7e2SAndroid Build Coastguard Worker    opts.on('--server_addresses [LIST]', Array) do |addrs|
109*cc02d7e2SAndroid Build Coastguard Worker      stress_args.server_addresses = addrs
110*cc02d7e2SAndroid Build Coastguard Worker    end
111*cc02d7e2SAndroid Build Coastguard Worker    opts.on('--test_cases cases', Array) do |cases|
112*cc02d7e2SAndroid Build Coastguard Worker      stress_args.test_cases = (cases.map do |item|
113*cc02d7e2SAndroid Build Coastguard Worker                                  split = item.split(':')
114*cc02d7e2SAndroid Build Coastguard Worker                                  [split[0]] * split[1].to_i
115*cc02d7e2SAndroid Build Coastguard Worker                                end).reduce([], :+)
116*cc02d7e2SAndroid Build Coastguard Worker    end
117*cc02d7e2SAndroid Build Coastguard Worker    opts.on('--test_duration_secs [INT]', OptionParser::DecimalInteger) do |time|
118*cc02d7e2SAndroid Build Coastguard Worker      stress_args.duration = time
119*cc02d7e2SAndroid Build Coastguard Worker    end
120*cc02d7e2SAndroid Build Coastguard Worker    opts.on('--num_channels_per_server [INT]', OptionParser::DecimalInteger) do |channels|
121*cc02d7e2SAndroid Build Coastguard Worker      stress_args.channels_per_server = channels
122*cc02d7e2SAndroid Build Coastguard Worker    end
123*cc02d7e2SAndroid Build Coastguard Worker    opts.on('--num_stubs_per_channel [INT]', OptionParser::DecimalInteger) do |stubs|
124*cc02d7e2SAndroid Build Coastguard Worker      stress_args.concurrent_calls = stubs
125*cc02d7e2SAndroid Build Coastguard Worker    end
126*cc02d7e2SAndroid Build Coastguard Worker    opts.on('--metrics_port [port]') do |port|
127*cc02d7e2SAndroid Build Coastguard Worker      stress_args.metrics_port = port
128*cc02d7e2SAndroid Build Coastguard Worker    end
129*cc02d7e2SAndroid Build Coastguard Worker  end.parse!
130*cc02d7e2SAndroid Build Coastguard Worker  stress_args
131*cc02d7e2SAndroid Build Coastguard Workerend
132*cc02d7e2SAndroid Build Coastguard Worker
133*cc02d7e2SAndroid Build Coastguard Workerdef main
134*cc02d7e2SAndroid Build Coastguard Worker  opts = parse_stress_args
135*cc02d7e2SAndroid Build Coastguard Worker  start(opts)
136*cc02d7e2SAndroid Build Coastguard Workerend
137*cc02d7e2SAndroid Build Coastguard Worker
138*cc02d7e2SAndroid Build Coastguard Workerif __FILE__ == $0
139*cc02d7e2SAndroid Build Coastguard Worker  main
140*cc02d7e2SAndroid Build Coastguard Workerend
141