Skip to content

Commit 6ad8ad7

Browse files
committed
Wait for interpreter to initialize in subprocess
1 parent 1bf048a commit 6ad8ad7

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

Lib/profile/sample.py

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
from .stack_collector import CollapsedStackCollector
1515

1616
FREE_THREADED_BUILD = sysconfig.get_config_var("Py_GIL_DISABLED") is not None
17+
MAX_STARTUP_ATTEMPTS = 5
18+
STARTUP_RETRY_DELAY_SECONDS = 0.1
19+
1720

1821
class SampleProfiler:
1922
def __init__(self, pid, sample_interval_usec, all_threads):
@@ -538,6 +541,30 @@ def _validate_collapsed_format_args(args, parser):
538541
args.outfile = f"collapsed.{args.pid}.txt"
539542

540543

544+
def wait_for_process_and_sample(process_pid, sort_value, args):
545+
for attempt in range(MAX_STARTUP_ATTEMPTS):
546+
try:
547+
sample(
548+
process_pid,
549+
sort=sort_value,
550+
sample_interval_usec=args.interval,
551+
duration_sec=args.duration,
552+
filename=args.outfile,
553+
all_threads=args.all_threads,
554+
limit=args.limit,
555+
show_summary=not args.no_summary,
556+
output_format=args.format,
557+
realtime_stats=args.realtime_stats,
558+
)
559+
break
560+
except RuntimeError:
561+
if attempt < MAX_STARTUP_ATTEMPTS - 1:
562+
print("Waiting for process to start...")
563+
time.sleep(STARTUP_RETRY_DELAY_SECONDS)
564+
else:
565+
raise RuntimeError("Process failed to start after maximum retries")
566+
567+
541568
def main():
542569
# Create the main parser
543570
parser = argparse.ArgumentParser(
@@ -760,24 +787,7 @@ def main():
760787
process = subprocess.Popen(cmd)
761788

762789
try:
763-
exit_code = process.wait(timeout=0.1)
764-
sys.exit(exit_code)
765-
except subprocess.TimeoutExpired:
766-
pass
767-
768-
try:
769-
sample(
770-
process.pid,
771-
sort=sort_value,
772-
sample_interval_usec=args.interval,
773-
duration_sec=args.duration,
774-
filename=args.outfile,
775-
all_threads=args.all_threads,
776-
limit=args.limit,
777-
show_summary=not args.no_summary,
778-
output_format=args.format,
779-
realtime_stats=args.realtime_stats,
780-
)
790+
wait_for_process_and_sample(process.pid, sort_value, args)
781791
finally:
782792
if process.poll() is None:
783793
process.terminate()

Lib/test/test_sample_profiler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1989,7 +1989,7 @@ def test_cli_empty_module_name(self):
19891989

19901990
self.assertEqual(cm.exception.code, 2) # argparse error
19911991
error_msg = mock_stderr.getvalue()
1992-
self.assertIn("must specify", error_msg)
1992+
self.assertIn("arguments are required: module name", error_msg)
19931993

19941994
def test_cli_long_module_option(self):
19951995
test_args = ["profile.sample", "--module", "mymodule", "arg1"]

0 commit comments

Comments
 (0)