/* * * Copyright 2015, 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. * */ /** * Benchmark server module * @module */ 'use strict'; var fs = require('fs'); var path = require('path'); 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 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 server = new grpc.Server(); this.port = server.bind(host + ':' + port, server_creds); if (generic) { server.addService(genericService, { streamingCall: makeStreamingGenericCall(response_size) }); } else { server.addProtoService(serviceProto.BenchmarkService.service, { unaryCall: unaryCall, streamingCall: streamingCall }); } this.server = server; } /** * Start the benchmark server. */ BenchmarkServer.prototype.start = function() { this.server.start(); this.last_wall_time = process.hrtime(); }; /** * 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); if (reset) { this.last_wall_time = process.hrtime(); } return { time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9, // Not sure how to measure these values time_user: 0, time_system: 0 }; }; /** * 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;