From 56fe94f903afba1d309ec2b9baddf03d4bfe50ab Mon Sep 17 00:00:00 2001 From: Vincent Rousseau <vincent.rousseau@irstea.fr> Date: Sat, 2 Dec 2017 20:31:31 +0100 Subject: [PATCH 1/7] Add eco mode --- app/cli.ts | 1 + app/lib/dto/ConfDTO.ts | 3 ++- app/modules/prover/lib/blockProver.ts | 19 +++++++++++--- app/modules/prover/lib/powCluster.ts | 38 ++++++++++++++------------- index.ts | 2 ++ test/integration/proof-of-work.js | 16 +++++++++-- 6 files changed, 55 insertions(+), 24 deletions(-) diff --git a/app/cli.ts b/app/cli.ts index 3c2e49515..6a6d3924b 100644 --- a/app/cli.ts +++ b/app/cli.ts @@ -41,6 +41,7 @@ export const ExecuteCommand = () => { .option('--addep <endpoint>', 'With `config` command, add given endpoint to the list of endpoints of this node') .option('--remep <endpoint>', 'With `config` command, remove given endpoint to the list of endpoints of this node') + .option('--no-eco-mode', 'Do not reduce CPU usage for proof-of-work computation') .option('--cpu <percent>', 'Percent of CPU usage for proof-of-work computation', parsePercent) .option('--nb-cores <number>', 'Number of cores uses for proof-of-work computation', parseInt) .option('--prefix <nodeId>', 'Prefix node id for the first character of nonce', parseInt) diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts index 2e77e92fc..b6ff36a94 100644 --- a/app/lib/dto/ConfDTO.ts +++ b/app/lib/dto/ConfDTO.ts @@ -91,6 +91,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, public rmEndpoints: string[], public rootoffset: number, public upInterval: number, + public ecoMode: boolean|true, public cpu: number, public nbCores: number, public prefix: number, @@ -162,7 +163,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, ) {} static mock() { - return new ConfDTO("", "", [], [], 0, 3600 * 1000, constants.PROOF_OF_WORK.DEFAULT.CPU, 1, constants.PROOF_OF_WORK.DEFAULT.PREFIX, 0, 0, constants.CONTRACT.DEFAULT.C, constants.CONTRACT.DEFAULT.DT, constants.CONTRACT.DEFAULT.DT_REEVAL, 0, constants.CONTRACT.DEFAULT.UD0, 0, 0, constants.CONTRACT.DEFAULT.STEPMAX, constants.CONTRACT.DEFAULT.SIGPERIOD, 0, constants.CONTRACT.DEFAULT.SIGVALIDITY, constants.CONTRACT.DEFAULT.MSVALIDITY, constants.CONTRACT.DEFAULT.SIGQTY, constants.CONTRACT.DEFAULT.SIGSTOCK, constants.CONTRACT.DEFAULT.X_PERCENT, constants.CONTRACT.DEFAULT.PERCENTROT, constants.CONTRACT.DEFAULT.POWDELAY, constants.CONTRACT.DEFAULT.AVGGENTIME, constants.CONTRACT.DEFAULT.MEDIANTIMEBLOCKS, false, 3000, false, constants.BRANCHES.DEFAULT_WINDOW_SIZE, constants.CONTRACT.DEFAULT.IDTYWINDOW, constants.CONTRACT.DEFAULT.MSWINDOW, constants.CONTRACT.DEFAULT.SIGWINDOW, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", "", 0, "", "", null, false, "", true, true, false, new ProxiesConf(), undefined) + return new ConfDTO("", "", [], [], 0, 3600 * 1000, true, constants.PROOF_OF_WORK.DEFAULT.CPU, 1, constants.PROOF_OF_WORK.DEFAULT.PREFIX, 0, 0, constants.CONTRACT.DEFAULT.C, constants.CONTRACT.DEFAULT.DT, constants.CONTRACT.DEFAULT.DT_REEVAL, 0, constants.CONTRACT.DEFAULT.UD0, 0, 0, constants.CONTRACT.DEFAULT.STEPMAX, constants.CONTRACT.DEFAULT.SIGPERIOD, 0, constants.CONTRACT.DEFAULT.SIGVALIDITY, constants.CONTRACT.DEFAULT.MSVALIDITY, constants.CONTRACT.DEFAULT.SIGQTY, constants.CONTRACT.DEFAULT.SIGSTOCK, constants.CONTRACT.DEFAULT.X_PERCENT, constants.CONTRACT.DEFAULT.PERCENTROT, constants.CONTRACT.DEFAULT.POWDELAY, constants.CONTRACT.DEFAULT.AVGGENTIME, constants.CONTRACT.DEFAULT.MEDIANTIMEBLOCKS, false, 3000, false, constants.BRANCHES.DEFAULT_WINDOW_SIZE, constants.CONTRACT.DEFAULT.IDTYWINDOW, constants.CONTRACT.DEFAULT.MSWINDOW, constants.CONTRACT.DEFAULT.SIGWINDOW, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", "", 0, "", "", null, false, "", true, true, false, new ProxiesConf(), undefined) } static defaultConf() { diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 9cd215d98..1b6d051c2 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -177,6 +177,7 @@ export class BlockProver { newPoW: { turnDuration: os.arch().match(/arm/) ? CommonConstants.POW_TURN_DURATION_ARM : CommonConstants.POW_TURN_DURATION_PC, conf: { + nbCores: this.conf.nbCores, cpu: this.conf.cpu, prefix: this.conf.prefix, avgGenTime: this.conf.avgGenTime, @@ -196,16 +197,28 @@ export class BlockProver { const proof = result.block; const testsCount = result.testsCount; const duration = (Date.now() - start); - const testsPerSecond = (testsCount / (duration / 1000)).toFixed(2); - this.logger.info('Done: #%s, %s in %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), testsCount, testsPerSecond); + const testsPerSecond = (testsCount / (duration / 1000)); + this.logger.info('Done: #%s, %s in %ss instead of %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), + this.conf.avgGenTime, testsCount, testsPerSecond.toFixed(2)); this.logger.info('FOUND proof-of-work with %s leading zeros followed by [0-' + highMark + ']!', nbZeros); + if(this.conf.ecoMode && this.conf.nbCores*testsPerSecond > 300) { + if(this.conf.nbCores > 1) { + this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) + this.conf.nbCores = this.conf.nbCores -1 + } + else if(this.conf.cpu > 0.19){ + let cpu:number = this.conf.cpu - 0.1 + this.logger.info("Slowing down the CPU to "+cpu) + this.changeCPU(cpu) + } + } return BlockDTO.fromJSONObject(proof) } })() }; async changeCPU(cpu:number) { - this.conf.cpu = cpu; + this.conf.cpu = Math.max(0.01, Math.min(1.0, cpu)); const farm = await this.getWorker() return farm.changeCPU(cpu) } diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts index 4d4820777..8e6e65843 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -185,25 +185,27 @@ export class Master { // Start the salves' job this.slaves.forEach((s:any, index) => { - s.worker.send({ - uuid, - command: 'newPoW', - value: { - block: stuff.newPoW.block, - nonceBeginning: s.nonceBeginning, - zeros: stuff.newPoW.zeros, - highMark: stuff.newPoW.highMark, - pair: _.clone(stuff.newPoW.pair), - forcedTime: stuff.newPoW.forcedTime, - turnDuration: stuff.newPoW.turnDuration, - conf: { - medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, - avgGenTime: stuff.newPoW.conf.avgGenTime, - cpu: stuff.newPoW.conf.cpu, - prefix: stuff.newPoW.conf.prefix + if(index < stuff.newPoW.conf.nbCores) { + s.worker.send({ + uuid, + command: 'newPoW', + value: { + block: stuff.newPoW.block, + nonceBeginning: s.nonceBeginning, + zeros: stuff.newPoW.zeros, + highMark: stuff.newPoW.highMark, + pair: _.clone(stuff.newPoW.pair), + forcedTime: stuff.newPoW.forcedTime, + turnDuration: stuff.newPoW.turnDuration, + conf: { + medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, + avgGenTime: stuff.newPoW.conf.avgGenTime, + cpu: stuff.newPoW.conf.cpu, + prefix: stuff.newPoW.conf.prefix + } } - } - }) + }) + } }) return await this.currentPromise diff --git a/index.ts b/index.ts index ecf7be9d6..daf1b333b 100644 --- a/index.ts +++ b/index.ts @@ -443,6 +443,7 @@ function commandLineConf(program:any, conf:any = {}) { conf = conf || {}; const cli = { currency: program.currency, + ecoMode: program.ecoMode, cpu: program.cpu, nbCores: program.nbCores, prefix: program.prefix, @@ -485,6 +486,7 @@ function commandLineConf(program:any, conf:any = {}) { // Update the rest of the conf if (cli.currency) conf.currency = cli.currency; if (cli.server.port) conf.port = cli.server.port; + if (cli.ecoMode) conf.ecoMode = cli.ecoMode if (cli.cpu) conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu)); if (cli.prefix) conf.prefix = Math.max(ProverConstants.MIN_PEER_ID, Math.min(ProverConstants.MAX_PEER_ID, cli.prefix)); if (cli.logs.http) conf.httplogs = true; diff --git a/test/integration/proof-of-work.js b/test/integration/proof-of-work.js index f2540c606..dd507167a 100644 --- a/test/integration/proof-of-work.js +++ b/test/integration/proof-of-work.js @@ -16,13 +16,15 @@ keyring from Key ***/ const intermediateProofs = []; -const NB_CORES_FOR_COMPUTATION = 1 // For simple tests. Can be changed to test multiple cores. +const NB_CORES_FOR_COMPUTATION = 2 // For simple tests. Can be changed to test multiple cores. const prover = new BlockProver({ push: (data) => intermediateProofs.push(data), conf: { + avgGenTime: 20,//1*60, + ecoMode: true, nbCores: NB_CORES_FOR_COMPUTATION, - cpu: 1.0, // 80%, + cpu: 0.8, // 80%, pair: { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' @@ -34,9 +36,11 @@ const prover = new BlockProver({ const now = 1474382274 * 1000; const MUST_START_WITH_A_ZERO = 16; const MUST_START_WITH_TWO_ZEROS = 32; +const MUST_START_WITH_THREE_ZEROS = 58; describe("Proof-of-work", function() { + this.timeout(6*60000) it('should be able to find an easy PoW', () => co(function*() { let block = yield prover.prove({ issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', @@ -48,6 +52,14 @@ describe("Proof-of-work", function() { intermediateProofs[intermediateProofs.length - 1].pow.should.have.property('hash').equal(block.hash); })); + it('should be reducing cpu when the PoW is too easy for the cpu', () => co(function*() { + for(let i=0; i<8; ++i) { + let block = yield prover.prove({ + issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', + number: i+2 + }, MUST_START_WITH_THREE_ZEROS, now); + } + })); // Too randomly successing test // it('should be able to cancel a proof-of-work on other PoW receival', () => co(function*() { // const now = 1474464489; -- GitLab From 97d0de7336c5f4718c1bec90c089d6226354d258 Mon Sep 17 00:00:00 2001 From: librelois <elois@ifee.fr> Date: Sun, 3 Dec 2017 00:54:59 +0100 Subject: [PATCH 2/7] [fix] cli option ecoMode : treat cleanly default and undefined value --- app/cli.ts | 1 + app/lib/dto/ConfDTO.ts | 2 +- app/modules/prover/index.ts | 3 +++ app/modules/prover/lib/blockProver.ts | 2 +- app/modules/prover/lib/constants.ts | 1 + index.ts | 4 +++- 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/cli.ts b/app/cli.ts index 6a6d3924b..aaae51f89 100644 --- a/app/cli.ts +++ b/app/cli.ts @@ -41,6 +41,7 @@ export const ExecuteCommand = () => { .option('--addep <endpoint>', 'With `config` command, add given endpoint to the list of endpoints of this node') .option('--remep <endpoint>', 'With `config` command, remove given endpoint to the list of endpoints of this node') + .option('--eco-mode', 'reduce CPU usage for proof-of-work computation') .option('--no-eco-mode', 'Do not reduce CPU usage for proof-of-work computation') .option('--cpu <percent>', 'Percent of CPU usage for proof-of-work computation', parsePercent) .option('--nb-cores <number>', 'Number of cores uses for proof-of-work computation', parseInt) diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts index b6ff36a94..e6e750ca0 100644 --- a/app/lib/dto/ConfDTO.ts +++ b/app/lib/dto/ConfDTO.ts @@ -91,7 +91,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, public rmEndpoints: string[], public rootoffset: number, public upInterval: number, - public ecoMode: boolean|true, + public ecoMode: boolean|undefined, public cpu: number, public nbCores: number, public prefix: number, diff --git a/app/modules/prover/index.ts b/app/modules/prover/index.ts index 856e14237..98e011793 100644 --- a/app/modules/prover/index.ts +++ b/app/modules/prover/index.ts @@ -18,6 +18,9 @@ export const ProverDependency = { /*********** Permanent prover **************/ config: { onLoading: async (conf:ConfDTO) => { + if (conf.ecoMode === null || conf.ecoMode === undefined) { + conf.ecoMode = ProverConstants.DEFAULT_ECO_MODE; + } if (conf.cpu === null || conf.cpu === undefined) { conf.cpu = ProverConstants.DEFAULT_CPU; } diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 1b6d051c2..03676a8f4 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -201,7 +201,7 @@ export class BlockProver { this.logger.info('Done: #%s, %s in %ss instead of %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), this.conf.avgGenTime, testsCount, testsPerSecond.toFixed(2)); this.logger.info('FOUND proof-of-work with %s leading zeros followed by [0-' + highMark + ']!', nbZeros); - if(this.conf.ecoMode && this.conf.nbCores*testsPerSecond > 300) { + if(this.conf.ecoMode === true && this.conf.nbCores*testsPerSecond > 300) { if(this.conf.nbCores > 1) { this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) this.conf.nbCores = this.conf.nbCores -1 diff --git a/app/modules/prover/lib/constants.ts b/app/modules/prover/lib/constants.ts index 0a454d38f..2b8299c33 100644 --- a/app/modules/prover/lib/constants.ts +++ b/app/modules/prover/lib/constants.ts @@ -5,6 +5,7 @@ export const ProverConstants = { MINIMAL_ZEROS_TO_SHOW_IN_LOGS: 3, POW_MINIMAL_TO_SHOW: 2, + DEFAULT_ECO_MODE: true, DEFAULT_CPU: 0.6, DEFAULT_PEER_ID: 1, MIN_PEER_ID: 1, diff --git a/index.ts b/index.ts index daf1b333b..4a8679e7d 100644 --- a/index.ts +++ b/index.ts @@ -444,6 +444,7 @@ function commandLineConf(program:any, conf:any = {}) { const cli = { currency: program.currency, ecoMode: program.ecoMode, + noEcoMode: program.noEcoMode, cpu: program.cpu, nbCores: program.nbCores, prefix: program.prefix, @@ -486,7 +487,8 @@ function commandLineConf(program:any, conf:any = {}) { // Update the rest of the conf if (cli.currency) conf.currency = cli.currency; if (cli.server.port) conf.port = cli.server.port; - if (cli.ecoMode) conf.ecoMode = cli.ecoMode + if (cli.ecoMode) conf.ecoMode = true + if (cli.noEcoMode) conf.ecoMode = false if (cli.cpu) conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu)); if (cli.prefix) conf.prefix = Math.max(ProverConstants.MIN_PEER_ID, Math.min(ProverConstants.MAX_PEER_ID, cli.prefix)); if (cli.logs.http) conf.httplogs = true; -- GitLab From 42ca7a5a5d0f6bfcc777aa9f2be73335ebd2e0f7 Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Mon, 4 Dec 2017 17:45:56 +0100 Subject: [PATCH 3/7] [enh] Improve ecomode unit test + fix workers --- app/modules/prover/lib/powCluster.ts | 37 +++++++++++++--------------- test/integration/proof-of-work.js | 16 ++++++++---- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts index 8e6e65843..15d8d24c3 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -185,27 +185,24 @@ export class Master { // Start the salves' job this.slaves.forEach((s:any, index) => { - if(index < stuff.newPoW.conf.nbCores) { - s.worker.send({ - uuid, - command: 'newPoW', - value: { - block: stuff.newPoW.block, - nonceBeginning: s.nonceBeginning, - zeros: stuff.newPoW.zeros, - highMark: stuff.newPoW.highMark, - pair: _.clone(stuff.newPoW.pair), - forcedTime: stuff.newPoW.forcedTime, - turnDuration: stuff.newPoW.turnDuration, - conf: { - medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, - avgGenTime: stuff.newPoW.conf.avgGenTime, - cpu: stuff.newPoW.conf.cpu, - prefix: stuff.newPoW.conf.prefix - } + s.worker.send({ + uuid, + command: 'newPoW', + value: { + block: stuff.newPoW.block, + nonceBeginning: s.nonceBeginning, + zeros: stuff.newPoW.zeros, + highMark: stuff.newPoW.highMark, + pair: _.clone(stuff.newPoW.pair), + forcedTime: stuff.newPoW.forcedTime, + turnDuration: stuff.newPoW.turnDuration,conf: { + medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, + avgGenTime: stuff.newPoW.conf.avgGenTime, + cpu: stuff.newPoW.conf.cpu, + prefix: stuff.newPoW.conf.prefix } - }) - } + } + }) }) return await this.currentPromise diff --git a/test/integration/proof-of-work.js b/test/integration/proof-of-work.js index dd507167a..4d61810e3 100644 --- a/test/integration/proof-of-work.js +++ b/test/integration/proof-of-work.js @@ -36,11 +36,10 @@ const prover = new BlockProver({ const now = 1474382274 * 1000; const MUST_START_WITH_A_ZERO = 16; const MUST_START_WITH_TWO_ZEROS = 32; -const MUST_START_WITH_THREE_ZEROS = 58; +const MUST_START_WITH_A_ZERO_AND_A_NUMBER = 22 describe("Proof-of-work", function() { - this.timeout(6*60000) it('should be able to find an easy PoW', () => co(function*() { let block = yield prover.prove({ issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', @@ -53,12 +52,19 @@ describe("Proof-of-work", function() { })); it('should be reducing cpu when the PoW is too easy for the cpu', () => co(function*() { + prover.conf.nbCores = 2 + prover.conf.cpu = 0.9 + prover.conf.nbCores.should.equal(2) + prover.conf.cpu.should.equal(0.9) for(let i=0; i<8; ++i) { - let block = yield prover.prove({ + yield prover.prove({ issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', - number: i+2 - }, MUST_START_WITH_THREE_ZEROS, now); + number: i+2, + now + }, MUST_START_WITH_A_ZERO_AND_A_NUMBER, now); } + prover.conf.nbCores.should.equal(1) + prover.conf.cpu.should.be.below(0.9) })); // Too randomly successing test // it('should be able to cancel a proof-of-work on other PoW receival', () => co(function*() { -- GitLab From 6959f9f19b888ccfc3acdcc6f4fe6320723a007a Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Mon, 4 Dec 2017 17:50:56 +0100 Subject: [PATCH 4/7] [enh] Put constants in a ProverConstants --- app/modules/prover/lib/blockProver.ts | 4 ++-- app/modules/prover/lib/constants.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 03676a8f4..f3e036770 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -201,12 +201,12 @@ export class BlockProver { this.logger.info('Done: #%s, %s in %ss instead of %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), this.conf.avgGenTime, testsCount, testsPerSecond.toFixed(2)); this.logger.info('FOUND proof-of-work with %s leading zeros followed by [0-' + highMark + ']!', nbZeros); - if(this.conf.ecoMode === true && this.conf.nbCores*testsPerSecond > 300) { + if(this.conf.ecoMode === true && this.conf.nbCores*testsPerSecond > ProverConstants.ECO_MODE_MINIMAL_TESTS_PER_SECONDS) { if(this.conf.nbCores > 1) { this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) this.conf.nbCores = this.conf.nbCores -1 } - else if(this.conf.cpu > 0.19){ + else if(this.conf.cpu > ProverConstants.ECO_MODE_MINIMAL_CPU){ let cpu:number = this.conf.cpu - 0.1 this.logger.info("Slowing down the CPU to "+cpu) this.changeCPU(cpu) diff --git a/app/modules/prover/lib/constants.ts b/app/modules/prover/lib/constants.ts index 2b8299c33..3a8d77c70 100644 --- a/app/modules/prover/lib/constants.ts +++ b/app/modules/prover/lib/constants.ts @@ -11,6 +11,9 @@ export const ProverConstants = { MIN_PEER_ID: 1, MAX_PEER_ID: 899, // Due to MAX_SAFE_INTEGER = 9007199254740991 (16 digits, and we use 11 digits for the nonce + 2 digits for core number => 3 digits for the peer, must be below 900) + ECO_MODE_MINIMAL_TESTS_PER_SECONDS: 300, + ECO_MODE_MINIMAL_CPU: 0.19, + NONCE_RANGE: 1000 * 1000 * 1000 * 100, POW_MAXIMUM_ACCEPTABLE_HANDICAP: 64, -- GitLab From 93c5b747d2eda594893a45da34bf3cbecc27278f Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Mon, 4 Dec 2017 17:51:20 +0100 Subject: [PATCH 5/7] [enh] Eco mode should not be by default --- app/modules/prover/lib/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/modules/prover/lib/constants.ts b/app/modules/prover/lib/constants.ts index 3a8d77c70..66dbe534b 100644 --- a/app/modules/prover/lib/constants.ts +++ b/app/modules/prover/lib/constants.ts @@ -5,7 +5,7 @@ export const ProverConstants = { MINIMAL_ZEROS_TO_SHOW_IN_LOGS: 3, POW_MINIMAL_TO_SHOW: 2, - DEFAULT_ECO_MODE: true, + DEFAULT_ECO_MODE: false, DEFAULT_CPU: 0.6, DEFAULT_PEER_ID: 1, MIN_PEER_ID: 1, -- GitLab From 4e8a97cb6377c85c6886d07cacdfb38cb2475151 Mon Sep 17 00:00:00 2001 From: Vincent Rousseau <vincent.rousseau@irstea.fr> Date: Tue, 9 Jan 2018 15:56:49 +0100 Subject: [PATCH 6/7] Add CPU boost when few bloc of the user in frame --- app/lib/computation/BlockchainContext.ts | 10 +++++++ app/lib/indexer.ts | 2 ++ app/modules/prover/lib/blockProver.ts | 33 ++++++++++++++++++------ app/modules/prover/lib/constants.ts | 2 +- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/lib/computation/BlockchainContext.ts b/app/lib/computation/BlockchainContext.ts index 426ed2dc8..d8c1344c5 100644 --- a/app/lib/computation/BlockchainContext.ts +++ b/app/lib/computation/BlockchainContext.ts @@ -93,6 +93,16 @@ export class BlockchainContext { return local_vHEAD.issuerDiff; } + /** + * Utility method: gives the number of block in the current frame for a given issuer. + * @param issuer The issuer we want. + */ + async getIssuerNbBlockInFrame(issuer: string): Promise<number> { + const local_vHEAD = await this.getvHeadCopy({ issuer }) + let issuerNbBlockInFrame = await indexer.preparePersonalizedPoW(local_vHEAD, this.vHEAD_1, (n:number, m:number, p = "") => this.dal.range(n,m,p), this.conf) + return issuerNbBlockInFrame + } + setConfDAL(newConf: any, newDAL: any, theBlockchain: DuniterBlockchain, theQuickSynchronizer: QuickSynchronizer): void { this.dal = newDAL; this.conf = newConf; diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts index ddb1cfa99..ea2d70521 100644 --- a/app/lib/indexer.ts +++ b/app/lib/indexer.ts @@ -1092,6 +1092,8 @@ export class Indexer { HEAD.powRemainder = HEAD.issuerDiff % 16; HEAD.powZeros = (HEAD.issuerDiff - HEAD.powRemainder) / 16; + + return nbPersonalBlocksInFrame; } // BR_G19 diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index f3e036770..ce45c9f68 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -192,6 +192,15 @@ export class BlockProver { }); if (!result) { this.logger.info('GIVEN proof-of-work for block#%s with %s leading zeros followed by [0-' + highMark + ']! stop PoW for %s', block.number, nbZeros, this.pair && this.pair.pub.slice(0,6)); + let selfNbBlockInFrame = await this.server.getBcContext().getIssuerNbBlockInFrame(this.server.PeeringService.selfPubkey) + if(this.conf.ecoMode === true) { + let selfNbBlockInFrame = await this.server.getBcContext().getIssuerNbBlockInFrame(this.server.PeeringService.selfPubkey) + if(selfNbBlockInFrame < 2) { + this.changeCPU(1) + this.conf.nbCores = this.server.conf.nbCores + this.logger.info("Boost number of CPU cores "+this.conf.nbCores+" with only "+selfNbBlockInFrame+" block member in frame") + } + } throw 'Proof-of-work computation canceled because block received'; } else { const proof = result.block; @@ -201,15 +210,23 @@ export class BlockProver { this.logger.info('Done: #%s, %s in %ss instead of %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), this.conf.avgGenTime, testsCount, testsPerSecond.toFixed(2)); this.logger.info('FOUND proof-of-work with %s leading zeros followed by [0-' + highMark + ']!', nbZeros); - if(this.conf.ecoMode === true && this.conf.nbCores*testsPerSecond > ProverConstants.ECO_MODE_MINIMAL_TESTS_PER_SECONDS) { - if(this.conf.nbCores > 1) { - this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) - this.conf.nbCores = this.conf.nbCores -1 + if(this.conf.ecoMode === true) { + let selfNbBlockInFrame = await this.server.getBcContext().getIssuerNbBlockInFrame(this.server.PeeringService.selfPubkey) + if(selfNbBlockInFrame < 2) { + this.changeCPU(1) + this.conf.nbCores = this.server.conf.nbCores + this.logger.info("Boost number of CPU cores "+this.conf.nbCores+" with only "+selfNbBlockInFrame+" block member in frame") } - else if(this.conf.cpu > ProverConstants.ECO_MODE_MINIMAL_CPU){ - let cpu:number = this.conf.cpu - 0.1 - this.logger.info("Slowing down the CPU to "+cpu) - this.changeCPU(cpu) + else if(this.conf.nbCores*testsPerSecond > ProverConstants.ECO_MODE_MINIMAL_TESTS_PER_SECONDS) { + if(this.conf.nbCores > 1) { + this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) + this.conf.nbCores = this.conf.nbCores -1 + } + else if(this.conf.cpu > ProverConstants.ECO_MODE_MINIMAL_CPU){ + let cpu:number = this.conf.cpu - 0.1 + this.logger.info("Slowing down the CPU to "+cpu) + this.changeCPU(cpu) + } } } return BlockDTO.fromJSONObject(proof) diff --git a/app/modules/prover/lib/constants.ts b/app/modules/prover/lib/constants.ts index 66dbe534b..3a8d77c70 100644 --- a/app/modules/prover/lib/constants.ts +++ b/app/modules/prover/lib/constants.ts @@ -5,7 +5,7 @@ export const ProverConstants = { MINIMAL_ZEROS_TO_SHOW_IN_LOGS: 3, POW_MINIMAL_TO_SHOW: 2, - DEFAULT_ECO_MODE: false, + DEFAULT_ECO_MODE: true, DEFAULT_CPU: 0.6, DEFAULT_PEER_ID: 1, MIN_PEER_ID: 1, -- GitLab From 63a7f4b75a6e19eb3bc9ae81241edb5b597a5f65 Mon Sep 17 00:00:00 2001 From: Vincent Rousseau <vincent.rousseau@irstea.fr> Date: Thu, 11 Jan 2018 13:43:43 +0100 Subject: [PATCH 7/7] Add and remove workers during eco mode --- app/modules/prover/lib/blockProver.ts | 41 ++++++++++---- app/modules/prover/lib/engine.ts | 13 +++-- app/modules/prover/lib/powCluster.ts | 82 +++++++++++++++++---------- 3 files changed, 91 insertions(+), 45 deletions(-) diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 11ff17da0..a94a03cfe 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -48,6 +48,14 @@ export class WorkerFarm { return this.theEngine.getNbWorkers() } + reduceNbCores() { + return this.theEngine.reduceNbCores() + } + + boostCPU(){ + return this.theEngine.boostCPU() + } + changeCPU(cpu:any) { return this.theEngine.setConf({ cpu }) } @@ -194,13 +202,12 @@ export class BlockProver { }); if (!result) { this.logger.info('GIVEN proof-of-work for block#%s with %s leading zeros followed by [0-' + highMark + ']! stop PoW for %s', block.number, nbZeros, this.pair && this.pair.pub.slice(0,6)); - let selfNbBlockInFrame = await this.server.getBcContext().getIssuerNbBlockInFrame(this.server.PeeringService.selfPubkey) if(this.conf.ecoMode === true) { let selfNbBlockInFrame = await this.server.getBcContext().getIssuerNbBlockInFrame(this.server.PeeringService.selfPubkey) if(selfNbBlockInFrame < 2) { - this.changeCPU(1) - this.conf.nbCores = this.server.conf.nbCores - this.logger.info("Boost number of CPU cores "+this.conf.nbCores+" with only "+selfNbBlockInFrame+" block member in frame") + this.boostCPU() + this.conf.nbCores = powFarm.nbWorkers + this.logger.info("Boost number of CPU cores "+powFarm.nbWorkers+" with only "+selfNbBlockInFrame+" block member in frame") } } throw 'Proof-of-work computation canceled because block received'; @@ -214,14 +221,15 @@ export class BlockProver { if(this.conf.ecoMode === true) { let selfNbBlockInFrame = await this.server.getBcContext().getIssuerNbBlockInFrame(this.server.PeeringService.selfPubkey) if(selfNbBlockInFrame < 2) { - this.changeCPU(1) - this.conf.nbCores = this.server.conf.nbCores - this.logger.info("Boost number of CPU cores "+this.conf.nbCores+" with only "+selfNbBlockInFrame+" block member in frame") + this.boostCPU() + this.conf.nbCores = powFarm.nbWorkers + this.logger.info("Boost number of CPU cores "+powFarm.nbWorkers+" with only "+selfNbBlockInFrame+" block member in frame") } - else if(this.conf.nbCores*testsPerSecond > ProverConstants.ECO_MODE_MINIMAL_TESTS_PER_SECONDS) { - if(this.conf.nbCores > 1) { - this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) - this.conf.nbCores = this.conf.nbCores -1 + else if(testsPerSecond > ProverConstants.ECO_MODE_MINIMAL_TESTS_PER_SECONDS) { + if(powFarm.nbWorkers > 1) { + this.logger.info("Reducing number of CPU cores "+powFarm.nbWorkers) + this.reduceNbCores() + this.conf.nbCores = powFarm.nbWorkers } else if(this.conf.cpu > ProverConstants.ECO_MODE_MINIMAL_CPU){ let cpu:number = this.conf.cpu - 0.1 @@ -235,6 +243,17 @@ export class BlockProver { })() }; + async reduceNbCores() { + const farm = await this.getWorker() + return farm.reduceNbCores() + } + + async boostCPU() { + this.conf.cpu = 1.0 + const farm = await this.getWorker() + return farm.boostCPU() + } + async changeCPU(cpu:number) { this.conf.cpu = Math.max(0.01, Math.min(1.0, cpu)); const farm = await this.getWorker() diff --git a/app/modules/prover/lib/engine.ts b/app/modules/prover/lib/engine.ts index 6ab1ca645..64bd629f3 100644 --- a/app/modules/prover/lib/engine.ts +++ b/app/modules/prover/lib/engine.ts @@ -12,15 +12,12 @@ if(debug) { export class PowEngine { - private nbWorkers:number private cluster:PowCluster readonly id:number constructor(private conf:ConfDTO, logger:any) { - // We use as much cores as available, but not more than CORES_MAXIMUM_USE_IN_PARALLEL - this.nbWorkers = conf.nbCores - this.cluster = new PowCluster(this.nbWorkers, logger) + this.cluster = new PowCluster(conf.nbCores, logger) this.id = this.cluster.clusterId } @@ -41,6 +38,14 @@ export class PowEngine { return this.cluster.cancelWork() } + reduceNbCores() { + return this.cluster.removeSlave() + } + + boostCPU() { + return this.cluster.boostCPU() + } + setConf(value:any) { return this.cluster.changeConf(value) } diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts index d0c64c4e4..fc3821043 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -35,6 +35,7 @@ export class Master { logger:any onInfoCallback:any workersOnline:Promise<any>[] + maxNbCores:number = Math.min(ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL, require('os').cpus().length) constructor(private nbCores:number, logger:any) { this.clusterId = clusterId++ @@ -65,6 +66,56 @@ export class Master { // this.logger.debug(`ENGINE c#${this.clusterId}#${this.slavesMap[worker.id].index}:`, message) } + createSlave(index:number) { + const nodejsWorker = cluster.fork() + const worker = new PowWorker(nodejsWorker, message => { + this.onWorkerMessage(index, message) + }, () => { + this.logger.info(`[online] worker c#${this.clusterId}#w#${index}`) + worker.sendConf({ + command: 'conf', + value: this.conf + }) + }, (code:any, signal:any) => { + this.logger.info(`worker ${worker.pid} died with code ${code} and signal ${signal}`) + }) + + this.logger.info(`Creating worker c#${this.clusterId}#w#${nodejsWorker.id}`) + const slave = { + + // The Node.js worker + worker, + + // Inner identifier + index, + + // Worker ready + online: worker.online, + + // Each worker has his own chunk of possible nonces + nonceBeginning: this.nbCores === 1 ? 0 : (index + 1) * ProverConstants.NONCE_RANGE + } + this.slavesMap[nodejsWorker.id] = slave + return slave + } + + boostCPU() { + if(this.nbWorkers < this.maxNbCores) { + while(this.nbWorkers < this.maxNbCores) { + this.slaves.push(this.createSlave(this.nbWorkers)) + } + } + let conf:any = {cpu: 1} + this.changeConf(conf) + } + + async removeSlave() { + let nb_workers = this.nbWorkers + await this.slaves[nb_workers-1].worker.kill() + this.slaves.pop() + this.logger.info('Remove slave number '+ (nb_workers-1)) + } + /***************** * CLUSTER METHODS ****************/ @@ -77,36 +128,7 @@ export class Master { }) this.slaves = Array.from({ length: this.nbCores }).map((value, index) => { - const nodejsWorker = cluster.fork() - const worker = new PowWorker(nodejsWorker, message => { - this.onWorkerMessage(index, message) - }, () => { - this.logger.info(`[online] worker c#${this.clusterId}#w#${index}`) - worker.sendConf({ - command: 'conf', - value: this.conf - }) - }, (code:any, signal:any) => { - this.logger.info(`worker ${worker.pid} died with code ${code} and signal ${signal}`) - }) - - this.logger.info(`Creating worker c#${this.clusterId}#w#${nodejsWorker.id}`) - const slave = { - - // The Node.js worker - worker, - - // Inner identifier - index, - - // Worker ready - online: worker.online, - - // Each worker has his own chunk of possible nonces - nonceBeginning: this.nbCores === 1 ? 0 : (index + 1) * ProverConstants.NONCE_RANGE - } - this.slavesMap[nodejsWorker.id] = slave - return slave + return this.createSlave(index) }) this.workersOnline = this.slaves.map((s) => s.online) -- GitLab