Repository: /home/mv/projects/developer-dashboard
Focus: startup performance of the public dashboard command
The public dashboard command is thin by design, but it still matters because it is the most frequently used entrypoint. Profiling shows that the switchboard itself is not the majority of end-to-end time for a normal built-in command. The bigger cost is split between Perl module loading and repeated current-directory resolution, with additional command-specific cost inside the helper process after handoff.
| Probe | Observed Time | Meaning |
|---|---|---|
dashboard version |
about 110 ms average | Special-case fast path. Useful baseline, but not representative of normal helper dispatch. |
dashboard paths |
about 493 ms average | Representative built-in command path through the switchboard and staged helper. |
Direct helper: .../cli/dd/paths |
about 362 ms average | Shows most of the cost is after the public switchboard hands off. |
perl -Ilib -c bin/dashboard |
about 120 ms | Compile/load overhead is a major part of the switchboard cost. |
| Switchboard module load | about 77 ms | Static startup cost from Perl module loading before command work begins. |
| Isolated env/path/helper setup | about 23 ms total | PathRegistry, EnvLoader, and ensure_helpers are not the main cost in isolation. |
The command is thin in architecture, but the real startup path still pays a measurable tax before useful work happens. This matters because users hit dashboard for nearly everything, so even modest startup delays become visible and repetitive friction.
Normal built-in command dispatch is slower than expected because the runtime repeatedly resolves the current working directory and project context, and that cost compounds across both the public switchboard and the helper process.
The command-specific helper runtime is doing enough repeated path recomputation that even a lightweight command such as dashboard paths still feels expensive.
dashboard paths showed /bin/pwd executing 72 times during one command invocation.pwd executions:
Cwd::cwd() on this machine forks /bin/pwd.cwd() averaging about 2.0 ms per call on this machine.paths helper alone took about 212 ms when invoked directly through its Perl module path.cwd() callsThe largest concrete hotspot is repeated Cwd::cwd() use. On this environment, that is not a cheap in-process call. It forks /bin/pwd. That makes otherwise innocent path lookups surprisingly expensive.
PathRegistry methods derive current project roots, runtime layers, state roots, and related values repeatedly. Commands such as dashboard paths ask for many of these values in one call, and that compounds the cwd() overhead.
The switchboard still pays a meaningful Perl compile/load cost before it can decide where to hand off. That cost is not the majority of total runtime for a normal helper path, but it is a large chunk of the public entrypoint overhead.
Developer::Dashboard::CLI::Paths::_build_paths() passes cwd => cwd() into PathRegistry->new(), but PathRegistry does not appear to store or reuse that value. So the helper pays for cwd() but does not gain any caching from it.
EnvLoader by itself is not the primary cost center.InternalCLI::ensure_helpers() is not the primary cost center in isolation.Keep the public dashboard command thin. Do not replace the switchboard design. Instead, reduce repeated startup work, especially current-directory and project-root recomputation.
cwd() calls from the startup and helper path.PathRegistry for cwd, project root, runtime layers, and derived roots.paths for repeated calls into path-derivation methods that can be computed once.bin/dashboard.cwd() CostPathRegistry to accept and actually use a precomputed cwd.cwd() lookups with the cached value wherever the command is operating in one fixed current directory.paths, compute the path inventory once and reuse that data structure rather than calling multiple lazy getters that each recompute upstream state.all_paths() and related accessors for repeated tree walks and repeated state-root creation.use statements behind require when the command path does not always need them.The biggest likely gain is from removing repeated /bin/pwd subprocess calls. Since the trace showed 72 pwd executions for one dashboard paths command, reducing that to one or a small handful should materially reduce wall time. After that, request-local caching should cut the remaining repeated path derivation overhead.
dashboard version and dashboard paths./bin/pwd executions.The public dashboard command is not slow because the switchboard pattern is wrong. It is slow because repeated path discovery work, especially cwd() on this environment, is expensive and occurs many times per invocation. The strongest plan is to keep the architecture, remove repeated cwd/process calls, add request-local path caching, and then trim module startup cost where justified.