Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed backlog controller enhancement #704

Merged
merged 1 commit into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions packages/caliper-core/lib/worker/rate-control/fixedBacklog.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,33 @@ class FixedBacklog extends RateInterface {
/**
* Initialise the rate controller with a passed msg object
* - Only requires the desired cnumber of unfinished transactions per client
* @param {JSON} msg the initialisation message
* @param {object} msg Client options with adjusted per-client load settings.
* @param {string} msg.type The type of the message. Currently always 'test'
* @param {string} msg.label The label of the round.
* @param {object} msg.rateControl The rate control to use for the round.
* @param {number} msg.trim The number/seconds of transactions to trim from the results.
* @param {object} msg.args The user supplied arguments for the round.
* @param {string} msg.cb The path of the user's callback module.
* @param {string} msg.config The path of the network's configuration file.
* @param {number} msg.numb The number of transactions to generate during the round.
* @param {number} msg.txDuration The length of the round in SECONDS.
* @param {number} msg.totalClients The number of clients executing the round.
* @param {number} msg.clients The number of clients executing the round.
* @param {object} msg.clientArgs Arguments for the client.
* @param {number} msg.clientIdx The 0-based index of the current client.
* @param {number} msg.roundIdx The 1-based index of the current round.
*
* @async
*/
init(msg) {
this.sleep_time = this.options.sleep_time ? parseFloat(this.options.sleep_time) : 100;
async init(msg) {
let tps;
if (this.options.startingTps) {
tps = this.options.startingTps;
} else {
tps = 1;
}
const tpsPerClient = msg.totalClients ? (tps / msg.totalClients) : tps;
this.sleepTime = 1000/tpsPerClient;
this.unfinished_per_client = this.options.unfinished_per_client ? parseInt(this.options.unfinished_per_client) : 10;
}

Expand All @@ -54,7 +77,7 @@ class FixedBacklog extends RateInterface {

// Waiting until successful transactions occur.
if(resultStats.length < 2 || !resultStats[0].succ || !resultStats[0].delay) {
await Sleep(this.sleep_time);
await Sleep(this.sleepTime);
return;
}

Expand All @@ -74,7 +97,7 @@ class FixedBacklog extends RateInterface {
const error = unfinished - this.unfinished_per_client;

// Sleep for a count of the load error and the current average delay
Logger.debug('Backlog error: ' + error);
Logger.debug('Difference between current and desired transaction backlog: ' + error);
await Sleep(error * avDelay);
}

Expand Down
3 changes: 2 additions & 1 deletion packages/caliper-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
".nyc_output",
"coverage",
".gitignore",
"log"
"log",
".DS_Store"
],
"file_type_method": "EXCLUDE",
"file_types": [
Expand Down
75 changes: 51 additions & 24 deletions packages/caliper-core/test/worker/rate-control/fixedBacklog.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,70 +21,97 @@ const chai = require('chai');
chai.should();
const sinon = require('sinon');

describe ('fixedBacklog controller implementation', () => {
describe('fixedBacklog controller implementation', () => {

let controller;
let opts = {
unfinished_per_client: 30,
sleep_time: 40
};

describe ('#init', () => {
describe('#init', () => {

it ('should set a default sleep time if no sleep time specified', () => {
controller = new FixedBacklog.createRateController({});
controller.init();
controller.sleep_time.should.equal(100);
let msg = {totalClients: 1};
let opts = {
unfinished_per_client: 30,
startingTps: 10
};

it('should set the sleep time for a single client if no clients are specified and the startingTps is specified', () => {
let msg = {};
controller = new FixedBacklog.createRateController(opts);
controller.init(msg);
controller.sleepTime.should.equal(100);
});

it ('should set the sleep time if specified', () => {
it('should set the sleep time for a single client if no clients are specified and the startingTps is not specified', () => {
let msg = {};
let opts = {
unfinished_per_client: 30
};
controller = new FixedBacklog.createRateController(opts);
controller.init(msg);
controller.sleepTime.should.equal(1000);
});

it('should set the sleep time for a multiple clients it the startingTps is specified', () => {
controller = new FixedBacklog.createRateController(opts);
controller.init(msg);
controller.sleepTime.should.equal(100);
});

it('should set the sleep time for a multiple clients it the startingTps is not specified', () => {
let opts = {
unfinished_per_client: 30
};
controller = new FixedBacklog.createRateController(opts);
controller.init();
controller.sleep_time.should.equal(40);
controller.init(msg);
controller.sleepTime.should.equal(1000);
});

it ('should set a default transaction backlog for multiple clients if not specified', () => {
it('should set a default transaction backlog for multiple clients if not specified', () => {
controller = new FixedBacklog.createRateController({});
controller.init();
controller.init(msg);
controller.unfinished_per_client.should.equal(10);
});

it ('should set the transaction backlog for multiple clients if specified', () => {
it('should set the transaction backlog for multiple clients if specified', () => {
controller = new FixedBacklog.createRateController(opts);
controller.init();
controller.init(msg);
controller.unfinished_per_client.should.equal(30);
});

});

describe ('#applyRateControl', () => {
describe('#applyRateControl', async () => {

let sleepStub;
let opts = {
unfinished_per_client: 30,
startingTps: 10
};

beforeEach(() => {
sleepStub = sinon.stub();
FixedBacklog.__set__('Sleep', sleepStub);

controller = new FixedBacklog.createRateController(opts);
controller.init();
controller.sleepTime = 1000;
controller.unfinished_per_client = 30;
});

it ('should sleep if resultStats.length < 2', () => {
it('should sleep if resultStats.length < 2', () => {
controller.applyRateControl(null, 1, [], []);
sinon.assert.calledOnce(sleepStub);
sinon.assert.calledWith(sleepStub, 40);
sinon.assert.calledWith(sleepStub, 1000);
});

it ('should sleep if no successful results are available', () => {
controller.applyRateControl(null, 1, [], [{}]);
sinon.assert.calledOnce(sleepStub);
sinon.assert.calledWith(sleepStub, 40);
sinon.assert.calledWith(sleepStub, 1000);
});

it ('should sleep if no delay results are available', () => {
controller.applyRateControl(null, 1, [], [{}]);
sinon.assert.calledOnce(sleepStub);
sinon.assert.calledWith(sleepStub, 40);
sinon.assert.calledWith(sleepStub, 1000);
});

it ('should not sleep if backlog transaction is below target', () => {
Expand Down Expand Up @@ -179,7 +206,7 @@ describe ('fixedBacklog controller implementation', () => {
const unfinshed = idx - completeTransactions;

const error = unfinshed - 30;
const message = 'Backlog error: ' + error;
const message = 'Difference between current and desired transaction backlog: ' + error;

sinon.assert.calledOnce(debugStub);
sinon.assert.calledWith(debugStub, message);
Expand Down