@@ -18,23 +18,47 @@ require('./remote_config')
18
18
const threadId = parentThreadId === 0 ? `pid:${ process . pid } ` : `pid:${ process . pid } ;tid:${ parentThreadId } `
19
19
const threadName = parentThreadId === 0 ? 'MainThread' : `WorkerThread:${ parentThreadId } `
20
20
21
+ // WARNING: The code above the line `await session.post('Debugger.resume')` is highly optimized. Please edit with care!
21
22
session . on ( 'Debugger.paused' , async ( { params } ) => {
22
23
const start = process . hrtime . bigint ( )
23
- const timestamp = Date . now ( )
24
24
25
25
let captureSnapshotForProbe = null
26
26
let maxReferenceDepth , maxCollectionSize , maxFieldCount , maxLength
27
- const probes = params . hitBreakpoints . map ( ( id ) => {
27
+
28
+ // V8 doesn't allow seting more than one breakpoint at a specific location, however, it's possible to set two
29
+ // breakpoints just next to eachother that will "snap" to the same logical location, which in turn will be hit at the
30
+ // same time. E.g. index.js:1:1 and index.js:1:2.
31
+ // TODO: Investigate if it will improve performance to create a fast-path for when there's only a single breakpoint
32
+ let sampled = false
33
+ const length = params . hitBreakpoints . length
34
+ let probes = new Array ( length )
35
+ for ( let i = 0 ; i < length ; i ++ ) {
36
+ const id = params . hitBreakpoints [ i ]
28
37
const probe = breakpoints . get ( id )
29
- if ( probe . captureSnapshot ) {
38
+
39
+ if ( start - probe . lastCaptureNs < probe . sampling . nsBetweenSampling ) {
40
+ continue
41
+ }
42
+
43
+ sampled = true
44
+ probe . lastCaptureNs = start
45
+
46
+ if ( probe . captureSnapshot === true ) {
30
47
captureSnapshotForProbe = probe
31
48
maxReferenceDepth = highestOrUndefined ( probe . capture . maxReferenceDepth , maxReferenceDepth )
32
49
maxCollectionSize = highestOrUndefined ( probe . capture . maxCollectionSize , maxCollectionSize )
33
50
maxFieldCount = highestOrUndefined ( probe . capture . maxFieldCount , maxFieldCount )
34
51
maxLength = highestOrUndefined ( probe . capture . maxLength , maxLength )
35
52
}
36
- return probe
37
- } )
53
+
54
+ probes [ i ] = probe
55
+ }
56
+
57
+ if ( sampled === false ) {
58
+ return session . post ( 'Debugger.resume' )
59
+ }
60
+
61
+ const timestamp = Date . now ( )
38
62
39
63
let processLocalState
40
64
if ( captureSnapshotForProbe !== null ) {
@@ -56,6 +80,9 @@ session.on('Debugger.paused', async ({ params }) => {
56
80
57
81
log . debug ( `Finished processing breakpoints - main thread paused for: ${ Number ( diff ) / 1000000 } ms` )
58
82
83
+ // Due to the highly optimized algorithm above, the `probes` array might have gaps
84
+ probes = probes . filter ( ( probe ) => ! ! probe )
85
+
59
86
const logger = {
60
87
// We can safely use `location.file` from the first probe in the array, since all probes hit by `hitBreakpoints`
61
88
// must exist in the same file since the debugger can only pause the main thread in one location.
0 commit comments