Unverified Commit bbf2b959 authored by Éloïs's avatar Éloïs
Browse files

[fix] finalize the revert of the branch' better_cpu'

parent d4123939
......@@ -44,9 +44,6 @@ export class WorkerFarm {
})
}
get nbWorkers() {
return this.theEngine.getNbWorkers()
}
changeCPU(cpu:any) {
return this.theEngine.setConf({ cpu })
......@@ -178,6 +175,7 @@ export class BlockProver {
const start = Date.now();
let result = await powFarm.askNewProof({
newPoW: {
turnDuration: os.arch().match(/arm/) ? CommonConstants.POW_TURN_DURATION_ARM : CommonConstants.POW_TURN_DURATION_PC,
conf: {
cpu: this.conf.cpu,
prefix: this.conf.prefix,
......@@ -196,10 +194,10 @@ export class BlockProver {
throw 'Proof-of-work computation canceled because block received';
} else {
const proof = result.block;
const testsCount = result.testsCount * powFarm.nbWorkers
const testsCount = result.testsCount;
const duration = (Date.now() - start);
const testsPerSecond = testsCount / (duration / 1000)
this.logger.info('Done: #%s, %s in %ss (~%s tests, ~%s tests/s, using %s cores, CPU %s%)', block.number, proof.hash, (duration / 1000).toFixed(2), testsCount, testsPerSecond.toFixed(2), powFarm.nbWorkers, Math.floor(100*this.conf.cpu))
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);
this.logger.info('FOUND proof-of-work with %s leading zeros followed by [0-' + highMark + ']!', nbZeros);
return BlockDTO.fromJSONObject(proof)
}
......
......@@ -25,25 +25,22 @@ export class PowEngine {
this.id = this.cluster.clusterId
}
getNbWorkers() {
return this.cluster.nbWorkers
}
forceInit() {
return this.cluster.initCluster()
}
async prove(stuff:any) {
if (this.cluster.hasProofPending) {
await this.cluster.cancelWork()
}
const cpus = os.cpus()
if (os.arch().match(/arm/) || cpus[0].model.match(/Atom/)) {
stuff.newPoW.conf.nbCores /= 2; // Make sure that only once each physical core is used (for Hyperthreading).
}
return await this.cluster.proveByWorkers(stuff)
if (this.cluster.hasProofPending) {
await this.cluster.cancelWork()
}
const cpus = os.cpus()
if (os.arch().match(/arm/) || cpus[0].model.match(/Atom/)) {
stuff.newPoW.conf.nbCores /= 2; // Make sure that only once each physical core is used (for Hyperthreading).
}
return await this.cluster.proveByWorkers(stuff)
}
cancel() {
......@@ -51,6 +48,9 @@ export class PowEngine {
}
setConf(value:any) {
if (os.arch().match(/arm/) && value.cpu !== undefined) {
value.cpu /= 2; // Don't know exactly why is ARM so much saturated by PoW, so let's divide by 2
}
return this.cluster.changeConf(value)
}
......
......@@ -195,6 +195,7 @@ export class Master {
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,
......
......@@ -6,11 +6,15 @@ import {ProverConstants} from "./constants"
import {KeyGen} from "../../../lib/common-libs/crypto/keyring"
import {dos2unix} from "../../../lib/common-libs/dos2unix"
import {rawer} from "../../../lib/common-libs/index"
import {ProcessCpuProfiler} from "../../../ProcessCpuProfiler"
const moment = require('moment');
const querablep = require('querablep');
const PAUSES_PER_TURN = 5;
// This value can be changed
let TURN_DURATION_IN_MILLISEC = 100;
let computing = querablep(Promise.resolve(null));
let askedStop = false;
......@@ -86,6 +90,7 @@ function beginNewProofOfWork(stuff:any) {
prefix *= 100 * ProverConstants.NONCE_RANGE
}
const highMark = stuff.highMark;
const turnDuration = stuff.turnDuration || TURN_DURATION_IN_MILLISEC
let sigFunc = null;
if (signatureFunc && lastSecret === pair.sec) {
sigFunc = signatureFunc;
......@@ -103,17 +108,13 @@ function beginNewProofOfWork(stuff:any) {
let testsCount = 0;
let found = false;
let score = 0;
let turn = 0;
const profiler = new ProcessCpuProfiler(100)
let cpuUsage = profiler.cpuUsageOverLastMilliseconds(1)
// We limit the number of tests according to CPU usage
let testsPerRound = 1
let turnDuration = 20 // We initially goes quickly to the max speed = 50 reevaluations per second (1000 / 20)
while (!found && !askedStop) {
/*****************
* A TURN ~ 100ms
* A TURN
****************/
await Promise.race([
......@@ -124,9 +125,26 @@ function beginNewProofOfWork(stuff:any) {
// II. Process the turn's PoW
(async () => {
/*****************
* A TURN OF POW ~= 100ms by default
* --------------------
*
* The concept of "turn" is required to limit the CPU usage.
* We need a time reference to have the speed = nb tests / period of time.
* Here we have:
*
* - speed = testsCount / turn
*
* We have taken 1 turn = 100ms to control the CPU usage after 100ms of PoW. This means that during the
* very first 100ms of the PoW, CPU usage = 100%. Then it becomes controlled to the %CPU set.
****************/
// Prove
let i = 0;
const thisTurn = turn;
const pausePeriod = score ? score / PAUSES_PER_TURN : 10; // number of pauses per turn
// We limit the number of tests according to CPU usage
const testsPerRound = score ? Math.floor(score * currentCPU) : 1000 * 1000 * 1000
// Time is updated regularly during the proof
block.time = getBlockTime(block, conf, forcedTime)
......@@ -178,7 +196,7 @@ function beginNewProofOfWork(stuff:any) {
if (!found && !askedStop) {
i++;
testsCount++;
if (i % testsPerRound === 0) {
if (i % pausePeriod === 0) {
await countDown(0); // Very low pause, just the time to process eventual end of the turn
}
}
......@@ -190,24 +208,12 @@ function beginNewProofOfWork(stuff:any) {
if (!found) {
// CPU speed recording
if (turn > 0) {
const oldTestsPerRound = testsPerRound
cpuUsage = profiler.cpuUsageOverLastMilliseconds(turnDuration)
if (cpuUsage > currentCPU + 0.005 || cpuUsage < currentCPU - 0.005) {
let powVariationFactor
// powVariationFactor = currentCPU / (cpuUsage || 0.01) / 5 // divide by 2 to avoid extreme responses
if (currentCPU > cpuUsage) {
powVariationFactor = 1.01
testsPerRound = Math.max(1, Math.ceil(testsPerRound * powVariationFactor))
} else {
powVariationFactor = 0.99
testsPerRound = Math.max(1, Math.floor(testsPerRound * powVariationFactor))
}
}
if (turn > 0 && !score) {
score = testsCount;
}
/*****************
* UNLOAD CPU CHARGE FOR THIS TURN
* UNLOAD CPU CHARGE
****************/
// We wait for a maximum time of `turnDuration`.
// This will trigger the end of the turn by the concurrent race I. During that time, the proof.js script
......@@ -220,9 +226,6 @@ function beginNewProofOfWork(stuff:any) {
// Next turn
turn++
turnDuration += 1
turnDuration = Math.min(turnDuration, 1000) // Max 1 second per turn
}
/*****************
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment