| /* |
| * |
| * Copyright 2015 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| /** |
| * Benchmark server module |
| * @module |
| */ |
| |
| 'use strict'; |
| |
| var fs = require('fs'); |
| var path = require('path'); |
| var EventEmitter = require('events'); |
| var util = require('util'); |
| |
| var genericService = require('./generic_service'); |
| |
| var grpc = require('../../../'); |
| var serviceProto = grpc.load({ |
| root: __dirname + '/../../..', |
| file: 'src/proto/grpc/testing/services.proto'}).grpc.testing; |
| |
| /** |
| * Create a buffer filled with size zeroes |
| * @param {number} size The length of the buffer |
| * @return {Buffer} The new buffer |
| */ |
| function zeroBuffer(size) { |
| var zeros = new Buffer(size); |
| zeros.fill(0); |
| return zeros; |
| } |
| |
| /** |
| * Handler for the unary benchmark method. Simply responds with a payload |
| * containing the requested number of zero bytes. |
| * @param {Call} call The call object to be handled |
| * @param {function} callback The callback to call with the response |
| */ |
| function unaryCall(call, callback) { |
| var req = call.request; |
| var payload = {body: zeroBuffer(req.response_size)}; |
| callback(null, {payload: payload}); |
| } |
| |
| /** |
| * Handler for the streaming benchmark method. Simply responds to each request |
| * with a payload containing the requested number of zero bytes. |
| * @param {Call} call The call object to be handled |
| */ |
| function streamingCall(call) { |
| call.on('data', function(value) { |
| var payload = {body: zeroBuffer(value.response_size)}; |
| call.write({payload: payload}); |
| }); |
| call.on('end', function() { |
| call.end(); |
| }); |
| } |
| |
| function makeUnaryGenericCall(response_size) { |
| var response = zeroBuffer(response_size); |
| return function unaryGenericCall(call, callback) { |
| callback(null, response); |
| }; |
| } |
| |
| function makeStreamingGenericCall(response_size) { |
| var response = zeroBuffer(response_size); |
| return function streamingGenericCall(call) { |
| call.on('data', function(value) { |
| call.write(response); |
| }); |
| call.on('end', function() { |
| call.end(); |
| }); |
| }; |
| } |
| |
| /** |
| * BenchmarkServer class. Constructed based on parameters from the driver and |
| * stores statistics. |
| * @param {string} host The host to serve on |
| * @param {number} port The port to listen to |
| * @param {boolean} tls Indicates whether TLS should be used |
| * @param {boolean} generic Indicates whether to use the generic service |
| * @param {number=} response_size The response size for the generic service |
| */ |
| function BenchmarkServer(host, port, tls, generic, response_size) { |
| var server_creds; |
| var host_override; |
| if (tls) { |
| var key_path = path.join(__dirname, '../test/data/server1.key'); |
| var pem_path = path.join(__dirname, '../test/data/server1.pem'); |
| |
| var key_data = fs.readFileSync(key_path); |
| var pem_data = fs.readFileSync(pem_path); |
| server_creds = grpc.ServerCredentials.createSsl(null, |
| [{private_key: key_data, |
| cert_chain: pem_data}]); |
| } else { |
| server_creds = grpc.ServerCredentials.createInsecure(); |
| } |
| |
| var options = { |
| "grpc.max_receive_message_length": -1, |
| "grpc.max_send_message_length": -1 |
| }; |
| |
| var server = new grpc.Server(options); |
| this.port = server.bind(host + ':' + port, server_creds); |
| if (generic) { |
| server.addService(genericService, { |
| unaryCall: makeUnaryGenericCall(response_size), |
| streamingCall: makeStreamingGenericCall(response_size) |
| }); |
| } else { |
| server.addService(serviceProto.BenchmarkService.service, { |
| unaryCall: unaryCall, |
| streamingCall: streamingCall |
| }); |
| } |
| this.server = server; |
| } |
| |
| util.inherits(BenchmarkServer, EventEmitter); |
| |
| /** |
| * Start the benchmark server. |
| */ |
| BenchmarkServer.prototype.start = function() { |
| this.server.start(); |
| this.last_wall_time = process.hrtime(); |
| this.last_usage = process.cpuUsage(); |
| this.emit('started'); |
| }; |
| |
| /** |
| * Return the port number that the server is bound to. |
| * @return {Number} The port number |
| */ |
| BenchmarkServer.prototype.getPort = function() { |
| return this.port; |
| }; |
| |
| /** |
| * Return current statistics for the server. If reset is set, restart |
| * statistic collection. |
| * @param {boolean} reset Indicates that statistics should be reset |
| * @return {object} Server statistics |
| */ |
| BenchmarkServer.prototype.mark = function(reset) { |
| var wall_time_diff = process.hrtime(this.last_wall_time); |
| var usage_diff = process.cpuUsage(this.last_usage); |
| if (reset) { |
| this.last_wall_time = process.hrtime(); |
| this.last_usage = process.cpuUsage(); |
| } |
| return { |
| time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9, |
| time_user: usage_diff.user / 1000000, |
| time_system: usage_diff.system / 1000000 |
| }; |
| }; |
| |
| /** |
| * Stop the server. |
| * @param {function} callback Called when the server has finished shutting down |
| */ |
| BenchmarkServer.prototype.stop = function(callback) { |
| this.server.tryShutdown(callback); |
| }; |
| |
| module.exports = BenchmarkServer; |