proxy-worker.rb 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #!/usr/bin/env ruby
  2. # Copyright 2017 gRPC authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. # Proxy of worker service implementation for running a PHP client
  16. this_dir = File.expand_path(File.dirname(__FILE__))
  17. lib_dir = File.join(File.dirname(this_dir), 'lib')
  18. $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
  19. $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
  20. require 'grpc'
  21. require 'optparse'
  22. require 'histogram'
  23. require 'etc'
  24. require 'facter'
  25. require 'qps-common'
  26. require 'src/proto/grpc/testing/worker_service_services_pb'
  27. require 'src/proto/grpc/testing/proxy-service_services_pb'
  28. class ProxyBenchmarkClientServiceImpl < Grpc::Testing::ProxyClientService::Service
  29. def initialize(port, c_ext, php_client_bin)
  30. @mytarget = "localhost:" + port.to_s
  31. @use_c_ext = c_ext
  32. @php_client_bin = php_client_bin
  33. end
  34. def setup(config)
  35. @config = config
  36. @histres = config.histogram_params.resolution
  37. @histmax = config.histogram_params.max_possible
  38. @histogram = Histogram.new(@histres, @histmax)
  39. @start_time = Time.now
  40. @php_pid = Array.new(@config.client_channels)
  41. (0..@config.client_channels-1).each do |chan|
  42. Thread.new {
  43. if @use_c_ext
  44. puts "Use protobuf c extension"
  45. command = "php -d extension=" + File.expand_path(File.dirname(__FILE__)) +
  46. "/../../../third_party/protobuf/php/ext/google/protobuf/modules/protobuf.so " +
  47. "-d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/ext/grpc/modules/grpc.so " +
  48. File.expand_path(File.dirname(__FILE__)) + "/" + @php_client_bin + " " + @mytarget + " #{chan%@config.server_targets.length}"
  49. else
  50. puts "Use protobuf php extension"
  51. command = "php -d extension=" + File.expand_path(File.dirname(__FILE__)) + "/../../php/ext/grpc/modules/grpc.so " +
  52. File.expand_path(File.dirname(__FILE__)) + "/" + @php_client_bin + " " + @mytarget + " #{chan%@config.server_targets.length}"
  53. end
  54. puts "[ruby proxy] Starting #{chan}th php-client command use c protobuf #{@use_c_ext}: " + command
  55. @php_pid[chan] = spawn(command)
  56. while true
  57. sleep
  58. end
  59. }
  60. end
  61. end
  62. def stop
  63. (0..@config.client_channels-1).each do |chan|
  64. Process.kill("TERM", @php_pid[chan])
  65. Process.wait(@php_pid[chan])
  66. end
  67. end
  68. def get_config(_args, _call)
  69. @config
  70. end
  71. def report_time(call)
  72. call.each_remote_read do |lat|
  73. @histogram.add((lat.latency)*1e9)
  74. end
  75. Grpc::Testing::Void.new
  76. end
  77. def report_hist(call)
  78. call.each_remote_read do |lat|
  79. @histogram.merge(lat)
  80. end
  81. Grpc::Testing::Void.new
  82. end
  83. def mark(reset)
  84. lat = Grpc::Testing::HistogramData.new(
  85. bucket: @histogram.contents,
  86. min_seen: @histogram.minimum,
  87. max_seen: @histogram.maximum,
  88. sum: @histogram.sum,
  89. sum_of_squares: @histogram.sum_of_squares,
  90. count: @histogram.count
  91. )
  92. elapsed = Time.now-@start_time
  93. if reset
  94. @start_time = Time.now
  95. @histogram = Histogram.new(@histres, @histmax)
  96. end
  97. Grpc::Testing::ClientStats.new(latencies: lat, time_elapsed: elapsed)
  98. end
  99. end
  100. class ProxyWorkerServiceImpl < Grpc::Testing::WorkerService::Service
  101. def cpu_cores
  102. Facter.value('processors')['count']
  103. end
  104. # Leave run_server unimplemented since this proxies for a client only.
  105. # If the driver tries to use this as a server, it will get an unimplemented
  106. # status return value.
  107. def run_client(reqs)
  108. q = EnumeratorQueue.new(self)
  109. Thread.new {
  110. reqs.each do |req|
  111. case req.argtype.to_s
  112. when 'setup'
  113. @bmc.setup(req.setup)
  114. q.push(Grpc::Testing::ClientStatus.new(stats: @bmc.mark(false)))
  115. when 'mark'
  116. q.push(Grpc::Testing::ClientStatus.new(stats:
  117. @bmc.mark(req.mark.reset)))
  118. end
  119. end
  120. @bmc.stop
  121. q.push(self)
  122. }
  123. q.each_item
  124. end
  125. def core_count(_args, _call)
  126. Grpc::Testing::CoreResponse.new(cores: cpu_cores)
  127. end
  128. def quit_worker(_args, _call)
  129. Thread.new {
  130. sleep 3
  131. @server.stop
  132. }
  133. Grpc::Testing::Void.new
  134. end
  135. def initialize(s, bmc)
  136. @server = s
  137. @bmc = bmc
  138. end
  139. end
  140. def proxymain
  141. options = {
  142. 'driver_port' => 0,
  143. 'php_client_bin' => '../../php/tests/qps/client.php'
  144. }
  145. OptionParser.new do |opts|
  146. opts.banner = 'Usage: [--driver_port <port>]'
  147. opts.on('--driver_port PORT', '<port>') do |v|
  148. options['driver_port'] = v
  149. end
  150. opts.on("-c", "--[no-]use_protobuf_c_extension", "Use protobuf C-extention") do |c|
  151. options[:c_ext] = c
  152. end
  153. opts.on("-b", "--php_client_bin [FILE]",
  154. "PHP client to execute; path relative to this script") do |c|
  155. options['php_client_bin'] = c
  156. end
  157. end.parse!
  158. # Configure any errors with client or server child threads to surface
  159. Thread.abort_on_exception = true
  160. # Make sure proxy_server can handle the large number of calls in benchmarks
  161. s = GRPC::RpcServer.new(pool_size: 1024)
  162. port = s.add_http2_port("0.0.0.0:" + options['driver_port'].to_s,
  163. :this_port_is_insecure)
  164. bmc = ProxyBenchmarkClientServiceImpl.new(port, options[:c_ext], options['php_client_bin'])
  165. s.handle(bmc)
  166. s.handle(ProxyWorkerServiceImpl.new(s, bmc))
  167. s.run
  168. end
  169. proxymain