Skip to content

Commit

Permalink
feat(cli): add --cpu-prof flag (#2046)
Browse files Browse the repository at this point in the history
* feat(cli): add --cpu-prof flag

* chore: dynamically import profiler

* docs: add debugging guide
  • Loading branch information
astahmer authored Jan 20, 2024
1 parent 9f07fc8 commit f255342
Show file tree
Hide file tree
Showing 10 changed files with 547 additions and 136 deletions.
10 changes: 10 additions & 0 deletions .changeset/little-falcons-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@pandacss/node': patch
'@pandacss/dev': patch
---

Add a `--cpu-prof` flag to `panda`, `panda cssgen`, `panda codegen` and `panda debug` commands This is useful for
debugging performance issues in `panda` itself. This will generate a `panda-{command}-{timestamp}.cpuprofile` file in
the current working directory, which can be opened in tools like [Speedscope](https://www.speedscope.app/)

This is mostly intended for maintainers or can be asked by maintainers to help debug issues.
105 changes: 0 additions & 105 deletions .draft/panda-debug.mdx

This file was deleted.

31 changes: 31 additions & 0 deletions packages/cli/src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
setupConfig,
setupGitIgnore,
setupPostcss,
startProfiling,
writeAnalyzeJSON,
type CssGenOptions,
} from '@pandacss/node'
Expand Down Expand Up @@ -96,11 +97,17 @@ export async function main() {
.option('-w, --watch', 'Watch files and rebuild')
.option('-p, --poll', 'Use polling instead of filesystem events when watching')
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.option('--cpu-prof', 'Generates a `.cpuprofile` to help debug performance issues')
.action(async (flags: CodegenCommandFlags) => {
const { silent, clean, config: configPath, watch, poll } = flags

const cwd = resolve(flags.cwd ?? '')

let stopProfiling: Function = () => void 0
if (flags.cpuProf) {
stopProfiling = await startProfiling(cwd, 'codegen')
}

if (silent) {
logger.level = 'silent'
}
Expand All @@ -126,6 +133,8 @@ export async function main() {
{ cwd, poll },
)
}

stopProfiling()
})

cli
Expand All @@ -143,11 +152,17 @@ export async function main() {
.option('-p, --poll', 'Use polling instead of filesystem events when watching')
.option('-o, --outfile [file]', "Output file for extracted css, default to './styled-system/styles.css'")
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.option('--cpu-prof', 'Generates a `.cpuprofile` to help debug performance issues')
.action(async (maybeGlob?: string, flags: CssGenCommandFlags = {}) => {
const { silent, clean, config: configPath, outfile, watch, poll, minify, minimal, lightningcss } = flags

const cwd = resolve(flags.cwd ?? '')

let stopProfiling: Function = () => void 0
if (flags.cpuProf) {
stopProfiling = await startProfiling(cwd, 'cssgen')
}

const cssArtifact = ['preflight', 'tokens', 'static', 'global', 'keyframes'].find(
(type) => type === maybeGlob,
) as CssArtifactType | undefined
Expand Down Expand Up @@ -206,6 +221,8 @@ export async function main() {
}
})
}

stopProfiling()
})

cli
Expand All @@ -223,17 +240,24 @@ export async function main() {
.option('--hash', 'Hash the generated classnames to make them shorter')
.option('--lightningcss', 'Use `lightningcss` instead of `postcss` for css optimization.')
.option('--emitTokensOnly', 'Whether to only emit the `tokens` directory')
.option('--cpu-prof', 'Generates a `.cpuprofile` to help debug performance issues')
.action(async (files: string[], flags: MainCommandFlags) => {
const { config: configPath, silent, ...rest } = flags

const cwd = resolve(flags.cwd ?? '')

let stopProfiling: Function = () => void 0
if (flags.cpuProf) {
stopProfiling = await startProfiling(cwd, 'cli')
}

if (silent) {
logger.level = 'silent'
}

const config = compact({ include: files, ...rest, cwd })
await generate(config, configPath)
stopProfiling()
})

cli
Expand Down Expand Up @@ -330,11 +354,17 @@ export async function main() {
.option('--only-config', "Should only output the config file, default to 'false'")
.option('-c, --config <path>', 'Path to panda config file')
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.option('--cpu-prof', 'Generates a `.cpuprofile` to help debug performance issues')
.action(async (maybeGlob?: string, flags: DebugCommandFlags = {}) => {
const { silent, dry = false, outdir: outdirFlag, config: configPath } = flags ?? {}

const cwd = resolve(flags.cwd!)

let stopProfiling: Function = () => void 0
if (flags.cpuProf) {
stopProfiling = await startProfiling(cwd, 'debug')
}

if (silent) {
logger.level = 'silent'
}
Expand All @@ -348,6 +378,7 @@ export async function main() {
const outdir = outdirFlag ?? join(...ctx.paths.root, 'debug')

await debug(ctx, { outdir, dry, onlyConfig: flags.onlyConfig })
stopProfiling()
})

cli
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface CssGenCommandFlags {
config?: string
minify?: boolean
lightningcss?: boolean
cpuProf?: boolean
}

export interface StudioCommandFlags extends Pick<Config, 'cwd'> {
Expand All @@ -45,6 +46,7 @@ export interface DebugCommandFlags {
cwd?: string
config?: string
onlyConfig?: boolean
cpuProf?: boolean
}

export interface ShipCommandFlags {
Expand All @@ -61,6 +63,7 @@ export interface CodegenCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watc
clean?: boolean
silent?: boolean
config?: string
cpuProf?: boolean
}

export interface MainCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watch'> {
Expand All @@ -74,4 +77,5 @@ export interface MainCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watch'>
hash?: boolean
emitTokensOnly?: boolean
lightningcss?: boolean
cpuProf?: boolean
}
3 changes: 2 additions & 1 deletion packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
"prettier": "^2.8.8",
"ts-morph": "19.0.0",
"ts-pattern": "5.0.5",
"tsconfck": "^2.1.2"
"tsconfck": "^2.1.2",
"v8-profiler-next": "^1.10.0"
},
"devDependencies": {
"@types/fs-extra": "11.0.4",
Expand Down
33 changes: 33 additions & 0 deletions packages/node/src/cpu-profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { logger } from '@pandacss/logger'
import fs from 'fs'
import path from 'path'

export const startProfiling = async (cwd: string, prefix: string) => {
const v8Profiler = (await import('v8-profiler-next')).default
const date = new Date()
const timestamp = date.toISOString().replace(/[-:.]/g, '')
const title = `panda-${prefix}-${timestamp}`

// set generateType 1 to generate new format for cpuprofile
// to be compatible with cpuprofile parsing in vscode.
v8Profiler.setGenerateType(1)
v8Profiler.startProfiling(title, true)

const stopProfiling = () => {
const profile = v8Profiler.stopProfiling(title)
profile.export(function (error, result) {
if (error) {
console.error(error)
return
}
if (!result) return

const outfile = path.join(cwd, `${title}.cpuprofile`)
fs.writeFileSync(outfile, result)
logger.info('cpu-prof', outfile)
profile.delete()
})
}

return stopProfiling
}
1 change: 1 addition & 0 deletions packages/node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { analyzeTokens, writeAnalyzeJSON } from './analyze-tokens'
export { buildInfo } from './build-info'
export { Builder } from './builder'
export { codegen } from './codegen'
export { startProfiling } from './cpu-profile'
export { loadConfigAndCreateContext } from './config'
export { PandaContext } from './create-context'
export { cssgen, type CssGenOptions } from './cssgen'
Expand Down
Loading

3 comments on commit f255342

@vercel
Copy link

@vercel vercel bot commented on f255342 Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

panda-studio – ./

panda-studio-git-main-chakra-ui.vercel.app
panda-app.vercel.app
panda-studio-chakra-ui.vercel.app

@vercel
Copy link

@vercel vercel bot commented on f255342 Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

panda-docs – ./website

panda-docs-git-main-chakra-ui.vercel.app
panda-docs.vercel.app
panda-docs-chakra-ui.vercel.app
panda-css.com

@vercel
Copy link

@vercel vercel bot commented on f255342 Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.