@@ -21,7 +21,9 @@ import Strata.Transform.LoopElim
2121import Strata.Transform.ANFEncoder
2222import Strata.Languages.Core.ObligationExtraction
2323public import Strata.Transform.IrrelevantAxioms
24- import Strata.Util.Profile
24+ public import Strata.Pipeline.Messages
25+
26+ open Strata.Pipeline (PipelineContext)
2527
2628---------------------------------------------------------------------
2729
@@ -1021,23 +1023,23 @@ def verifySingleEnv (oblProgram : Program)
10211023 -- irrelevant axiom removal to determine which axioms to prune.
10221024 (axiomProgram : Option Program := .none)
10231025 (externalPhases : List AbstractedPhase := [])
1024- (corePhases : List AbstractedPhase := coreAbstractedPhases) :
1026+ (corePhases : List AbstractedPhase := coreAbstractedPhases)
1027+ (pipelineCtx : Option PipelineContext := none) :
10251028 EIO DiagnosticModel (VCResults × Statistics) := do
10261029 -- Build SMT encoding context from the obligations program itself
10271030 let E ← EIO.ofExcept (Core.buildEnv options oblProgram moreFns (registerCustomFunctions := true ) |>.map (·.1 ))
10281031 let p := E.program
1029- let profile := options.profile
1032+ let pctx ← match pipelineCtx with
1033+ | some ctx => pure ctx
1034+ | none => (PipelineContext.create (outputMode := .quiet) : BaseIO _)
1035+
10301036 -- Extract obligations from the obligations program via ObligationExtraction
10311037 let obligations ← match Core.ObligationExtraction.extractObligations oblProgram with
10321038 | .ok obs => pure obs
10331039 | .error e => .error (DiagnosticModel.fromFormat f!"ObligationExtraction error: {e}" )
10341040 let mut stats : Statistics := ({} : Statistics)
10351041 |>.increment s! "{ Evaluator.Stats.verify_numObligations} " obligations.size
10361042 let mut results := (#[] : VCResults)
1037- let mut preprocessNs : Nat := 0
1038- let mut smtEncodeNs : Nat := 0
1039- let mut solverNs : Nat := 0
1040- let mut peResolvedCount : Nat := 0
10411043 for obligation in obligations do
10421044 -- Determine which checks to perform based on metadata or check mode/amount
10431045 let (satisfiabilityCheck, validityCheck) :=
@@ -1051,10 +1053,8 @@ def verifySingleEnv (oblProgram : Program)
10511053 | .deductive, _ =>
10521054 if obligation.property.passWhenUnreachable then (false , true ) else (true , false )
10531055 | .bugFinding, _ => (true , false )
1054- let t0 ← IO.monoNanosNow
1055- let (obligation, peSatResult?, peValResult?) ← preprocessObligation obligation p options satisfiabilityCheck validityCheck axiomCache axiomNames axiomProgram
1056- let t1 ← IO.monoNanosNow
1057- preprocessNs := preprocessNs + (t1 - t0)
1056+ let (obligation, peSatResult?, peValResult?) ← pctx.withRepeatedPhase "preprocess" do
1057+ preprocessObligation obligation p options satisfiabilityCheck validityCheck axiomCache axiomNames axiomProgram
10581058 -- If evaluator resolved both checks, we're done, unless we always want to generate SMT queries
10591059 if not options.alwaysGenerateSMT then
10601060 if let (some peSat, some peVal) := (peSatResult?, peValResult?) then
@@ -1070,7 +1070,6 @@ def verifySingleEnv (oblProgram : Program)
10701070 let result : VCResult := { obligation, outcome := .ok outcome, verbose := options.verbose,
10711071 checkLevel := options.checkLevel, checkMode := options.checkMode, lexprModel := [] }
10721072 results := results.push result
1073- peResolvedCount := peResolvedCount + 1
10741073 if result.isFailure || result.isImplementationError || result.isTimeout then
10751074 if options.verbose >= .debug then
10761075 let prog := f!"\n\n [DEBUG] Evaluated program:\n {Core.formatProgram p}"
@@ -1080,10 +1079,8 @@ def verifySingleEnv (oblProgram : Program)
10801079 -- Need the solver for at least one check
10811080 let needSatCheck := satisfiabilityCheck && peSatResult?.isNone
10821081 let needValCheck := validityCheck && peValResult?.isNone
1083- let t2 ← IO.monoNanosNow
1084- let maybeTerms := ProofObligation.toSMTTerms E obligation { SMT.Context.default with uniqueBoundNames := options.uniqueBoundNames } options.useArrayTheory
1085- let t3 ← IO.monoNanosNow
1086- smtEncodeNs := smtEncodeNs + (t3 - t2)
1082+ let maybeTerms ← pctx.withRepeatedPhase "smtEncode" do
1083+ pure (ProofObligation.toSMTTerms E obligation { SMT.Context.default with uniqueBoundNames := options.uniqueBoundNames } options.useArrayTheory)
10871084 match maybeTerms with
10881085 | .error err =>
10891086 let result := { obligation,
@@ -1099,12 +1096,10 @@ def verifySingleEnv (oblProgram : Program)
10991096 if options.stopOnFirstError then break
11001097 | .ok (assumptionTerms, varDefs, varDecls, obligationTerm, ctx, encStats) =>
11011098 stats := stats.merge encStats
1102- let t4 ← IO.monoNanosNow
1103- let result ← getObligationResult assumptionTerms obligationTerm ctx obligation p options
1099+ let result ← pctx.withRepeatedPhase "solver" do
1100+ getObligationResult assumptionTerms obligationTerm ctx obligation p options
11041101 counter tempDir needSatCheck needValCheck (externalPhases ++ corePhases)
11051102 (varDefinitions := varDefs) (varDeclarations := varDecls)
1106- let t5 ← IO.monoNanosNow
1107- solverNs := solverNs + (t5 - t4)
11081103 -- Merge evaluator results with solver results
11091104 let result := match result.outcome with
11101105 | .ok solverOutcome =>
@@ -1120,11 +1115,6 @@ def verifySingleEnv (oblProgram : Program)
11201115 let prog := f!"\n\n [DEBUG] Evaluated program:\n {Core.formatProgram p}"
11211116 dbg_trace f!"\n\n Result: {result}\n {prog}"
11221117 if options.stopOnFirstError then break
1123- if profile then
1124- let _ ← (IO.println s! "[profile] Preprocess obligations: { nsToMs preprocessNs} ms" |>.toBaseIO)
1125- let _ ← (IO.println s! "[profile] SMT encoding: { nsToMs smtEncodeNs} ms" |>.toBaseIO)
1126- let _ ← (IO.println s! "[profile] Solver/file writing: { nsToMs solverNs} ms" |>.toBaseIO)
1127- let _ ← (IO.println s! "[profile] Obligations: { obligations.size} total, { peResolvedCount} resolved by evaluator" |>.toBaseIO)
11281118 return (results, stats)
11291119
11301120/-- Run the Strata Core verification pipeline on a program: transform,
@@ -1142,12 +1132,17 @@ def verify (program : Program)
11421132 (externalPhases : List AbstractedPhase := [])
11431133 (prefixPhases : List PipelinePhase := [])
11441134 (keepAllFilesPrefix : Option String := none)
1135+ (pipelineCtx : Option PipelineContext := none)
11451136 : EIO DiagnosticModel VCResults := do
11461137 let profile := options.profile
1138+ let pctx ← match pipelineCtx with
1139+ | some ctx => pure ctx
1140+ | none => (PipelineContext.create (outputMode := .quiet) : BaseIO _)
1141+
11471142 let factory ← EIO.ofExcept (Core.Factory.addFactory moreFns)
11481143 let pipelinePhases := prefixPhases ++ corePipelinePhases (procs := proceduresToVerify) (options := options) (moreFns := moreFns)
11491144 let phases := pipelinePhases.map (·.phase)
1150- let (oblProgram, pipelineStats) ← profileStep profile " Program transformations " do
1145+ let (oblProgram, pipelineStats) ← pctx.withPhase "programTransformations " do
11511146 if let some pfx := keepAllFilesPrefix then
11521147 if let some parent := (System.FilePath.mk pfx).parent then
11531148 IO.toEIO (fun e => DiagnosticModel.fromFormat f!"{e}" )
@@ -1172,23 +1167,17 @@ def verify (program : Program)
11721167 throw e
11731168 .ok (current, state.statistics)
11741169 let allStats := pipelineStats
1175- -- Extract axiom names from the original program. The oblProgram (output of
1176- -- toCoreProofObligationProgram) inlines axioms as assume statements but does
1177- -- not preserve axiom declarations, so we use the pre-transform program for
1178- -- axiom identity.
11791170 let axiomNames := program.decls.filterMap fun decl =>
11801171 match decl with | .ax a _ => some a.name | _ => none
1181- -- Build the axiom relevance cache from the original program (which has
1182- -- axiom declarations). The cache is reused across all obligations.
1183- let axiomCache? ← profileStep profile " Build axiom relevance cache" do
1172+ let axiomCache? ← pctx.withPhase "buildAxiomCache" do
11841173 pure (if options.removeIrrelevantAxioms == .Off then .none
11851174 else .some (IrrelevantAxioms.Cache.build program))
11861175 let counter ← IO.toEIO (fun e => DiagnosticModel.fromFormat f!"{e}" ) (IO.mkRef 0 )
1187- let VCss ← profileStep profile " VC discharge " do
1176+ let VCss ← pctx.withPhase "vcDischarge " do
11881177 if options.checkOnly then
11891178 pure []
11901179 else
1191- pure [← verifySingleEnv oblProgram moreFns options counter tempDir axiomCache? axiomNames (axiomProgram := program) externalPhases phases]
1180+ pure [← verifySingleEnv oblProgram moreFns options counter tempDir axiomCache? axiomNames (axiomProgram := program) externalPhases phases (pipelineCtx := pipelineCtx) ]
11921181 let allStats := VCss.foldl (fun acc (_, s) => acc.merge s) allStats
11931182 if profile then
11941183 let _ ← (IO.println allStats.format |>.toBaseIO)
0 commit comments