From f751010550f07200428ca708afb2ec1d242cf7a7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 4 Jul 2023 20:28:58 +0200 Subject: [PATCH] feat: add minimum and maximum to internal measurements MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- package.json | 2 +- pnpm-lock.yaml | 71 +++++++++++----------- src/pools/abstract-pool.ts | 66 ++++++++++++++++---- src/pools/worker.ts | 10 ++- tests/pools/abstract/abstract-pool.test.js | 55 ++++++++++++++--- 5 files changed, 144 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 903d0c6a..02d47d0e 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "eslint-plugin-promise": "^6.1.1", "eslint-plugin-spellcheck": "^0.0.20", "eslint-plugin-tsdoc": "^0.2.17", - "expect": "^29.5.0", + "expect": "^29.6.0", "husky": "^8.0.3", "lint-staged": "^13.2.3", "microtime": "^3.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55a77126..05a01f43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,8 +72,8 @@ devDependencies: specifier: ^0.2.17 version: 0.2.17 expect: - specifier: ^29.5.0 - version: 29.5.0 + specifier: ^29.6.0 + version: 29.6.0 husky: specifier: ^8.0.3 version: 8.0.3 @@ -434,25 +434,25 @@ packages: engines: {node: '>=8'} dev: true - /@jest/expect-utils@29.5.0: - resolution: {integrity: sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==} + /@jest/expect-utils@29.6.0: + resolution: {integrity: sha512-LLSQQN7oypMSETKoPWpsWYVKJd9LQWmSDDAc4hUQ4JocVC7LAMy9R3ZMhlnLwbcFvQORZnZR7HM893Px6cJhvA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: jest-get-type: 29.4.3 dev: true - /@jest/schemas@29.4.3: - resolution: {integrity: sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==} + /@jest/schemas@29.6.0: + resolution: {integrity: sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@sinclair/typebox': 0.25.24 + '@sinclair/typebox': 0.27.8 dev: true - /@jest/types@29.5.0: - resolution: {integrity: sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==} + /@jest/types@29.6.0: + resolution: {integrity: sha512-8XCgL9JhqbJTFnMRjEAO+TuW251+MoMd5BSzLiE3vvzpQ8RlBxy8NoyNkDhs3K3OL3HeVinlOl9or5p7GTeOLg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/schemas': 29.4.3 + '@jest/schemas': 29.6.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 '@types/node': 20.3.3 @@ -782,8 +782,8 @@ packages: rollup: 3.26.0 dev: true - /@sinclair/typebox@0.25.24: - resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true /@sindresorhus/is@5.4.1: @@ -2653,15 +2653,16 @@ packages: strip-final-newline: 3.0.0 dev: true - /expect@29.5.0: - resolution: {integrity: sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==} + /expect@29.6.0: + resolution: {integrity: sha512-AV+HaBtnDJ2YEUhPPo25HyUHBLaetM+y/Dq6pEC8VPQyt1dK+k8MfGkMy46djy2bddcqESc1kl4/K1uLWSfk9g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/expect-utils': 29.5.0 + '@jest/expect-utils': 29.6.0 + '@types/node': 20.3.3 jest-get-type: 29.4.3 - jest-matcher-utils: 29.5.0 - jest-message-util: 29.5.0 - jest-util: 29.5.0 + jest-matcher-utils: 29.6.0 + jest-message-util: 29.6.0 + jest-util: 29.6.0 dev: true /external-editor@3.1.0: @@ -3677,14 +3678,14 @@ packages: iterate-iterator: 1.0.2 dev: true - /jest-diff@29.5.0: - resolution: {integrity: sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==} + /jest-diff@29.6.0: + resolution: {integrity: sha512-ZRm7cd2m9YyZ0N3iMyuo1iUiprxQ/MFpYWXzEEj7hjzL3WnDffKW8192XBDcrAI8j7hnrM1wed3bL/oEnYF/8w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 diff-sequences: 29.4.3 jest-get-type: 29.4.3 - pretty-format: 29.5.0 + pretty-format: 29.6.0 dev: true /jest-get-type@29.4.3: @@ -3692,36 +3693,36 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /jest-matcher-utils@29.5.0: - resolution: {integrity: sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==} + /jest-matcher-utils@29.6.0: + resolution: {integrity: sha512-oSlqfGN+sbkB2Q5um/zL7z80w84FEAcLKzXBZIPyRk2F2Srg1ubhrHVKW68JCvb2+xKzAeGw35b+6gciS24PHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - jest-diff: 29.5.0 + jest-diff: 29.6.0 jest-get-type: 29.4.3 - pretty-format: 29.5.0 + pretty-format: 29.6.0 dev: true - /jest-message-util@29.5.0: - resolution: {integrity: sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==} + /jest-message-util@29.6.0: + resolution: {integrity: sha512-mkCp56cETbpoNtsaeWVy6SKzk228mMi9FPHSObaRIhbR2Ujw9PqjW/yqVHD2tN1bHbC8ol6h3UEo7dOPmIYwIA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/code-frame': 7.22.5 - '@jest/types': 29.5.0 + '@jest/types': 29.6.0 '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.11 micromatch: 4.0.5 - pretty-format: 29.5.0 + pretty-format: 29.6.0 slash: 3.0.0 stack-utils: 2.0.6 dev: true - /jest-util@29.5.0: - resolution: {integrity: sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==} + /jest-util@29.6.0: + resolution: {integrity: sha512-S0USx9YwcvEm4pQ5suisVm/RVxBmi0GFR7ocJhIeaCuW5AXnAnffXbaVKvIFodyZNOc9ygzVtTxmBf40HsHXaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.5.0 + '@jest/types': 29.6.0 '@types/node': 20.3.3 chalk: 4.1.2 ci-info: 3.8.0 @@ -4842,11 +4843,11 @@ packages: hasBin: true dev: true - /pretty-format@29.5.0: - resolution: {integrity: sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==} + /pretty-format@29.6.0: + resolution: {integrity: sha512-XH+D4n7Ey0iSR6PdAnBs99cWMZdGsdKrR33iUHQNr79w1szKTCIZDVdXuccAsHVwDBp0XeWPfNEoaxP9EZgRmQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/schemas': 29.4.3 + '@jest/schemas': 29.6.0 ansi-styles: 5.2.0 react-is: 18.2.0 dev: true diff --git a/src/pools/abstract-pool.ts b/src/pools/abstract-pool.ts index 283b04d6..ad657b17 100644 --- a/src/pools/abstract-pool.ts +++ b/src/pools/abstract-pool.ts @@ -585,7 +585,16 @@ export abstract class AbstractPool< this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime .aggregate ) { - workerUsage.runTime.aggregate += message.taskPerformance?.runTime ?? 0 + const taskRunTime = message.taskPerformance?.runTime ?? 0 + workerUsage.runTime.aggregate += taskRunTime + workerUsage.runTime.minimum = Math.min( + taskRunTime, + workerUsage.runTime.minimum + ) + workerUsage.runTime.maximum = Math.max( + taskRunTime, + workerUsage.runTime.maximum + ) if ( this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime .average && @@ -616,7 +625,15 @@ export abstract class AbstractPool< this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime .aggregate ) { - workerUsage.waitTime.aggregate += taskWaitTime ?? 0 + workerUsage.waitTime.aggregate += taskWaitTime + workerUsage.waitTime.minimum = Math.min( + taskWaitTime, + workerUsage.waitTime.minimum + ) + workerUsage.waitTime.maximum = Math.max( + taskWaitTime, + workerUsage.waitTime.maximum + ) if ( this.workerChoiceStrategyContext.getTaskStatisticsRequirements() .waitTime.average && @@ -645,17 +662,33 @@ export abstract class AbstractPool< this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu .aggregate ) { - if (workerUsage.elu != null && message.taskPerformance?.elu != null) { + if (message.taskPerformance?.elu != null) { workerUsage.elu.idle.aggregate += message.taskPerformance.elu.idle workerUsage.elu.active.aggregate += message.taskPerformance.elu.active - workerUsage.elu.utilization = - (workerUsage.elu.utilization + - message.taskPerformance.elu.utilization) / - 2 - } else if (message.taskPerformance?.elu != null) { - workerUsage.elu.idle.aggregate = message.taskPerformance.elu.idle - workerUsage.elu.active.aggregate = message.taskPerformance.elu.active - workerUsage.elu.utilization = message.taskPerformance.elu.utilization + if (workerUsage.elu.utilization != null) { + workerUsage.elu.utilization = + (workerUsage.elu.utilization + + message.taskPerformance.elu.utilization) / + 2 + } else { + workerUsage.elu.utilization = message.taskPerformance.elu.utilization + } + workerUsage.elu.idle.minimum = Math.min( + message.taskPerformance.elu.idle, + workerUsage.elu.idle.minimum + ) + workerUsage.elu.idle.maximum = Math.max( + message.taskPerformance.elu.idle, + workerUsage.elu.idle.maximum + ) + workerUsage.elu.active.minimum = Math.min( + message.taskPerformance.elu.active, + workerUsage.elu.active.minimum + ) + workerUsage.elu.active.maximum = Math.max( + message.taskPerformance.elu.active, + workerUsage.elu.active.maximum + ) } if ( this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu @@ -1062,12 +1095,16 @@ export abstract class AbstractPool< }, runTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: new CircularArray() }, waitTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: new CircularArray() @@ -1075,17 +1112,20 @@ export abstract class AbstractPool< elu: { idle: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: new CircularArray() }, active: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: new CircularArray() - }, - utilization: 0 + } } } } diff --git a/src/pools/worker.ts b/src/pools/worker.ts index 93e4eda4..7f9cef0a 100644 --- a/src/pools/worker.ts +++ b/src/pools/worker.ts @@ -65,6 +65,14 @@ export interface MeasurementStatistics { * Measurement aggregate. */ aggregate: number + /** + * Measurement minimum. + */ + minimum: number + /** + * Measurement maximum. + */ + maximum: number /** * Measurement average. */ @@ -87,7 +95,7 @@ export interface MeasurementStatistics { export interface EventLoopUtilizationMeasurementStatistics { readonly idle: MeasurementStatistics readonly active: MeasurementStatistics - utilization: number + utilization?: number } /** diff --git a/tests/pools/abstract/abstract-pool.test.js b/tests/pools/abstract/abstract-pool.test.js index d3a71bc1..d4b147f7 100644 --- a/tests/pools/abstract/abstract-pool.test.js +++ b/tests/pools/abstract/abstract-pool.test.js @@ -463,12 +463,16 @@ describe('Abstract pool test suite', () => { }, runTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) @@ -476,17 +480,20 @@ describe('Abstract pool test suite', () => { elu: { idle: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, active: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) - }, - utilization: 0 + } } }) } @@ -528,12 +535,16 @@ describe('Abstract pool test suite', () => { }, runTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) @@ -541,17 +552,20 @@ describe('Abstract pool test suite', () => { elu: { idle: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, active: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) - }, - utilization: 0 + } } }) } @@ -567,12 +581,16 @@ describe('Abstract pool test suite', () => { }, runTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) @@ -580,17 +598,20 @@ describe('Abstract pool test suite', () => { elu: { idle: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, active: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) - }, - utilization: 0 + } } }) } @@ -620,12 +641,16 @@ describe('Abstract pool test suite', () => { }, runTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) @@ -633,17 +658,20 @@ describe('Abstract pool test suite', () => { elu: { idle: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, active: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) - }, - utilization: 0 + } } }) expect(workerNode.usage.tasks.executed).toBeGreaterThan(0) @@ -661,12 +689,16 @@ describe('Abstract pool test suite', () => { }, runTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) @@ -674,17 +706,20 @@ describe('Abstract pool test suite', () => { elu: { idle: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) }, active: { aggregate: 0, + maximum: 0, + minimum: 0, average: 0, median: 0, history: expect.any(CircularArray) - }, - utilization: 0 + } } }) expect(workerNode.usage.runTime.history.length).toBe(0) -- 2.34.1