Skip to content

perf functions getEntriesByName and getEntriesByType seem to have unnecessarily bad performance #42004

Closed
@tomjw64

Description

@tomjw64

Version

v16.14.0

Platform

Linux 5.13.0-28-generic #31~20.04.1-Ubuntu SMP Wed Jan 19 14:08:10 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

internal/lib/perf

What steps will reproduce the bug?

// slow.js
let iter = 0

const getEntries = process.argv[2] === 'name'
  ? () => performance.getEntriesByName('x')
  : () => performance.getEntriesByType('measure')

while (++iter <= process.argv[3]) {
  performance.mark('x')
  performance.mark('y')
  performance.measure('x', 'x', 'y')
  getEntries()
}
console.log(getEntries().length)
// fast.js
let iter = 0
let entries = {
  mark: {},
  measure: {}
}

const getEntriesByType = (type) => [].concat(...Object.values(entries[type]))
const getEntriesByName = (name) => entries.mark[name].concat(entries.measure[name])
const mark = (name) => {
  if (!entries.mark[name]) { entries.mark[name] = [] }
  entries.mark[name].push(performance.mark(name))
}
const measure = (name, start, end) => {
  if (!entries.measure[name]) { entries.measure[name] = [] }
  entries.measure[name].push(performance.measure(name, start, end))
}

const getEntries = process.argv[2] === 'name'
  ? () => getEntriesByName('x')
  : () => getEntriesByType('measure')

while (++iter <= process.argv[3]) {
  mark('x')
  mark('y')
  measure('x', 'x', 'y')
  getEntries()
}
console.log(getEntries().length)
$ time node slow.js name 10000
20000

real	0m15.021s
user	0m14.930s
sys	0m0.196s
$ time node slow.js type 10000
10000

real	0m7.476s
user	0m7.482s
sys	0m0.020s
$ time node fast.js name 10000
20000

real	0m0.188s
user	0m0.117s
sys	0m0.117s
$ time node fast.js type 10000
10000

real	0m0.083s
user	0m0.107s
sys	0m0.009s

How often does it reproduce? Is there a required condition?

Lots of marks or measures must be present to see a noticeable difference in performance. Additionally, the name parameter for the getEntriesByName function must be for a entry name that exists in the buffers, as far as I can tell.

What is the expected behavior?

No response

What do you see instead?

getEntriesByName and getEntriesByType take significantly longer than a naive entry tracking solution using object key lookups and concatenation.

Additional information

kMaxPerformanceEntryBuffers makes clear that no more than 1000000 entries should be present. Maybe that implies that the performance expectations for these functions should not be high and that users should be expected to regularly clear entries instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    perf_hooksIssues and PRs related to the implementation of the Performance Timing API.performanceIssues and PRs related to the performance of Node.js.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions