mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	proc/native/linuc: Better native.Process.stop performance (#1874)
* proc/native/linux: only set breakpoints on threads that receive SIGTRAP * proc/native/linux: do not call (*Thread).Stopped inside (*Process).stop (*Thread).Stopped is slow because it needs to open, read and parse a file in /proc, we don't actually need to do that, we can just rely on the value of Thread.os.running. Benchmark before: BenchmarkConditionalBreakpoints-4 1 12476166303 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 10403533675 ns/op Conditional breakpoint evaluation: 1.24ms -> 1ms Updates #1549
This commit is contained in:
		 Alessandro Arzilli
					Alessandro Arzilli
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							17e70a908e
						
					
				
				
					commit
					e9b2da17cb
				
			| @ -250,16 +250,31 @@ func findExecutable(path string, pid int) string { | ||||
| } | ||||
|  | ||||
| func (dbp *Process) trapWait(pid int) (*Thread, error) { | ||||
| 	return dbp.trapWaitInternal(pid, false) | ||||
| 	return dbp.trapWaitInternal(pid, 0) | ||||
| } | ||||
|  | ||||
| func (dbp *Process) trapWaitInternal(pid int, halt bool) (*Thread, error) { | ||||
| type trapWaitOptions uint8 | ||||
|  | ||||
| const ( | ||||
| 	trapWaitHalt trapWaitOptions = 1 << iota | ||||
| 	trapWaitNohang | ||||
| ) | ||||
|  | ||||
| func (dbp *Process) trapWaitInternal(pid int, options trapWaitOptions) (*Thread, error) { | ||||
| 	halt := options&trapWaitHalt != 0 | ||||
| 	for { | ||||
| 		wpid, status, err := dbp.wait(pid, 0) | ||||
| 		wopt := 0 | ||||
| 		if options&trapWaitNohang != 0 { | ||||
| 			wopt = sys.WNOHANG | ||||
| 		} | ||||
| 		wpid, status, err := dbp.wait(pid, wopt) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("wait err %s %d", err, pid) | ||||
| 		} | ||||
| 		if wpid == 0 { | ||||
| 			if options&trapWaitNohang != 0 { | ||||
| 				return nil, nil | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		th, ok := dbp.threads[wpid] | ||||
| @ -321,6 +336,9 @@ func (dbp *Process) trapWaitInternal(pid int, halt bool) (*Thread, error) { | ||||
| 		} | ||||
| 		if (halt && status.StopSignal() == sys.SIGSTOP) || (status.StopSignal() == sys.SIGTRAP) { | ||||
| 			th.os.running = false | ||||
| 			if status.StopSignal() == sys.SIGTRAP { | ||||
| 				th.os.setbp = true | ||||
| 			} | ||||
| 			return th, nil | ||||
| 		} | ||||
|  | ||||
| @ -411,7 +429,7 @@ func (dbp *Process) exitGuard(err error) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	if status(dbp.pid, dbp.os.comm) == StatusZombie { | ||||
| 		_, err := dbp.trapWaitInternal(-1, false) | ||||
| 		_, err := dbp.trapWaitInternal(-1, 0) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| @ -442,14 +460,26 @@ func (dbp *Process) stop(trapthread *Thread) (err error) { | ||||
| 	if dbp.exited { | ||||
| 		return &proc.ErrProcessExited{Pid: dbp.Pid()} | ||||
| 	} | ||||
|  | ||||
| 	for _, th := range dbp.threads { | ||||
| 		if !th.Stopped() { | ||||
| 		th.os.setbp = false | ||||
| 	} | ||||
| 	trapthread.os.setbp = true | ||||
|  | ||||
| 	// check if any other thread simultaneously received a SIGTRAP | ||||
| 	for { | ||||
| 		th, _ := dbp.trapWaitInternal(-1, trapWaitNohang) | ||||
| 		if th == nil { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// stop all threads that are still running | ||||
| 	for _, th := range dbp.threads { | ||||
| 		if th.os.running { | ||||
| 			if err := th.stop(); err != nil { | ||||
| 				return dbp.exitGuard(err) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// Thread is already in a trace stop but we didn't get the notification yet. | ||||
| 			th.os.running = false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -465,7 +495,7 @@ func (dbp *Process) stop(trapthread *Thread) (err error) { | ||||
| 		if allstopped { | ||||
| 			break | ||||
| 		} | ||||
| 		_, err := dbp.trapWaitInternal(-1, true) | ||||
| 		_, err := dbp.trapWaitInternal(-1, trapWaitHalt) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| @ -475,9 +505,9 @@ func (dbp *Process) stop(trapthread *Thread) (err error) { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// set breakpoints on all threads | ||||
| 	// set breakpoints on SIGTRAP threads | ||||
| 	for _, th := range dbp.threads { | ||||
| 		if th.CurrentBreakpoint.Breakpoint == nil { | ||||
| 		if th.CurrentBreakpoint.Breakpoint == nil && th.os.setbp { | ||||
| 			if err := th.SetCurrentBreakpoint(true); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| @ -16,6 +16,7 @@ type OSSpecificDetails struct { | ||||
| 	delayedSignal int | ||||
| 	registers     sys.PtraceRegs | ||||
| 	running       bool | ||||
| 	setbp         bool | ||||
| } | ||||
|  | ||||
| func (t *Thread) stop() (err error) { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user