mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +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) { | 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 { | 	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 { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("wait err %s %d", err, pid) | 			return nil, fmt.Errorf("wait err %s %d", err, pid) | ||||||
| 		} | 		} | ||||||
| 		if wpid == 0 { | 		if wpid == 0 { | ||||||
|  | 			if options&trapWaitNohang != 0 { | ||||||
|  | 				return nil, nil | ||||||
|  | 			} | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		th, ok := dbp.threads[wpid] | 		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) { | 		if (halt && status.StopSignal() == sys.SIGSTOP) || (status.StopSignal() == sys.SIGTRAP) { | ||||||
| 			th.os.running = false | 			th.os.running = false | ||||||
|  | 			if status.StopSignal() == sys.SIGTRAP { | ||||||
|  | 				th.os.setbp = true | ||||||
|  | 			} | ||||||
| 			return th, nil | 			return th, nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -411,7 +429,7 @@ func (dbp *Process) exitGuard(err error) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if status(dbp.pid, dbp.os.comm) == StatusZombie { | 	if status(dbp.pid, dbp.os.comm) == StatusZombie { | ||||||
| 		_, err := dbp.trapWaitInternal(-1, false) | 		_, err := dbp.trapWaitInternal(-1, 0) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -442,14 +460,26 @@ func (dbp *Process) stop(trapthread *Thread) (err error) { | |||||||
| 	if dbp.exited { | 	if dbp.exited { | ||||||
| 		return &proc.ErrProcessExited{Pid: dbp.Pid()} | 		return &proc.ErrProcessExited{Pid: dbp.Pid()} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, th := range dbp.threads { | 	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 { | 			if err := th.stop(); err != nil { | ||||||
| 				return dbp.exitGuard(err) | 				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 { | 		if allstopped { | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		_, err := dbp.trapWaitInternal(-1, true) | 		_, err := dbp.trapWaitInternal(-1, trapWaitHalt) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -475,9 +505,9 @@ func (dbp *Process) stop(trapthread *Thread) (err error) { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// set breakpoints on all threads | 	// set breakpoints on SIGTRAP threads | ||||||
| 	for _, th := range dbp.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 { | 			if err := th.SetCurrentBreakpoint(true); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ type OSSpecificDetails struct { | |||||||
| 	delayedSignal int | 	delayedSignal int | ||||||
| 	registers     sys.PtraceRegs | 	registers     sys.PtraceRegs | ||||||
| 	running       bool | 	running       bool | ||||||
|  | 	setbp         bool | ||||||
| } | } | ||||||
|  |  | ||||||
| func (t *Thread) stop() (err error) { | func (t *Thread) stop() (err error) { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user