-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support query for output record derivation trace. #725
base: master
Are you sure you want to change the base?
Conversation
3f97622
to
3d7ec5c
Compare
debugger/Main.hs
Outdated
d''' <- case confOutputInput of | ||
"" -> return d'' | ||
x -> return $ progMirrorInputRelations d'' x | ||
when confDumpFlat $ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to add this option to dump the transformed program in the debugger program. If we want to dump it, we can always use the ddlog binary to do it.
debugger/Main.hs
Outdated
parseProgram Config{..} = do | ||
fdata <- readFile confDatalogFile | ||
(d, _, _) <- parseDatalogProgram (takeDirectory confDatalogFile:confLibDirs) True fdata confDatalogFile | ||
d'' <- case confOutputInternal of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that we have to ensure that we pass the same options when we compiled the ddlog program and here.
Instead of loading the original program here (and ensuring the same options are passed), I wonder if we can just load the dumped transformed source here? I haven't thought about it deeply yet, so not sure if it's possible to generate DatalogProgram from an ast file?
@@ -0,0 +1,179 @@ | |||
{- | |||
Copyright (c) 2018-2020 VMware, Inc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what the convention is for new files, but usually the year here should be the year it was added (i.e., just 2020)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@haroldlim , yep
debugger/Main.hs
Outdated
s = queryAll events (dbgRecordMap recordMap) | ||
putStr $ show s | ||
|
||
queryAll :: [Event] -> DebuggerRecordMap -> String |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, currently the debugger tool will just print/query all derivations of all output records?
Not required for this change, but I wonder if we can make it more interactive (i.e., list out the output records, and then we can specify which output record we want to trace the derivation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for now the debugger tool's function is
queryDerivations :: DebuggerRecord -> DebuggerRecordMap -> DebuggerRecordNode
It takes one output record and debuggerRecordMap (got built when parsing log events) and return the root node of the derivations since the derivation result is a tree like structure.
According to Leonid, we are planning to design a UI that will take the debugger output and then display it in a better way, probably is a next step work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import Language.DifferentialDatalog.Validate | ||
import Language.DifferentialDatalog.Debug | ||
|
||
data TOption = Help |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to copy all flags from the DDlog executable. LibDir
and Help
seem like the only relevant ones.
@@ -51,6 +51,7 @@ data Config = Config { confDatalogFile :: FilePath | |||
, confDumpDebug :: Bool | |||
, confDumpOpt :: Bool | |||
, confReValidate :: Bool | |||
, confDebugDumpFile :: FilePath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debugger should have its own Config type, which should include this field.
@@ -182,12 +183,17 @@ insertRHSInspectDebugHooks d rlIdx rule = | |||
|
|||
debugUpdateRHSRules :: DatalogProgram -> Int -> Rule -> [RuleRHS] | |||
debugUpdateRHSRules d rlIdx rule = | |||
let rhs = debugUpdateRHSRulesWithoutHooks d rlIdx rule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this offline, but just to make sure we're on the same page, with #729 we should not need to perform any kind of preprocessing in the debugger, right?
@@ -0,0 +1,179 @@ | |||
{- | |||
Copyright (c) 2018-2020 VMware, Inc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@haroldlim , yep
type DebuggerRecordMap = M.Map DebuggerRecord [Derivation] | ||
type DebuggerRecordWeightMap = M.Map DebuggerRecord Int | ||
|
||
data OperatorInput = InputOp OperatorId |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment here would be great.
in case traceRecords of | ||
Nothing -> let updatedDbgRecordMap = M.insert outputRecord [derivation] dbgRecordMap | ||
in DebuggerMaps { dbgRecordMap = updatedDbgRecordMap, dbgRecordWeightMap = updatedDbgRecordWeightMap} | ||
Just derivations -> let updatedDbgRecordMap = M.insert outputRecord (derivations ++ [derivation]) dbgRecordMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will introduce duplicate derivations, and because we do not track individual derivation weights, we won't be able to eliminate mutually canceling derivations.
Just derivations -> let updatedDbgRecordMap = M.insert outputRecord (derivations ++ [derivation]) dbgRecordMap | ||
in DebuggerMaps { dbgRecordMap = updatedDbgRecordMap, dbgRecordWeightMap = updatedDbgRecordWeightMap} | ||
|
||
constructRecordMap :: [Event] -> DebuggerMaps -> DatalogProgram -> DebuggerMaps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems nearly identical to handleDebugEvents
.
-- Get the operator if for input records in a debug entry | ||
getPredecessorOpId :: OperatorId -> DatalogProgram-> [OperatorInput] | ||
getPredecessorOpId OperatorId{..} DatalogProgram{..} = | ||
let Rule{..} = progRules !! ruleIdx |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will crash if ruleIdx
is out of range. We should not trust input data. One way to deal with this is to run functions that can fail inside MonadError
. See, e.g., Validate.hs
for examples of this.
if rhsIdx == 0 | ||
then [InputRel (atomRelation rhsAtom)] | ||
else let prevRuleRhs = ruleRHS !! (rhsIdx - 1) | ||
in case prevRuleRhs of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the case analysis here should not be whether prevRuleRhs is a literal or not, but rather whether rhsIdx - 1 == 0
.
_ -> [InputOp OperatorId {ruleIdx = ruleIdx, rhsIdx = (rhsIdx - 1), headIdx = headIdx}, InputRel (atomRelation rhsAtom)] | ||
RHSCondition{..} -> let prevRhsIdx = getPredecessorRHSRuleIdxForCondition rhsIdx ruleRHS | ||
in [InputOp OperatorId {ruleIdx = ruleIdx, rhsIdx = prevRhsIdx, headIdx = headIdx}] | ||
_ -> [InputOp OperatorId {ruleIdx = ruleIdx, rhsIdx = (rhsIdx - 1), headIdx = headIdx}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we want to consider two cases, based on whether rhsIdx - 1 == 0
. If it is then we want InputRel
, otherwise InputOp
3d7ec5c
to
f9c78d7
Compare
1. Add maps to store all debug event entries and extract output record and its input record and store these information. 2. Add helper function to get predecessor operatorId for input record from syntax tree 3. Add tree-like 'DebuggerRecordNode' structure to store all possible derivation results for a given output record with operator id.
f9c78d7
to
0fc2d4f
Compare
and store these information.
for a given output record with operator id.