session-timeline-profile.ts 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. import type { CDPSession, Page } from "@playwright/test"
  2. export async function startTimelineProfile(page: Page, options: { cpuThrottle: number; profileCPU: boolean }) {
  3. const cdp = await page.context().newCDPSession(page)
  4. if (options.cpuThrottle > 1) await cdp.send("Emulation.setCPUThrottlingRate", { rate: options.cpuThrottle })
  5. if (options.profileCPU) {
  6. await cdp.send("Profiler.enable")
  7. await cdp.send("Profiler.setSamplingInterval", { interval: 100 })
  8. await cdp.send("Profiler.start")
  9. }
  10. return {
  11. async stop() {
  12. if (!options.profileCPU) return
  13. const result = await cdp.send("Profiler.stop")
  14. const self = new Map<number, number>()
  15. result.profile.samples?.forEach((id, index) => {
  16. const duration = (result.profile.timeDeltas?.[index] ?? 0) / 1_000
  17. self.set(id, (self.get(id) ?? 0) + duration)
  18. })
  19. console.log(
  20. "timeline cpu profile",
  21. JSON.stringify(
  22. result.profile.nodes
  23. .map((node) => ({
  24. function: node.callFrame.functionName || "(anonymous)",
  25. url: node.callFrame.url,
  26. line: node.callFrame.lineNumber + 1,
  27. selfMs: self.get(node.id) ?? 0,
  28. }))
  29. .filter((node) => node.selfMs > 1)
  30. .sort((a, b) => b.selfMs - a.selfMs)
  31. .slice(0, 40),
  32. ),
  33. )
  34. },
  35. async reset() {
  36. if (options.cpuThrottle > 1) await cdp.send("Emulation.setCPUThrottlingRate", { rate: 1 })
  37. },
  38. }
  39. }