Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Side by Side Diff: third_party/grpc/src/node/performance/benchmark_client.js

Issue 1932353002: Initial checkin of gRPC to third_party/ Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 *
3 * Copyright 2015-2016, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34 /**
35 * Benchmark client module
36 * @module
37 */
38
39 'use strict';
40
41 var fs = require('fs');
42 var path = require('path');
43 var util = require('util');
44 var EventEmitter = require('events');
45 var _ = require('lodash');
46 var PoissonProcess = require('poisson-process');
47 var Histogram = require('./histogram');
48 var grpc = require('../../../');
49 var serviceProto = grpc.load({
50 root: __dirname + '/../../..',
51 file: 'src/proto/grpc/testing/services.proto'}).grpc.testing;
52
53 /**
54 * Create a buffer filled with size zeroes
55 * @param {number} size The length of the buffer
56 * @return {Buffer} The new buffer
57 */
58 function zeroBuffer(size) {
59 var zeros = new Buffer(size);
60 zeros.fill(0);
61 return zeros;
62 }
63
64 /**
65 * Convert a time difference, as returned by process.hrtime, to a number of
66 * nanoseconds.
67 * @param {Array.<number>} time_diff The time diff, represented as
68 * [seconds, nanoseconds]
69 * @return {number} The total number of nanoseconds
70 */
71 function timeDiffToNanos(time_diff) {
72 return time_diff[0] * 1e9 + time_diff[1];
73 }
74
75 /**
76 * The BenchmarkClient class. Opens channels to servers and makes RPCs based on
77 * parameters from the driver, and records statistics about those RPCs.
78 * @param {Array.<string>} server_targets List of servers to connect to
79 * @param {number} channels The total number of channels to open
80 * @param {Object} histogram_params Options for setting up the histogram
81 * @param {Object=} security_params Options for TLS setup. If absent, don't use
82 * TLS
83 */
84 function BenchmarkClient(server_targets, channels, histogram_params,
85 security_params) {
86 var options = {};
87 var creds;
88 if (security_params) {
89 var ca_path;
90 if (security_params.use_test_ca) {
91 ca_path = path.join(__dirname, '../test/data/ca.pem');
92 var ca_data = fs.readFileSync(ca_path);
93 creds = grpc.credentials.createSsl(ca_data);
94 } else {
95 creds = grpc.credentials.createSsl();
96 }
97 if (security_params.server_host_override) {
98 var host_override = security_params.server_host_override;
99 options['grpc.ssl_target_name_override'] = host_override;
100 options['grpc.default_authority'] = host_override;
101 }
102 } else {
103 creds = grpc.credentials.createInsecure();
104 }
105
106 this.clients = [];
107
108 for (var i = 0; i < channels; i++) {
109 this.clients[i] = new serviceProto.BenchmarkService(
110 server_targets[i % server_targets.length], creds, options);
111 }
112
113 this.histogram = new Histogram(histogram_params.resolution,
114 histogram_params.max_possible);
115
116 this.running = false;
117
118 this.pending_calls = 0;
119 };
120
121 util.inherits(BenchmarkClient, EventEmitter);
122
123 /**
124 * Start a closed-loop test. For each channel, start
125 * outstanding_rpcs_per_channel RPCs. Then, whenever an RPC finishes, start
126 * another one.
127 * @param {number} outstanding_rpcs_per_channel Number of RPCs to start per
128 * channel
129 * @param {string} rpc_type Which method to call. Should be 'UNARY' or
130 * 'STREAMING'
131 * @param {number} req_size The size of the payload to send with each request
132 * @param {number} resp_size The size of payload to request be sent in responses
133 */
134 BenchmarkClient.prototype.startClosedLoop = function(
135 outstanding_rpcs_per_channel, rpc_type, req_size, resp_size) {
136 var self = this;
137
138 self.running = true;
139
140 self.last_wall_time = process.hrtime();
141
142 var makeCall;
143
144 var argument = {
145 response_size: resp_size,
146 payload: {
147 body: zeroBuffer(req_size)
148 }
149 };
150
151 if (rpc_type == 'UNARY') {
152 makeCall = function(client) {
153 if (self.running) {
154 self.pending_calls++;
155 var start_time = process.hrtime();
156 client.unaryCall(argument, function(error, response) {
157 if (error) {
158 self.emit('error', new Error('Client error: ' + error.message));
159 self.running = false;
160 return;
161 }
162 var time_diff = process.hrtime(start_time);
163 self.histogram.add(timeDiffToNanos(time_diff));
164 makeCall(client);
165 self.pending_calls--;
166 if ((!self.running) && self.pending_calls == 0) {
167 self.emit('finished');
168 }
169 });
170 }
171 };
172 } else {
173 makeCall = function(client) {
174 if (self.running) {
175 self.pending_calls++;
176 var start_time = process.hrtime();
177 var call = client.streamingCall();
178 call.write(argument);
179 call.on('data', function() {
180 });
181 call.on('end', function() {
182 var time_diff = process.hrtime(start_time);
183 self.histogram.add(timeDiffToNanos(time_diff));
184 makeCall(client);
185 self.pending_calls--;
186 if ((!self.running) && self.pending_calls == 0) {
187 self.emit('finished');
188 }
189 });
190 call.on('error', function(error) {
191 self.emit('error', new Error('Client error: ' + error.message));
192 self.running = false;
193 });
194 }
195 };
196 }
197
198 _.each(self.clients, function(client) {
199 _.times(outstanding_rpcs_per_channel, function() {
200 makeCall(client);
201 });
202 });
203 };
204
205 /**
206 * Start a poisson test. For each channel, this initiates a number of Poisson
207 * processes equal to outstanding_rpcs_per_channel, where each Poisson process
208 * has the load parameter offered_load.
209 * @param {number} outstanding_rpcs_per_channel Number of RPCs to start per
210 * channel
211 * @param {string} rpc_type Which method to call. Should be 'UNARY' or
212 * 'STREAMING'
213 * @param {number} req_size The size of the payload to send with each request
214 * @param {number} resp_size The size of payload to request be sent in responses
215 * @param {number} offered_load The load parameter for the Poisson process
216 */
217 BenchmarkClient.prototype.startPoisson = function(
218 outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, offered_load) {
219 var self = this;
220
221 self.running = true;
222
223 self.last_wall_time = process.hrtime();
224
225 var makeCall;
226
227 var argument = {
228 response_size: resp_size,
229 payload: {
230 body: zeroBuffer(req_size)
231 }
232 };
233
234 if (rpc_type == 'UNARY') {
235 makeCall = function(client, poisson) {
236 if (self.running) {
237 self.pending_calls++;
238 var start_time = process.hrtime();
239 client.unaryCall(argument, function(error, response) {
240 if (error) {
241 self.emit('error', new Error('Client error: ' + error.message));
242 self.running = false;
243 return;
244 }
245 var time_diff = process.hrtime(start_time);
246 self.histogram.add(timeDiffToNanos(time_diff));
247 self.pending_calls--;
248 if ((!self.running) && self.pending_calls == 0) {
249 self.emit('finished');
250 }
251 });
252 } else {
253 poisson.stop();
254 }
255 };
256 } else {
257 makeCall = function(client, poisson) {
258 if (self.running) {
259 self.pending_calls++;
260 var start_time = process.hrtime();
261 var call = client.streamingCall();
262 call.write(argument);
263 call.on('data', function() {
264 });
265 call.on('end', function() {
266 var time_diff = process.hrtime(start_time);
267 self.histogram.add(timeDiffToNanos(time_diff));
268 self.pending_calls--;
269 if ((!self.running) && self.pending_calls == 0) {
270 self.emit('finished');
271 }
272 });
273 call.on('error', function(error) {
274 self.emit('error', new Error('Client error: ' + error.message));
275 self.running = false;
276 });
277 } else {
278 poisson.stop();
279 }
280 };
281 }
282
283 var averageIntervalMs = (1 / offered_load) * 1000;
284
285 _.each(self.clients, function(client) {
286 _.times(outstanding_rpcs_per_channel, function() {
287 var p = PoissonProcess.create(averageIntervalMs, function() {
288 makeCall(client, p);
289 });
290 p.start();
291 });
292 });
293 };
294
295 /**
296 * Return curent statistics for the client. If reset is set, restart
297 * statistic collection.
298 * @param {boolean} reset Indicates that statistics should be reset
299 * @return {object} Client statistics
300 */
301 BenchmarkClient.prototype.mark = function(reset) {
302 var wall_time_diff = process.hrtime(this.last_wall_time);
303 var histogram = this.histogram;
304 if (reset) {
305 this.last_wall_time = process.hrtime();
306 this.histogram = new Histogram(histogram.resolution,
307 histogram.max_possible);
308 }
309
310 return {
311 latencies: {
312 bucket: histogram.getContents(),
313 min_seen: histogram.minimum(),
314 max_seen: histogram.maximum(),
315 sum: histogram.getSum(),
316 sum_of_squares: histogram.sumOfSquares(),
317 count: histogram.getCount()
318 },
319 time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
320 // Not sure how to measure these values
321 time_user: 0,
322 time_system: 0
323 };
324 };
325
326 /**
327 * Stop the clients.
328 * @param {function} callback Called when the clients have finished shutting
329 * down
330 */
331 BenchmarkClient.prototype.stop = function(callback) {
332 this.running = false;
333 this.on('finished', callback);
334 };
335
336 module.exports = BenchmarkClient;
OLDNEW
« no previous file with comments | « third_party/grpc/src/node/jsdoc_conf.json ('k') | third_party/grpc/src/node/performance/benchmark_server.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698