@jsenv/performance-impact 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/performance-impact",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Report pull request impacts on performance metrics",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -16,8 +16,7 @@
16
16
  "node": ">=14.17.0"
17
17
  },
18
18
  "publishConfig": {
19
- "access": "public",
20
- "registry": "https://registry.npmjs.org"
19
+ "access": "public"
21
20
  },
22
21
  "type": "module",
23
22
  "exports": {
@@ -44,6 +43,7 @@
44
43
  "postpublish": "node ./script/publish/restore_postinstall.mjs"
45
44
  },
46
45
  "dependencies": {
46
+ "@jsenv/dynamic-import-worker": "1.0.0",
47
47
  "@jsenv/filesystem": "2.3.1",
48
48
  "@jsenv/github-pull-request-impact": "1.6.4",
49
49
  "@jsenv/logger": "4.0.1",
@@ -5,13 +5,8 @@ export const assertPerformanceReport = (performanceReport) => {
5
5
  throw new TypeError(`performanceReport must be an object, received ${performanceReport}.`)
6
6
  }
7
7
 
8
- const { groups } = performanceReport
9
- if (typeof groups !== "object" || groups === null) {
10
- throw new TypeError(`performanceReport.groups must be an object, found ${groups}.`)
11
- }
12
-
13
- Object.keys(groups).forEach((groupName) => {
14
- const metrics = groups[groupName]
8
+ Object.keys(performanceReport).forEach((groupName) => {
9
+ const metrics = performanceReport[groupName]
15
10
  assertMetrics(metrics)
16
11
  })
17
12
  }
@@ -13,11 +13,11 @@ export const createPerfImpactComment = ({
13
13
 
14
14
  // here we have are sure beforeMergeData and afterMergeData are valid
15
15
  // because we assert their shape is correct in reportPerformanceImpact.js#collectInfo()
16
- // for the measures that where in before merge but are no longer here, we will ignore them.
17
- // for the measurers that are new we'll show them without doing the diff
16
+ // for metrics here before merge but are no longer in afetr merge, we will ignore them
17
+ // for new metrics we'll show them without doing the diff
18
18
 
19
- const afterMergeGroups = afterMergeData.groups
20
- const beforeMergeGroups = beforeMergeData.groups
19
+ const beforeMergeGroups = beforeMergeData
20
+ const afterMergeGroups = afterMergeData
21
21
 
22
22
  const groupNames = Object.keys(afterMergeGroups)
23
23
  const metricCount = groupNames.reduce((previous, groupName) => {
@@ -5,16 +5,21 @@ export const jsenvFormatGroupSummary = ({ groupName, beforeMergeMetrics, afterMe
5
5
  return `${groupName} (new)`
6
6
  }
7
7
 
8
- const totalImpactRatio = getTotalImpactRatio({ beforeMergeMetrics, afterMergeMetrics })
9
- if (totalImpactRatio === 0) {
8
+ const allRatios = getAllImpactRatios({ beforeMergeMetrics, afterMergeMetrics })
9
+ if (allRatios.length === 0) {
10
10
  return `${groupName} (no impact)`
11
11
  }
12
12
 
13
- return `${groupName} (${formatRatioAsPercentage(totalImpactRatio)})`
13
+ const ratioSum = allRatios.reduce((previous, ratio) => previous + ratio, 0)
14
+ if (ratioSum === 0) {
15
+ return `${groupName} (no impact)`
16
+ }
17
+
18
+ return `${groupName} (${formatRatioAsPercentage(ratioSum)})`
14
19
  }
15
20
 
16
- const getTotalImpactRatio = ({ afterMergeMetrics, beforeMergeMetrics }) => {
17
- let totalRatio = 0
21
+ const getAllImpactRatios = ({ afterMergeMetrics, beforeMergeMetrics }) => {
22
+ let allRatios = []
18
23
  Object.keys(afterMergeMetrics).forEach((metricName) => {
19
24
  const metricBeforeMerge = beforeMergeMetrics[metricName]
20
25
  if (!metricBeforeMerge) {
@@ -33,7 +38,7 @@ const getTotalImpactRatio = ({ afterMergeMetrics, beforeMergeMetrics }) => {
33
38
  : metricValueAfterMerge === 0
34
39
  ? -1
35
40
  : metricDiff / metricValueBeforeMerge
36
- totalRatio += metricDiffRatio
41
+ allRatios.push(metricDiffRatio)
37
42
  })
38
- return totalRatio
43
+ return allRatios
39
44
  }
@@ -8,20 +8,17 @@ export const startMeasures = ({
8
8
  filesystemUsage = false,
9
9
  gc = false,
10
10
  } = {}) => {
11
- const measures = []
12
-
13
- if (gc) {
14
- if (!global.gc) {
15
- v8.setFlagsFromString("--expose_gc")
16
- global.gc = runInNewContext("gc")
17
- emitWarning(`node must be started with --expose-gc`, {
18
- CODE: "EXPOSE_GC_IS_MISSING",
19
- detail: "global.gc forced with v8.setFlagsFromString",
20
- })
21
- }
22
- global.gc()
11
+ if (gc && !global.gc) {
12
+ v8.setFlagsFromString("--expose_gc")
13
+ global.gc = runInNewContext("gc")
14
+ emitWarning(`node must be started with --expose-gc`, {
15
+ CODE: "EXPOSE_GC_IS_MISSING",
16
+ detail: "global.gc forced with v8.setFlagsFromString",
17
+ })
23
18
  }
24
19
 
20
+ const measures = []
21
+
25
22
  if (duration) {
26
23
  const beforeMs = Date.now()
27
24
  measures.push(() => {
@@ -33,17 +30,6 @@ export const startMeasures = ({
33
30
  })
34
31
  }
35
32
 
36
- if (memoryHeapUsage) {
37
- const beforeHeapUsed = memoryUsage().heapUsed
38
- measures.push(() => {
39
- const afterHeapUsed = memoryUsage().heapUsed
40
- const heapUsed = afterHeapUsed - beforeHeapUsed
41
- return {
42
- heapUsed,
43
- }
44
- })
45
- }
46
-
47
33
  if (filesystemUsage) {
48
34
  const beforeRessourceUsage = resourceUsage()
49
35
  measures.push(() => {
@@ -58,11 +44,24 @@ export const startMeasures = ({
58
44
  })
59
45
  }
60
46
 
61
- const stop = () => {
47
+ if (memoryHeapUsage) {
62
48
  if (gc) {
63
49
  global.gc()
64
50
  }
51
+ const beforeHeapUsed = memoryUsage().heapUsed
52
+ measures.push(() => {
53
+ if (gc) {
54
+ global.gc()
55
+ }
56
+ const afterHeapUsed = memoryUsage().heapUsed
57
+ const heapUsed = afterHeapUsed - beforeHeapUsed
58
+ return {
59
+ heapUsed,
60
+ }
61
+ })
62
+ }
65
63
 
64
+ const stop = () => {
66
65
  let metrics = {}
67
66
  measures.forEach((measure) => {
68
67
  metrics = {
@@ -1,64 +0,0 @@
1
- // TODO: This deserves its own npm package
2
-
3
- import { Worker } from "node:worker_threads"
4
- import { existsSync } from "node:fs"
5
- import { fileURLToPath } from "node:url"
6
-
7
- // we use a worker to bypass node cache on dynamic import
8
- const WORKER_COLLECTING_ON_EXPORT_FILE_URL = new URL(
9
- "./worker_collecting_one_export.js",
10
- import.meta.url,
11
- )
12
-
13
- export const collectOneExportFromFile = async (fileUrl) => {
14
- const { hash, urlWithoutHash } = extractHashFromUrl(fileUrl)
15
- if (!hash) {
16
- throw new Error(`no hash found in fileUrl ${fileUrl}`)
17
- }
18
-
19
- const url = urlWithoutHash
20
- const exportName = hash.slice(1)
21
-
22
- const exists = existsSync(fileURLToPath(new URL(url)))
23
- if (!exists) {
24
- throw new Error(`File not found at ${url}`)
25
- }
26
-
27
- const worker = new Worker(WORKER_COLLECTING_ON_EXPORT_FILE_URL, {
28
- workerData: {
29
- url,
30
- exportName,
31
- },
32
- })
33
-
34
- let errorData
35
- let messageData
36
- await new Promise((resolve) => {
37
- worker.once("message", (message) => {
38
- messageData = message
39
- })
40
- worker.once("error", (error) => {
41
- errorData = error
42
- })
43
- worker.once("exit", () => {
44
- resolve()
45
- })
46
- })
47
-
48
- if (errorData) {
49
- const error = new Error(errorData.message)
50
- error.name = errorData.name
51
- error.stack = errorData.stack
52
- throw error
53
- }
54
-
55
- return messageData
56
- }
57
-
58
- const extractHashFromUrl = (url) => {
59
- const urlObject = new URL(url)
60
- const { hash } = urlObject
61
- urlObject.hash = ""
62
- const urlWithoutHash = String(urlObject)
63
- return { hash, urlWithoutHash }
64
- }
@@ -1,17 +0,0 @@
1
- import { parentPort, workerData } from "node:worker_threads"
2
-
3
- const { url, exportName } = workerData
4
- const namespace = await import(url)
5
-
6
- if (!Object.prototype.hasOwnProperty.call(namespace, exportName)) {
7
- throw new Error(`No export named "${exportName}" in ${url}`)
8
- }
9
-
10
- const exportValue = namespace[exportName]
11
- if (typeof exportValue === "function") {
12
- const metrics = await exportValue()
13
- parentPort.postMessage(metrics)
14
- } else {
15
- const metrics = exportValue
16
- parentPort.postMessage(metrics)
17
- }