Add two simple perf helpers. (#3399)
Can be useful for ad-hoc measure of performance. One is a method
decorator, which can be use on methods like so:
```typescript
@measureDuration
someLongRunningProccess() {
// ....
}
```
And the other offer more granular control. It also returns what the
callback returns, so it can be use in assignments / return statements.
```typescript
return measureCbDuration('sorting took', () => renderingShapes.sort(sortById))
```
### Change Type
<!-- ❗ Please select a 'Scope' label ❗️ -->
- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff
<!-- ❗ Please select a 'Type' label ❗️ -->
- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [x] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-08 13:41:09 +00:00
|
|
|
/** @internal */
|
|
|
|
export function measureCbDuration(name: string, cb: () => any) {
|
|
|
|
const now = performance.now()
|
|
|
|
const result = cb()
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(`${name} took`, performance.now() - now, 'ms')
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @internal */
|
|
|
|
export function measureDuration(_target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
|
|
const originalMethod = descriptor.value
|
|
|
|
descriptor.value = function (...args: any[]) {
|
|
|
|
const start = performance.now()
|
|
|
|
const result = originalMethod.apply(this, args)
|
|
|
|
const end = performance.now()
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(`${propertyKey} took ${end - start}ms `)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
return descriptor
|
|
|
|
}
|
2024-04-09 12:57:46 +00:00
|
|
|
|
|
|
|
const averages = new Map<any, { total: number; count: number }>()
|
|
|
|
|
|
|
|
/** @internal */
|
|
|
|
export function measureAverageDuration(
|
|
|
|
_target: any,
|
|
|
|
propertyKey: string,
|
|
|
|
descriptor: PropertyDescriptor
|
|
|
|
) {
|
|
|
|
const originalMethod = descriptor.value
|
|
|
|
descriptor.value = function (...args: any[]) {
|
|
|
|
const start = performance.now()
|
|
|
|
const result = originalMethod.apply(this, args)
|
|
|
|
const end = performance.now()
|
|
|
|
const length = end - start
|
2024-04-21 11:46:35 +00:00
|
|
|
if (length !== 0) {
|
|
|
|
const value = averages.get(descriptor.value)!
|
|
|
|
const total = value.total + length
|
|
|
|
const count = value.count + 1
|
|
|
|
averages.set(descriptor.value, { total, count })
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(
|
|
|
|
`${propertyKey} took ${(end - start).toFixed(2)}ms | average ${(total / count).toFixed(2)}ms`
|
|
|
|
)
|
|
|
|
}
|
2024-04-09 12:57:46 +00:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
averages.set(descriptor.value, { total: 0, count: 0 })
|
|
|
|
return descriptor
|
|
|
|
}
|