Trace expression evaluation with command-line TLC
See original GitHub issueGoal
Refactor TLC and Toolbox to make it possible to evaluate trace expressions with command-line TLC. In addition, the functionality should be reusable by third-party tools such as https://github.com/alygin/vscode-tlaplus.
User Experience/Proposal
From the implementation perspective it is easiest to generate SpecTE.tla and SpecTE.cfg (see below for details) when printing the original error trace (at this stage, all relevant information is available in the TLC Java model). A user would write TE.tla (TE extends SpecTE extends Spec) that defines actual trace expressions (e.g. the trace expression foo = tail - head
where tail
and head
are vars of Spec.tla):
------------- MODULE TE -----------
EXTENDS SpecTE
VARIABLE foo
Init2323 == /\ init_15737066180447000
/\ foo = tail - head
Next2323 == /\ next_15737066180448000
/\ foo' = tail - head
=========================
A separate, dedicated module (TE.tla) has the advantage over command-line parameters that it can be checked into SCM and parsing errors can be reported; should we wish to support trace expressions supplied via a command line parameter, this TE.tla file could be generated in memory before SANY parses it.
An IDE such as vscode-tlaplus could generate a template for TE.tla, though it seems like two birds could be killed with one stone by having TLC accept a file that is a list of 1-N trace expressions and from this generate the TE.tla file in addition to the evaluation output. In this manner the user can have the file for SCM and future use, and third party applications / IDEs can be written to collect the trace expressions and provide those to TLC.
Current Toolbox implementation:
Reading regular error trace from MC.out into Toolbox’s error view:
-
Toolbox converts the trace in MC.out into
org.lamport.tla.toolbox.tool.tlc.output.data.TLCState
with an Eclipse based parser.TLCState
and its imports do not depend on Eclipse code. Parsing should be straight forward to re-implemented without Eclipse code. -
Each TLCState gets added to
org.lamport.tla.toolbox.tool.tlc.output.data.TLCError
.TLCError
is little more than a list except that it contains support to do paging of states (used when a trace is exceptionally long). TLCError and its imports have trivial dependencies on Eclipse code which don’t prevent implementation in a non-Eclipse environment. -
Toolbox’s error view gets states via
org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.getStates(Length)
that more or less returns the underlying raw LinkedList.
Toolbox’s error view to TE.tla/TE.cfg:
-
When “Explore” is clicked in the Error-Trace Exploration section,
org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate.buildForLaunch(ILaunchConfiguration, String, IProgressMonitor)
does the following in the.toolbox
directory:- Removes previous TE-related files
- Creates new TE-related files (TE.tla, TA.cfg, …)
- Copies Spec.tla
- Copies extended (either spec or Toolbox’s error view) modules
- Converts the trace in MC_TE.out (which is a copy of MC.out) into a
Vector
ofSimpleTLCState
viaorg.lamport.tla.toolbox.tool.tlc.model.Model.getErrorTrace() TraceExplorerDelegate
- this parsing relies on Eclipse code and, so, will need be re-implemented.
-
The Vector<SimpleTLCState> from 1.5 above, the trace expressions, and the model definitions/constants/… are written to TE.tla and TE.cfg using
org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter
; this class does not depend on Eclipse code. The behavior spec, invariants, properties, constraints from the original model are ignored; it should be noted thatorg.lamport.tla.toolbox.tool.tlc.model.Model
does depends on Eclipse code and would not be easily rewritten.
\* TRACE EXPLORER variable declaration @traceExploreExpressions
VARIABLES __trace_var_157369392033116000
...
\* TRACE NEXT definitiontraceExploreNext
next_157369392168618000 ==
/\ tail = 0
/\ pc = (worker1 :> "deq" @@ worker2 :> "deq" @@ worker3 :> "deq")
/\ disk = <<1>>
/\ head = 1
/\ tail' = 0
/\ pc' = (worker1 :> "casA" @@ worker2 :> "deq" @@ worker3 :> "deq")
/\ disk' = <<1>>
/\ head' = 2
/\ __trace_var_157369392033116000' = 42
...
-
org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate.finalLaunchCheck(ILaunchConfiguration, String, IProgressMonitor)
performs the following:- Parses the set of modules from step (2.); if parsing errors are found, the launch is halted and the errors are presented to the user
- Runs level checking; if level 3 (Temporal) formulae are found, the launch is halted and the user is informed
- Write the trace files again with
TraceExpressionModelWriter
-
org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate.launch(ILaunchConfiguration, String, ILaunch, IProgressMonitor)
performs the following:- Spawns TLC such that it checks for deadlock; this forces it to print an error trace.
Reading error trace with trace expressions from TE.out into Toolbox’s error view:
org.lamport.tla.toolbox.tool.tlc.output.data.TraceExplorerDataProvider
provides the following functionality:#getTraceExpressionsInformation()
extracts the identifier for each trace expression from TE.tla#processTraceForTraceExplorer()
merges the evaluated trace expressions into the originalTLCError
instances (viaTLCError.apply(TLCError, Map<String, Formula>, HashTable<String, TraceExpressionInformationHolder>, String)
.) The new instances ofTLCVariable
which appear in eachTLCState
of the error instance are marked appropriately as being trace explorer expressions.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:74 (72 by maintainers)
f2808bd introduces manpages like help text for TLC; i’ll next apply this to TraceExplorer, then add a flag to TLC for non-monolith-creation.
@will62794 once 7cde038 makes its way into a nightly, please give it a try.
Also, going forward, if there’s no reason not to, just run TLC with
-generateSpecTE
. It automatically turns on-tool
, so there is no need to specify that, and it will not generate a SpecTE if there are no errors encountered.