lib/accy/src/preparation/run.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const choir = @import("choir");
  3 const sys = @import("sys");
  4 
  5 const stage = @import("stage.zig");
  6 const target_profile = @import("target.zig");
  7 
  8 const passes = choir.passes;
  9 
 10 pub const BackendPreparationStats = struct {
 11     pass_runs: u64 = 0,
 12     pass_failures: u64 = 0,
 13     passes_modified: u64 = 0,
 14     analysis_hits: u64 = 0,
 15     analysis_misses: u64 = 0,
 16     analyses_invalidated: u64 = 0,
 17 };
 18 
 19 pub const BackendPreparationFailureKind = passes.PassFailureKind;
 20 
 21 pub const BackendPreparationFailure = struct {
 22     pipeline_name: ?[]const u8 = null,
 23     failure_kind: ?BackendPreparationFailureKind = null,
 24     pass_name: ?[]const u8 = null,
 25     target_op_name: ?[]const u8 = null,
 26     target_symbol_name: ?[]const u8 = null,
 27     verifier_error_name: ?[]const u8 = null,
 28     worker_count: usize = 0,
 29 
 30     pub fn deinit(self: *BackendPreparationFailure, allocator: std.mem.Allocator) void {
 31         if (self.pass_name) |name| allocator.free(name);
 32         if (self.target_op_name) |name| allocator.free(name);
 33         if (self.target_symbol_name) |name| allocator.free(name);
 34         if (self.verifier_error_name) |name| allocator.free(name);
 35         self.* = .{};
 36     }
 37 
 38     pub fn capture(
 39         self: *BackendPreparationFailure,
 40         allocator: std.mem.Allocator,
 41         pipeline_name: []const u8,
 42         reproducer: *const passes.PassFailureReproducer,
 43     ) !void {
 44         self.deinit(allocator);
 45         errdefer self.deinit(allocator);
 46 
 47         self.pipeline_name = pipeline_name;
 48         self.failure_kind = reproducer.failure_kind;
 49         self.worker_count = reproducer.worker_count;
 50         self.pass_name = try dupeOptional(allocator, reproducer.pass_name);
 51         self.target_op_name = try dupeOptional(allocator, reproducer.target_op_name);
 52         self.target_symbol_name = try dupeOptional(allocator, reproducer.target_symbol_name);
 53         self.verifier_error_name = try dupeOptional(allocator, reproducer.verifier_error_name);
 54     }
 55 
 56     fn dupeOptional(allocator: std.mem.Allocator, value: ?[]const u8) !?[]const u8 {
 57         if (value) |text| return try allocator.dupe(u8, text);
 58         return null;
 59     }
 60 };
 61 
 62 pub const BackendPreparationTiming = struct {
 63     inner: passes.TimingInstrumentation,
 64 
 65     pub const TimingOptions: type = passes.PassTimingOptions;
 66     pub const AllocationSnapshot: type = passes.PassAllocationSnapshot;
 67     pub const AllocationSnapshotProvider: type =
 68         passes.PassAllocationSnapshotProvider;
 69 
 70     pub fn init(allocator: std.mem.Allocator) BackendPreparationTiming {
 71         return .{ .inner = passes.TimingInstrumentation.init(allocator) };
 72     }
 73 
 74     pub fn initWithOptions(allocator: std.mem.Allocator, options: TimingOptions) BackendPreparationTiming {
 75         return .{ .inner = passes.TimingInstrumentation.initWithOptions(allocator, options) };
 76     }
 77 
 78     pub fn deinit(self: *BackendPreparationTiming) void {
 79         self.inner.deinit();
 80         self.* = undefined;
 81     }
 82 
 83     fn instrumentation(self: *BackendPreparationTiming) passes.PassInstrumentation {
 84         return self.inner.instrumentation();
 85     }
 86 
 87     pub fn getPassTime(self: *const BackendPreparationTiming, name: []const u8) ?i128 {
 88         return self.inner.getPassTime(name);
 89     }
 90 
 91     pub fn getPassCount(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
 92         return self.inner.getPassCount(name);
 93     }
 94 
 95     pub fn getPassOpCountBefore(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
 96         return self.inner.getPassOpCountBefore(name);
 97     }
 98 
 99     pub fn getPassOpCountAfter(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
100         return self.inner.getPassOpCountAfter(name);
101     }
102 
103     pub fn getPassOpCountDelta(self: *const BackendPreparationTiming, name: []const u8) ?i128 {
104         return self.inner.getPassOpCountDelta(name);
105     }
106 
107     pub fn setAllocationSnapshotProvider(
108         self: *BackendPreparationTiming,
109         provider: ?AllocationSnapshotProvider,
110     ) void {
111         self.inner.setAllocationSnapshotProvider(provider);
112     }
113 
114     pub fn getPassAllocCount(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
115         return self.inner.getPassAllocCount(name);
116     }
117 
118     pub fn getPassFreeCount(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
119         return self.inner.getPassFreeCount(name);
120     }
121 
122     pub fn getPassAllocBytes(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
123         return self.inner.getPassAllocBytes(name);
124     }
125 
126     pub fn getAnalysisTime(self: *const BackendPreparationTiming, name: []const u8) ?i128 {
127         return self.inner.getAnalysisTime(name);
128     }
129 
130     pub fn getAnalysisCount(self: *const BackendPreparationTiming, name: []const u8) ?u64 {
131         return self.inner.getAnalysisCount(name);
132     }
133 
134     pub fn collectsPassIrSizes(self: *const BackendPreparationTiming) bool {
135         return self.inner.collectsPassIrSizes();
136     }
137 };
138 
139 pub const BackendPreparationRunOptions = struct {
140     timing: ?*BackendPreparationTiming = null,
141     failure: ?*BackendPreparationFailure = null,
142     target_profile: ?target_profile.BackendTargetProfile = null,
143     generated_scan_schedules: []const target_profile.GeneratedScanScheduleDecision = &.{},
144     generated_row_pipeline_schedules: []const target_profile.GeneratedRowPipelineScheduleDecision = &.{},
145     tensor: stage.TensorLoweringOptions = .{},
146     now: *const fn () i128 = sys.time.nanoTimestamp,
147 };
148 
149 pub const BackendPreparationRun = struct {
150     total_ns: u64,
151     contract_ns: u64 = 0,
152     tensor_ns: u64 = 0,
153     dispatch_ns: u64 = 0,
154     memory_ns: u64 = 0,
155     kernel_ns: u64 = 0,
156     target_ns: u64 = 0,
157     initial_choir_ops: u64,
158     final_choir_ops: u64,
159     semantic_fingerprint: ?u64 = null,
160     contract_fingerprint: u64 = 0,
161     tensor_fingerprint: u64 = 0,
162     /// A caller reads this field to show whether the dispatch plans of two runs look alike. The
163     /// field holds a 64-bit summary of the plans made by the dispatch stage, zero when the stage
164     /// has not run. It is for display, and no product key or reuse decision reads it.
165     dispatch_fingerprint: u64 = 0,
166     /// A caller reads this field to show whether the memory plans of two runs look alike. The field
167     /// holds a 64-bit summary of the buffer, memory-space and layout plans made by the memory
168     /// stage, zero when the stage has not run. It is for display, and no product key or reuse
169     /// decision reads it.
170     memory_fingerprint: u64 = 0,
171     /// A caller reads this field to show whether the kernel plans of two runs look alike. The field
172     /// holds a 64-bit summary of the kernel outline and generated kernels made by the kernel stage,
173     /// zero when the stage has not run. It is for display, and no product key or reuse decision
174     /// reads it.
175     kernel_fingerprint: u64 = 0,
176     target_fingerprint: u64 = 0,
177     contract_stats: BackendPreparationStats = .{},
178     tensor_stats: BackendPreparationStats = .{},
179     dispatch_stats: BackendPreparationStats = .{},
180     memory_stats: BackendPreparationStats = .{},
181     kernel_stats: BackendPreparationStats = .{},
182     target_stats: BackendPreparationStats = .{},
183     target_profile: ?target_profile.BackendTargetProfile = null,
184 };
185 
186 pub fn addTimingInstrumentation(pm: *passes.PassManager, timing: *BackendPreparationTiming) !void {
187     try pm.addInstrumentation(timing.instrumentation());
188 }
189 
190 pub fn backendPreparationStats(stats: passes.PassManagerStats) BackendPreparationStats {
191     return .{
192         .pass_runs = stats.pass_runs,
193         .pass_failures = stats.pass_failures,
194         .passes_modified = stats.passes_modified,
195         .analysis_hits = stats.analysis_hits,
196         .analysis_misses = stats.analysis_misses,
197         .analyses_invalidated = stats.analyses_invalidated,
198     };
199 }
200 
201 pub fn stageTotal(run: BackendPreparationRun) u64 {
202     return run.contract_ns +|
203         run.tensor_ns +|
204         run.dispatch_ns +|
205         run.memory_ns +|
206         run.kernel_ns +|
207         run.target_ns;
208 }