Skip to content

Procedure tracing

Nexus Pascal can instrument physical Win64 x86-64 procedures and write a binary execution trace.

Build the support units

From the nexus-fpc source checkout:

.\packages\nexusprofiler\Build-NexusProfiler.ps1 `
  -Compiler C:/path/to/nxpc-x86_64.exe `
  -RtlUnits C:/path/to/matching/win64/rtl `
  -OutputDirectory $env:TEMP\nexusprofiler

The script builds the compiler-owned tracing support units with the supplied Nexus Pascal compiler and matching Win64 RTL. Supply both paths explicitly; the helper's defaults describe an older in-tree compiler layout. Install the resulting units on the compiler unit path. Clang and LLD must be available on PATH.

Build a profiled program

Add -profile to the normal Nexus Pascal command line:

nxpc -profile -Aas-clang -XLL program.pas

No profiling unit, source annotation, or external profiler DLL is required. The compiler links the tracing runtime into the executable.

Removing -profile and rebuilding produces an ordinary binary without profiling imports or .nxprof metadata.

Start and stop capture

Profiling starts active by default. Set the environment variable below before launching an instrumented process to start it paused:

NEXUS_PROFILE_START=paused

The runtime creates a hidden top-level window with class NexusFPCProfilerControl and title NexusFPCProfiler-<process-id>. A controller uses RegisterWindowMessage for these names and sends the resulting messages to that window:

NexusFPCProfiler.Start
NexusFPCProfiler.Stop

Stop immediately disables new capture, discards events and completed calls that have not yet reached disk, resets the worker's call stacks, writes TRACE_END, and closes the current trace. Start opens a fresh trace, writes its metadata, and then enables capture. Each active interval therefore produces one independent .nxtrace file. While capture is paused, generated hook calls return before timestamp, thread-state, and event-memory work.

Trace output

A profiled executable writes this file in its current directory:

nexus-profile-<process-id>-<startup-counter>.nxtrace

The trace records module, procedure and thread information, completed-call durations, caller relationships and normal/unwind return kinds. Incomplete captures can contain gaps or unmatched events; the importer reports them.

Inspect a trace

NexusProfilerImport imports Nexus Pascal .nxtrace traces into SQLite for direct analysis with SQLite tools.

The executable uses Nexus SQLite and requires SQLite 3.53.4 or newer. Use the matching sqlite3.dll from the Nexus SQLite runtime, placing it beside the executable or making it discoverable through PATH. Replace older copies beside the executable, which take precedence over PATH.

NexusProfilerImport import <database.sqlite> <trace-or-directory> [-run <name>]

A directory import is recursive. Every new input/run combination creates one nxp_run; all trace files discovered under the input path belong to that run. Retries reuse that run.

Import progress is committed atomically to SQLite every 64 MiB of processed trace data. Running the same command again resumes each unfinished trace from its last checkpoint. The default run name is the expanded input path so it is stable across retries. When -run is supplied, use the same name to resume. Checkpoint state is stored only in SQLite; there is no external checkpoint log.

The database preserves metadata and completed calls in the nxp_* tables and materializes procedure totals and call edges during import. Useful views are:

  • v_nxp_hotspots: totals across every trace in a run;
  • v_nxp_procedure_totals: per-trace procedure totals;
  • v_nxp_call_edges: caller/callee totals;
  • v_nxp_trace_summary: trace completeness, event counts, and issue counts.

For example:

select name, unit_name, calls, self_seconds, inclusive_seconds
from v_nxp_hotspots
order by self_seconds desc
limit 100;

nxp_import_issue records discontinuities and unmatched terminal events. The importer does not invent durations for incomplete data.