Revisit built-in Oxlint rule timings using compile-time gating via const generics, so timing instrumentation has no measurable cost on the normal linting path.
This follows from #19745, which tracks JS plugin rule timings, and from the earlier closed PR #19689, where broader per-rule timing support regressed linter benchmarks by ~15%. The goal here is to explore whether native Rust rule timings can be implemented without the normal-path performance cost that made the previous approach unsuitable.
Motivation
When an Oxlint run is unexpectedly slow, contributors and users currently have two options:
- Use external profilers with a
release-with-debug build.
- Manually narrow rule sets to infer which rule is expensive.
External profilers are still the most accurate option, but they are not ergonomic for quick triage. A built-in timing mode would make it much easier to answer:
- Which native rules are consuming the most time?
- Is the slowdown from Oxlint itself, a JS plugin rule, type-aware linting, or project/config shape?
- Which rules should be investigated for performance regressions?
Proposal
Add an opt-in timing mode for native Oxlint rules where the timing decision is encoded as a const generic, for example:
fn run_rules<const TIMING: bool>(...) {
if TIMING {
// timed path
} else {
// normal path
}
}
or through a similarly structured helper / runner split.
The important requirement is that the default path monomorphizes to code with no timing branches, no timer construction, no timing storage, and no synchronization overhead.
This would be exposed at the CLI level.
Expected Behavior
When timing mode is disabled:
- No behavior change.
- No timing table is generated.
- No measurable runtime regression in linter benchmarks.
- No meaningful code size regression in the hot path.
When timing mode is enabled:
- Oxlint records aggregate native rule execution time across all linted files.
- Output includes a human-readable table sorted by total rule time.
- Counts/relative percentages should be clearly defined.
- The timing output should be useful for triage, not necessarily a replacement for profiler-grade analysis.
Example output shape:
Rule Time (ms) Relative
-------------------------------------------------
typescript/no-unused-vars 123.40 31.2%
import/no-cycle 88.10 22.3%
eslint/no-dupe-keys 12.50 3.1%
Prior Art / Context
Revisit built-in Oxlint rule timings using compile-time gating via const generics, so timing instrumentation has no measurable cost on the normal linting path.
This follows from #19745, which tracks JS plugin rule timings, and from the earlier closed PR #19689, where broader per-rule timing support regressed linter benchmarks by ~15%. The goal here is to explore whether native Rust rule timings can be implemented without the normal-path performance cost that made the previous approach unsuitable.
Motivation
When an Oxlint run is unexpectedly slow, contributors and users currently have two options:
release-with-debugbuild.External profilers are still the most accurate option, but they are not ergonomic for quick triage. A built-in timing mode would make it much easier to answer:
Proposal
Add an opt-in timing mode for native Oxlint rules where the timing decision is encoded as a const generic, for example:
or through a similarly structured helper / runner split.
The important requirement is that the default path monomorphizes to code with no timing branches, no timer construction, no timing storage, and no synchronization overhead.
This would be exposed at the CLI level.
Expected Behavior
When timing mode is disabled:
When timing mode is enabled:
Example output shape:
Prior Art / Context
TIMINGenv var #535 originally addedTIMING=1support.--timingsfeature #2049 removed--timingsbecause it bloated code size and native rules could be profiled with Rust tooling.