22//!
33//! This module manages pass registration, dependency resolution,
44//! and execution in the correct order using topological sorting.
5+ //! Supports optional per-pass performance profiling via --perf-stats flag.
56
67const std = @import ("std" );
78const Allocator = std .mem .Allocator ;
@@ -12,6 +13,7 @@ const DiagnosticWriter = @import("pass.zig").DiagnosticWriter;
1213const PassKind = @import ("pass.zig" ).PassKind ;
1314const FactStore = @import ("../fact/store.zig" ).FactStore ;
1415const QueryEngine = @import ("../fact/query.zig" ).QueryEngine ;
16+ const profiler = @import ("../perf/profiler.zig" );
1517
1618/// Dependency resolution error
1719pub const DependencyError = error {
@@ -26,6 +28,8 @@ pub const PassManager = struct {
2628 pass_map : std .StringHashMap (usize ), // name -> index
2729 resolved_order : ? []usize , // indices in execution order
2830 execution_names : ? []const []const u8 , // cached pass names in order
31+ perf_stats : bool = false , // Enable per-pass performance profiling
32+ pass_stats_collector : ? profiler.PassStatsCollector = null , // Collected statistics
2933
3034 const PassEntry = struct {
3135 name : []const u8 ,
@@ -53,6 +57,10 @@ pub const PassManager = struct {
5357 if (self .resolved_order ) | order | {
5458 self .allocator .free (order );
5559 }
60+ if (self .pass_stats_collector ) | * collector | {
61+ collector .deinit ();
62+ self .pass_stats_collector = null ;
63+ }
5664 self .pass_map .deinit ();
5765 self .passes .deinit (self .allocator );
5866 }
@@ -195,16 +203,40 @@ pub const PassManager = struct {
195203 _ = try self .resolveDependencies ();
196204 }
197205
206+ // Initialize stats collector if profiling is enabled
207+ if (self .perf_stats ) {
208+ self .pass_stats_collector = profiler .PassStatsCollector .init (self .allocator );
209+ }
210+
198211 // Execute in resolved order with graceful degradation (v0.1.6)
199212 var pass_failures : usize = 0 ;
200213 for (self .resolved_order .? ) | idx | {
201214 const pass_name = self .passes .items [idx ].name ;
215+
216+ // Per-pass timing and memory sampling (only when enabled)
217+ var pass_timer : ? profiler.PassTimer = null ;
218+ if (self .perf_stats ) {
219+ pass_timer = profiler .PassTimer .startPass () catch null ;
220+ }
221+
202222 const t0 = std .time .nanoTimestamp ();
203223 self .passes .items [idx ].run_fn (ctx , diag ) catch | err | {
204224 diag .warn ("PassManager: pass '{s}' failed with error: {any}, degrading gracefully" , .{ pass_name , err });
205225 pass_failures += 1 ;
206226 // Continue running remaining passes
207227 };
228+
229+ // Record per-pass statistics
230+ if (self .perf_stats and pass_timer != null ) {
231+ if (pass_timer ) | * timer | {
232+ if (timer .stopPass (pass_name )) | stats | {
233+ if (self .pass_stats_collector ) | * collector | {
234+ collector .record (stats ) catch {};
235+ }
236+ } else | _ | {}
237+ }
238+ }
239+
208240 // Early exit: no FFI boundaries found, skip remaining heavy passes
209241 if (ctx .early_exit ) {
210242 diag .info ("PassManager: early exit after '{s}' — no FFI boundaries, remaining passes skipped" , .{pass_name });
@@ -217,11 +249,33 @@ pub const PassManager = struct {
217249 }
218250 }
219251
252+ // Print performance report if profiling was enabled
253+ if (self .perf_stats ) {
254+ if (self .pass_stats_collector ) | * collector | {
255+ collector .printReport (true );
256+ }
257+ }
258+
220259 if (pass_failures > 0 ) {
221260 diag .info ("PassManager: completed with {} degraded passes out of {}" , .{ pass_failures , self .resolved_order .? .len });
222261 }
223262 }
224263
264+ /// Enable or disable per-pass performance profiling
265+ /// Must be called before run()
266+ pub fn setPerfStats (self : * PassManager , enabled : bool ) void {
267+ self .perf_stats = enabled ;
268+ }
269+
270+ /// Get the collected pass statistics (for programmatic access)
271+ /// Returns null if profiling was not enabled or no data collected
272+ pub fn getPassStats (self : * const PassManager ) ? []const profiler.PassStats {
273+ if (self .pass_stats_collector ) | * collector | {
274+ return collector .stats .items ;
275+ }
276+ return null ;
277+ }
278+
225279 /// Get the number of registered passes
226280 pub fn count (self : * const PassManager ) usize {
227281 return self .passes .items .len ;
0 commit comments