- Adds DexLimitSteps Command.
- Add ConditionalController, a new DebuggerController type.
- 5 regression tests
- documentation
THE PROBLEM
The default operating behaviour of dexter would step onto every line and gather step information for each of them. This means that, given a large enough test program, dexter would take an undesirable amount of time to run.
This is because dexter would set a break point on every line of the program, step onto each line, repeatedly if within a loop, and attempt to gather step information. Even if no step information is required for a line, the debugger would halt, context switch to dexter, dexter would then attempt to get step info and then move onto the next line.
This is a problem when we have tight loops for example that run thousands of iterations. With an unoptimized binary dexter, a for loop with 100 iterations could take as long as 20/30 seconds to complete.
The debugging information for that for loop shouldn't change during each iteration, so why gather step info for every iteration?
THE SOLUTION
Allow test writers to specify a range of lines in a test program that dexter will conditionally gather step information for. The condition will be predicated on a variable value at run time. If I have a loop counter variable ix, and ix increments up to 100, then specify a range of lines within the loop that we gather step information only when ix is equal to 50, 65 and 90.
Using the DexLimitSteps command, test writers can now write tests that have this behaviour.
DexLimitSteps('ix', 50, 65, 90, from_line='start_of_for', to_line'end_of_for')
This expresses that the test write wishes to only gather step information on the range of lines from start_of_for TO end_of_for when the loop counter variable 'ix' is equal to 50, 65, 90.
Without a DexLimitSteps command to specify a conditional range of lines to step on, the default behaviour would dumbly gather step information for all 100 iterations of the for loop. This is costly in time.
THE IMPLEMENTATION
Given a DexLimitSteps command within a test suite, we then have to 'control' the debugger to carry out these instructions. The old 'default' behaviour that is now encapsulated in the 'DefaultController' of dexter would require heavy modification to work with both behaviours. Much simpler then to create a new class that can carry out the conditional stepping behaviour we desire.
Drum roll please, presenting the 'ConditionalController'
The conditional controller's job is to 'control/pull the strings' of the debugger in order to carry out conditional stepping behaviour. For every 'DexLimitSteps' command in your test program it creates a conditional break point at the start of the range you defined with "from_line='from', to_line='to'".
There maybe multiple conditional breakpoints on a single line, each one testing a different condition for each variable and value combination specified by the 'DexLimitSteps' commands in the test. The conditional checking is handled by the debugger implementation natively as context switching back to dexter to check them on each iteration is slow.
When a conditional break point is hit, we get a list of all the conditional ranges that start on that line. It's not currently possible to check which break point was last hit for both the VS Debugger and LLDB, so instead we have to recheck that the conditionals were hit. As one or more conditional range can start on the same line, we need to check which conditions are true in Dexter in order to set the correct ranges, this is handled my _conditional_met(), probably the hackiest part of this implementation, recommendations on how to spruce this part up are welcomed.
Remember that we only set a conditional break point on the first line on a range. If a conditional bp fires, we then set a range of unconditional break points through out the rest of the range of 'from_line='from' TO to_line='to'. We gather step information for the line the conditional was hit and then continue execution up to the next break point.
Any non-conditional break points on a line we breaked on get deleted immediately before we continue execution.
All this boils down to is a set of lines in a program that the conditional controller gathers step information for IFF the value of a variable is equal to an expected value at runtime.
There is an extra , (in ],[)