mirror of https://github.com/grpc/grpc.git
parent
e621f13ecd
commit
ddaa69f15d
6 changed files with 301 additions and 22 deletions
@ -0,0 +1,28 @@ |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: grpc/testing/metrics.proto |
||||
|
||||
require 'google/protobuf' |
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do |
||||
add_message "grpc.testing.GaugeResponse" do |
||||
optional :name, :string, 1 |
||||
oneof :value do |
||||
optional :long_value, :int64, 2 |
||||
optional :double_value, :double, 3 |
||||
optional :string_value, :string, 4 |
||||
end |
||||
end |
||||
add_message "grpc.testing.GaugeRequest" do |
||||
optional :name, :string, 1 |
||||
end |
||||
add_message "grpc.testing.EmptyMessage" do |
||||
end |
||||
end |
||||
|
||||
module Grpc |
||||
module Testing |
||||
GaugeResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GaugeResponse").msgclass |
||||
GaugeRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GaugeRequest").msgclass |
||||
EmptyMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EmptyMessage").msgclass |
||||
end |
||||
end |
@ -0,0 +1,27 @@ |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# Source: grpc/testing/metrics.proto for package 'grpc.testing' |
||||
|
||||
require 'grpc' |
||||
require 'grpc/testing/metrics' |
||||
|
||||
module Grpc |
||||
module Testing |
||||
module MetricsService |
||||
|
||||
# TODO: add proto service documentation here |
||||
class Service |
||||
|
||||
include GRPC::GenericService |
||||
|
||||
self.marshal_class_method = :encode |
||||
self.unmarshal_class_method = :decode |
||||
self.service_name = 'grpc.testing.MetricsService' |
||||
|
||||
rpc :GetAllGauges, EmptyMessage, stream(GaugeResponse) |
||||
rpc :GetGauge, GaugeRequest, GaugeResponse |
||||
end |
||||
|
||||
Stub = Service.rpc_stub_class |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,83 @@ |
||||
# Copyright 2016, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
require_relative '../pb/grpc/testing/metrics.rb' |
||||
require_relative '../pb/grpc/testing/metrics_services.rb' |
||||
|
||||
class Gauge |
||||
def get_name |
||||
raise NoMethodError.new |
||||
end |
||||
|
||||
def get_type |
||||
raise NoMethodError.new |
||||
end |
||||
|
||||
def get_value |
||||
raise NoMethodError.new |
||||
end |
||||
end |
||||
|
||||
class MetricsServiceImpl < Grpc::Testing::MetricsService::Service |
||||
include Grpc::Testing |
||||
@gauges |
||||
|
||||
def initialize |
||||
@gauges = {} |
||||
end |
||||
|
||||
def register_gauge(gauge) |
||||
@gauges[gauge.get_name] = gauge |
||||
end |
||||
|
||||
def make_gauge_response(gauge) |
||||
response = GaugeResponse.new(:name => gauge.get_name) |
||||
value = gauge.get_value |
||||
case gauge.get_type |
||||
when 'long' |
||||
response.long_value = value |
||||
when 'double' |
||||
response.double_value = value |
||||
when 'string' |
||||
response.string_value = value |
||||
end |
||||
response |
||||
end |
||||
|
||||
def get_all_gauges(_empty, _call) |
||||
@gauges.values.map do |gauge| |
||||
make_gauge_response gauge |
||||
end |
||||
end |
||||
|
||||
def get_gauge(gauge_req, _call) |
||||
gauge = @gauges[gauge_req.name] |
||||
make_gauge_response gauge |
||||
end |
||||
end |
@ -0,0 +1,155 @@ |
||||
#!/usr/bin/env ruby |
||||
|
||||
# Copyright 2016, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
require 'optparse' |
||||
require 'thread' |
||||
require_relative '../pb/test/client' |
||||
require_relative './metrics_server' |
||||
require_relative '../lib/grpc' |
||||
|
||||
class QpsGauge < Gauge |
||||
@query_count |
||||
@query_mutex |
||||
@start_time |
||||
|
||||
def initialize |
||||
@query_count = 0 |
||||
@query_mutex = Mutex.new |
||||
@start_time = Time.now |
||||
end |
||||
|
||||
def increment_queries |
||||
@query_mutex.synchronize { @query_count += 1} |
||||
end |
||||
|
||||
def get_name |
||||
'qps' |
||||
end |
||||
|
||||
def get_type |
||||
'long' |
||||
end |
||||
|
||||
def get_value |
||||
(@query_mutex.synchronize { @query_count / (Time.now - @start_time) }).to_i |
||||
end |
||||
end |
||||
|
||||
def start_metrics_server(port) |
||||
host = "0.0.0.0:#{port}" |
||||
server = GRPC::RpcServer.new |
||||
server.add_http2_port(host, :this_port_is_insecure) |
||||
service = MetricsServiceImpl.new |
||||
server.handle(service) |
||||
server_thread = Thread.new { server.run_till_terminated } |
||||
[server, service, server_thread] |
||||
end |
||||
|
||||
StressArgs = Struct.new(:server_addresses, :test_cases, :duration, |
||||
:channels_per_server, :concurrent_calls, :metrics_port) |
||||
|
||||
def start(stress_args) |
||||
running = true |
||||
threads = [] |
||||
qps_gauge = QpsGauge.new |
||||
metrics_server, metrics_service, metrics_thread = |
||||
start_metrics_server(stress_args.metrics_port) |
||||
metrics_service.register_gauge(qps_gauge) |
||||
stress_args.server_addresses.each do |address| |
||||
stress_args.channels_per_server.times do |
||||
client_args = Args.new |
||||
client_args.host, client_args.port = address.split(':') |
||||
client_args.secure = false |
||||
client_args.test_case = '' |
||||
stub = create_stub(client_args) |
||||
named_tests = NamedTests.new(stub, client_args) |
||||
stress_args.concurrent_calls.times do |
||||
threads << Thread.new do |
||||
while running |
||||
named_tests.method(stress_args.test_cases.sample).call |
||||
qps_gauge.increment_queries |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
if stress_args.duration >= 0 |
||||
sleep stress_args.duration |
||||
running = false |
||||
metrics_server.stop |
||||
p "QPS: #{qps_gauge.get_value}" |
||||
threads.each { |thd| thd.join; } |
||||
end |
||||
metrics_thread.join |
||||
end |
||||
|
||||
def parse_stress_args |
||||
stress_args = StressArgs.new |
||||
stress_args.server_addresses = ['localhost:8080'] |
||||
stress_args.test_cases = [] |
||||
stress_args.duration = -1 |
||||
stress_args.channels_per_server = 1 |
||||
stress_args.concurrent_calls = 1 |
||||
stress_args.metrics_port = '8081' |
||||
OptionParser.new do |opts| |
||||
opts.on('--server_addresses [LIST]', Array) do |addrs| |
||||
stress_args.server_addresses = addrs |
||||
end |
||||
opts.on('--test_cases cases', Array) do |cases| |
||||
stress_args.test_cases = (cases.map do |item| |
||||
split = item.split(':') |
||||
[split[0]] * split[1].to_i |
||||
end).reduce([], :+) |
||||
end |
||||
opts.on('--test_duration_secs [INT]', OptionParser::DecimalInteger) do |time| |
||||
stress_args.duration = time |
||||
end |
||||
opts.on('--num_channels_per_server [INT]', OptionParser::DecimalInteger) do |channels| |
||||
stress_args.channels_per_server = channels |
||||
end |
||||
opts.on('--num_stubs_per_channel [INT]', OptionParser::DecimalInteger) do |stubs| |
||||
stress_args.concurrent_calls = stubs |
||||
end |
||||
opts.on('--metrics_port [port]') do |port| |
||||
stress_args.metrics_port = port |
||||
end |
||||
end.parse! |
||||
stress_args |
||||
end |
||||
|
||||
def main |
||||
opts = parse_stress_args |
||||
start(opts) |
||||
end |
||||
|
||||
if __FILE__ == $0 |
||||
main |
||||
end |
Loading…
Reference in new issue