gh-141999: Handle KeyboardInterrupt when sampling in the new tachyon profiler (#142000)

This commit is contained in:
yihong 2025-11-30 10:49:13 +08:00 committed by GitHub
parent ea51e745c7
commit 056d6c5ed9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 85 additions and 37 deletions

View file

@ -57,50 +57,56 @@ def sample(self, collector, duration_sec=10):
last_sample_time = start_time
realtime_update_interval = 1.0 # Update every second
last_realtime_update = start_time
interrupted = False
while running_time < duration_sec:
# Check if live collector wants to stop
if hasattr(collector, 'running') and not collector.running:
break
current_time = time.perf_counter()
if next_time < current_time:
try:
stack_frames = self.unwinder.get_stack_trace()
collector.collect(stack_frames)
except ProcessLookupError:
duration_sec = current_time - start_time
try:
while running_time < duration_sec:
# Check if live collector wants to stop
if hasattr(collector, 'running') and not collector.running:
break
except (RuntimeError, UnicodeDecodeError, MemoryError, OSError):
collector.collect_failed_sample()
errors += 1
except Exception as e:
if not self._is_process_running():
current_time = time.perf_counter()
if next_time < current_time:
try:
stack_frames = self.unwinder.get_stack_trace()
collector.collect(stack_frames)
except ProcessLookupError:
duration_sec = current_time - start_time
break
raise e from None
except (RuntimeError, UnicodeDecodeError, MemoryError, OSError):
collector.collect_failed_sample()
errors += 1
except Exception as e:
if not self._is_process_running():
break
raise e from None
# Track actual sampling intervals for real-time stats
if num_samples > 0:
actual_interval = current_time - last_sample_time
self.sample_intervals.append(
1.0 / actual_interval
) # Convert to Hz
self.total_samples += 1
# Track actual sampling intervals for real-time stats
if num_samples > 0:
actual_interval = current_time - last_sample_time
self.sample_intervals.append(
1.0 / actual_interval
) # Convert to Hz
self.total_samples += 1
# Print real-time statistics if enabled
if (
self.realtime_stats
and (current_time - last_realtime_update)
>= realtime_update_interval
):
self._print_realtime_stats()
last_realtime_update = current_time
# Print real-time statistics if enabled
if (
self.realtime_stats
and (current_time - last_realtime_update)
>= realtime_update_interval
):
self._print_realtime_stats()
last_realtime_update = current_time
last_sample_time = current_time
num_samples += 1
next_time += sample_interval_sec
last_sample_time = current_time
num_samples += 1
next_time += sample_interval_sec
running_time = time.perf_counter() - start_time
except KeyboardInterrupt:
interrupted = True
running_time = time.perf_counter() - start_time
print("Interrupted by user.")
# Clear real-time stats line if it was being displayed
if self.realtime_stats and len(self.sample_intervals) > 0:
@ -121,7 +127,7 @@ def sample(self, collector, duration_sec=10):
collector.set_stats(self.sample_interval_usec, running_time, sample_rate, error_rate, mode=self.mode)
expected_samples = int(duration_sec / sample_interval_sec)
if num_samples < expected_samples and not is_live_mode:
if num_samples < expected_samples and not is_live_mode and not interrupted:
print(
f"Warning: missed {expected_samples - num_samples} samples "
f"from the expected total of {expected_samples} "