command (next): Improvements for parallel programs

This patch aims to improve how Delve tracks the current goroutine,
especially in very highly parallel programs. The main spirit of this
patch is to ensure that even in situations where the goroutine we care
about is not executing (common for len(g) > len(m)) we still end up back
on that goroutine as a result of executing the 'next' command.

We accomplish this by tracking our original goroutine id, and any time a
breakpoint is hit or a threads stops, we examine the stopped threads and
see if any are executing the goroutine we care about. If not, we set
'next' breakpoint for them again and continue them. This is done so that
one of those threads can eventually pick up the goroutine we care about
and begin executing it again.
This commit is contained in:
Derek Parker
2015-08-20 09:28:11 -05:00
parent 71845350a0
commit b9846c7684
10 changed files with 205 additions and 74 deletions

View File

@ -130,6 +130,9 @@ func TestHalt(t *testing.T) {
// actually stopped, err will not be nil if the process
// is still running.
for _, th := range p.Threads {
if !th.Stopped() {
t.Fatal("expected thread to be stopped, but was not")
}
if th.running != false {
t.Fatal("expected running = false for thread", th.Id)
}
@ -297,6 +300,36 @@ func TestNextGeneral(t *testing.T) {
testnext("testnextprog", testcases, "main.testnext", t)
}
func TestNextConcurrent(t *testing.T) {
testcases := []nextTest{
{9, 10},
{10, 11},
}
withTestProcess("parallel_next", t, func(p *Process, fixture protest.Fixture) {
_, err := setFunctionBreakpoint(p, "main.sayhi")
assertNoError(err, t, "SetBreakpoint")
assertNoError(p.Continue(), t, "Continue")
f, ln := currentLineNumber(p, t)
initV, err := p.EvalVariable("n")
assertNoError(err, t, "EvalVariable")
for _, tc := range testcases {
if ln != tc.begin {
t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
}
assertNoError(p.Next(), t, "Next() returned an error")
f, ln = currentLineNumber(p, t)
if ln != tc.end {
t.Fatalf("Program did not continue to correct next location expected %d was %s:%d", tc.end, filepath.Base(f), ln)
}
v, err := p.EvalVariable("n")
assertNoError(err, t, "EvalVariable")
if v.Value != initV.Value {
t.Fatal("Did not end up on same goroutine")
}
}
})
}
func TestNextGoroutine(t *testing.T) {
testcases := []nextTest{
{47, 42},