Skip to main content

Analysis Profiling

Unreleased source feature

This guide covers the unreleased source implementation. Check skylos . --help and skylos verify --help in your installed build before using these options.

Use --profile to see where Skylos spends time while checking a repository:

skylos . --danger --profile
skylos src/app.py --format json --profile
skylos verify src/app.py --format json --profile

Profiling measures Skylos's own analysis. It does not run the application or enable tests, call tracing, coverage execution, or a type checker. Those features keep their existing options and execution requirements. Profiling does not change rules, severities, quality-gate thresholds or exit-code policy. Its overhead can make timed work reach an existing limit sooner; that work still reports incomplete rather than passing.

The human profile goes to stderr, including when the report uses JSON on stdout. The json and json-ci scan reports and verify JSON responses also contain a top-level profiling object. To save a standalone profile, use --profile-output; that option enables profiling even without --profile:

skylos . --format json --profile-output profile.json > findings.json

The output directory must already exist, and the profile path must differ from --output so the two artifacts cannot overwrite each other. An unavailable profile output path is an operational error (exit 2), including with --force; the normal report is still rendered when analysis completed. An existing scanner exception is preserved if writing its partial profile also fails.

Read the profile​

The report includes:

  • Phase wall times: elapsed time between the scanner's progress phase markers, including time waiting for workers or subprocesses. Repeated visits to a phase are combined. Work before the first marker is listed as analysis setup.
  • Top cumulative scanner functions: Python functions in Skylos with the most time including child calls. Rows overlap; do not add their times.
  • Top self-time scanner functions: functions with the most time inside the function itself, excluding child calls.
  • Call counts: total calls and, in JSON, primitive calls excluding recursive re-entry.

Function measurements cover the current process and thread. Worker-process, other-thread and subprocess internals are not profiled. Their enclosing phase can still be slow even when the function list does not expose the work inside them. An explicitly requested type check runs separately from this static scanner profile; its elapsed time is reported as type_check.seconds. Calls inside that subprocess are not application or compiler runtime profiles.

Profiling adds overhead, sometimes substantial overhead for code that makes many Python calls. Use the ordinary warm-edit benchmark for latency comparisons; use --profile to locate work that explains those timings. The JSON records this limitation alongside the measured values.

Normal scans profile the main analyzer call, excluding CLI startup, report formatting and uploads. Verify profiles its static verification call, including the separately reported static behavior comparison when enabled.

JSON shape​

The profiling object in a scan report and the standalone file have the same shape:

{
"schema_version": 1,
"kind": "skylos_analysis",
"completed": true,
"wall_seconds": 0.42,
"phases": [
{"name": "analysis setup", "seconds": 0.12, "visits": 1},
{"name": "AI defect scan", "seconds": 0.3, "visits": 1}
],
"functions": {
"by_cumulative": [],
"by_self": []
},
"notes": []
}

Each function row contains file, line, function, calls, primitive_calls, self_seconds and cumulative_seconds. File names refer to scanner source under skylos/. A partial profile has completed: false; its timings do not establish that the requested analysis finished. The profile's completion field describes that profiled call only. Read the report verdict and type_check.status for their own completion and outcome.