@@ -32,6 +32,22 @@ impl PcStepTimings {
3232 }
3333}
3434
35+ /// Clock for one `pc_step` phase. Disarmed (`None`) on the untimed path, so
36+ /// [`LindbladSpec::pc_step`] pays no `Instant` syscalls.
37+ struct Phase ( Option < Instant > ) ;
38+
39+ impl Phase {
40+ fn start ( timed : bool ) -> Self {
41+ Self ( timed. then ( Instant :: now) )
42+ }
43+
44+ fn stop ( self , slot : & mut u64 ) {
45+ if let Some ( t0) = self . 0 {
46+ * slot = t0. elapsed ( ) . as_micros ( ) as u64 ;
47+ }
48+ }
49+ }
50+
3551/// Compact `basis` / `coeffs` in place: drop entries whose absolute
3652/// coefficient is below `drop_tol` unless the word appears in `protected`.
3753/// No-op when `drop_tol ≤ 0`.
@@ -143,7 +159,7 @@ impl LindbladSpec {
143159 cfg : & PcStepConfig ,
144160 ) -> Result < ( ) , Error > {
145161 self . run_in_pool ( cfg, |this| {
146- this. pc_step_inner ( basis, coeffs, dt, protected, cfg)
162+ this. pc_step_inner ( basis, coeffs, dt, protected, cfg, false )
147163 . map ( |_| ( ) )
148164 } )
149165 }
@@ -160,7 +176,7 @@ impl LindbladSpec {
160176 cfg : & PcStepConfig ,
161177 ) -> Result < PcStepTimings , Error > {
162178 self . run_in_pool ( cfg, |this| {
163- this. pc_step_inner ( basis, coeffs, dt, protected, cfg)
179+ this. pc_step_inner ( basis, coeffs, dt, protected, cfg, true )
164180 } )
165181 }
166182
@@ -187,6 +203,7 @@ impl LindbladSpec {
187203 dt : f64 ,
188204 protected : & [ Word ] ,
189205 cfg : & PcStepConfig ,
206+ timed : bool ,
190207 ) -> Result < PcStepTimings , Error > {
191208 let PcStepConfig {
192209 max_basis,
@@ -209,37 +226,37 @@ impl LindbladSpec {
209226 // coefficients followed by zeros for the newly-added leakage strings.
210227 // We rely on `coeffs` itself as the pre-step buffer for the corrector
211228 // — no `.clone()` is needed because `expm_step` only borrows it.
212- let t0 = Instant :: now ( ) ;
229+ let p = Phase :: start ( timed ) ;
213230 let leak = self . leakage_with_prune ( basis, coeffs, protected, admit, tau_add) ?;
214- t . leakage1_us = t0 . elapsed ( ) . as_micros ( ) as u64 ;
231+ p . stop ( & mut t . leakage1_us ) ;
215232
216- let t0 = Instant :: now ( ) ;
233+ let p = Phase :: start ( timed ) ;
217234 add_leakage_capped ( basis, coeffs, leak, admit) ;
218- t . expand1_us = t0 . elapsed ( ) . as_micros ( ) as u64 ;
235+ p . stop ( & mut t . expand1_us ) ;
219236
220237 // 2. Predictor: `expm_step` reads `coeffs` immutably and returns a
221238 // new owned vector with the predicted state.
222- let t0 = Instant :: now ( ) ;
239+ let p = Phase :: start ( timed ) ;
223240 let coeffs_predict = self . expm_step ( basis, dt, coeffs, drop_tol) ;
224- t . expm1_us = t0 . elapsed ( ) . as_micros ( ) as u64 ;
241+ p . stop ( & mut t . expm1_us ) ;
225242
226243 // 3. Second-hop expansion from the predicted state. After leakage2
227244 // we no longer need `coeffs_predict`. Extend `coeffs` with zeros for
228245 // any newly-added second-hop strings so it remains a valid input
229246 // (pre-step state) for the corrector.
230- let t0 = Instant :: now ( ) ;
247+ let p = Phase :: start ( timed ) ;
231248 let leak2 = self . leakage_with_prune ( basis, & coeffs_predict, protected, admit, tau_add) ?;
232- t . leakage2_us = t0 . elapsed ( ) . as_micros ( ) as u64 ;
249+ p . stop ( & mut t . leakage2_us ) ;
233250 drop ( coeffs_predict) ;
234251
235- let t0 = Instant :: now ( ) ;
252+ let p = Phase :: start ( timed ) ;
236253 add_leakage_capped ( basis, coeffs, leak2, admit) ;
237- t . expand2_us = t0 . elapsed ( ) . as_micros ( ) as u64 ;
254+ p . stop ( & mut t . expand2_us ) ;
238255
239256 // 4. Corrector: redo from pre-step state on the doubly-enlarged basis.
240- let t0 = Instant :: now ( ) ;
257+ let p = Phase :: start ( timed ) ;
241258 * coeffs = self . expm_step ( basis, dt, coeffs, drop_tol) ;
242- t . expm2_us = t0 . elapsed ( ) . as_micros ( ) as u64 ;
259+ p . stop ( & mut t . expm2_us ) ;
243260
244261 // 5. Prune basis entries below `drop_tol` (protected words never dropped).
245262 prune_basis ( basis, coeffs, drop_tol, protected) ;
0 commit comments