-
Notifications
You must be signed in to change notification settings - Fork 407
Expand file tree
/
Copy pathtime-budget.js
More file actions
135 lines (121 loc) · 4.74 KB
/
Copy pathtime-budget.js
File metadata and controls
135 lines (121 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
'use strict'
// @ts-expect-error This code is running in a sandbox where dd-trace is available
require('dd-trace/init')
// @ts-expect-error This code is running in a sandbox where fastify is available
const Fastify = require('fastify')
const {
LARGE_OBJECT_SKIP_THRESHOLD,
// @ts-expect-error This code is running in a sandbox where dd-trace is available
} = require('dd-trace/packages/dd-trace/src/debugger/devtools_client/snapshot/constants')
const fastify = Fastify({ logger: { level: 'error' } })
fastify.get('/deeply-nested-large-object', function handler () {
// The size of `obj` generated is carefully tuned to never result in a snapshot larger than the 1MB size limit, while
// still being large enough to trigger the time budget limit. However, the size of `fastify` and `request` is not
// stable across Node.js and Fastify versions, so the generated object might need to be adjusted.
const obj = generateObject(5, 12) // eslint-disable-line no-unused-vars
const start = process.hrtime.bigint()
const diff = process.hrtime.bigint() - start // BREAKPOINT: /deeply-nested-large-object
return { paused: Number(diff) / 1_000_000 }
})
fastify.get('/object-with-many-properties', function handler () {
const obj = generateObject(0, 1_000_000) // eslint-disable-line no-unused-vars
const start = process.hrtime.bigint()
const diff = process.hrtime.bigint() - start // BREAKPOINT: /object-with-many-properties
return { paused: Number(diff) / 1_000_000 }
})
fastify.get('/large-collections', function handler () {
const arrOfPrimitives = Array.from({ length: 1_000_000 }, (_, i) => i) // eslint-disable-line no-unused-vars
const arrOfObjects = Array.from({ length: 1_000_000 }, (_, i) => ({ i }))
const map = new Map(arrOfObjects.map((obj, i) => [i, obj])) // eslint-disable-line no-unused-vars
const set = new Set(arrOfObjects) // eslint-disable-line no-unused-vars
const start = process.hrtime.bigint()
const diff = process.hrtime.bigint() - start // BREAKPOINT: /large-collections
return { paused: Number(diff) / 1_000_000 }
})
fastify.get('/large-collections-below-size-threshold', function handler () {
// eslint-disable-next-line no-unused-vars
const arrOfPrimitives = Array.from({ length: LARGE_OBJECT_SKIP_THRESHOLD - 1 }, (_, i) => i)
const arrOfObjects = Array.from({ length: LARGE_OBJECT_SKIP_THRESHOLD - 1 }, (_, i) => ({ i }))
const map = new Map(arrOfObjects.map((obj, i) => [i, obj])) // eslint-disable-line no-unused-vars
const set = new Set(arrOfObjects) // eslint-disable-line no-unused-vars
const start = process.hrtime.bigint()
const diff = process.hrtime.bigint() - start // BREAKPOINT: /large-collections-below-size-threshold
return { paused: Number(diff) / 1_000_000 }
})
fastify.listen({ port: process.env.APP_PORT || 0 }, (err) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
process.send?.({ port: fastify.server.address().port })
})
const leafValues = [null, undefined, true, 1, '']
const complexTypes = ['object', 'array', 'map', 'set']
/**
* Generate a complex nested object that requires a lot of async CDP calls to traverse
*
* @param {number} depth
* @param {number} breath
* @returns {Record<string, unknown>}
*/
function generateObject (depth, breath) {
const obj = {}
for (let i = 0; i < breath; i++) {
const key = `p${i}`
if (depth === 0) {
obj[key] = leafValues[i % leafValues.length]
} else {
const type = complexTypes[i % complexTypes.length]
obj[key] = generateType(type, depth - 1, breath)
}
}
return obj
}
function generateArray (depth, breath) {
const arr = []
for (let i = 0; i < breath; i++) {
if (depth === 0) {
arr.push(leafValues[i % leafValues.length])
} else {
const type = complexTypes[i % complexTypes.length]
arr.push(generateType(type, depth - 1, breath))
}
}
return arr
}
function generateMap (depth, breath) {
const map = new Map()
for (let i = 0; i < breath; i++) {
if (depth === 0) {
map.set(i, leafValues[i % leafValues.length])
} else {
const type = complexTypes[i % complexTypes.length]
map.set(i, generateType(type, depth - 1, breath))
}
}
return map
}
function generateSet (depth, breath) {
const set = new Set()
for (let i = 0; i < breath; i++) {
if (depth === 0) {
set.add(leafValues[i % leafValues.length])
} else {
const type = complexTypes[i % complexTypes.length]
set.add(generateType(type, depth - 1, breath))
}
}
return set
}
function generateType (type, depth, breath) {
switch (type) {
case 'object':
return generateObject(depth, breath)
case 'array':
return generateArray(depth, breath)
case 'map':
return generateMap(depth, breath)
case 'set':
return generateSet(depth, breath)
}
}