Skip to content

Commit ebe24ab

Browse files
committed
Made it to that even if wfbench is ^C-ed, it doesn't leave runaway
processes around
1 parent 8bb70bc commit ebe24ab

1 file changed

Lines changed: 55 additions & 35 deletions

File tree

bin/wfbench

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ class ProcessHandle:
8080
self._proc.terminate()
8181

8282
def terminate_along_with_children(self):
83+
# If it's a multiprocessing, just kill the parent and return
8384
if isinstance(self._proc, multiprocessing.Process):
84-
log_error("Calling terminate_along_with_children() on a multiprocessing.Process is a likely bug")
85+
self._proc.terminate()
8586
return
86-
87+
# If it's a Popen, then do the brute-force thing
8788
try:
8889
parent = psutil.Process(self._proc.pid)
8990
children = parent.children(recursive=True)
@@ -595,6 +596,12 @@ def compute_num_chunks(args):
595596
num_chunks = max(num_chunks, 1) # The above computations may say "zero"
596597
return num_chunks
597598

599+
def kill_current_handles(handles: list[ProcessHandle]):
600+
for handle in handles:
601+
if handle is not None and handle.is_alive():
602+
handle.terminate_along_with_children()
603+
604+
598605
def main():
599606
"""Main program."""
600607
parser = get_parser()
@@ -618,10 +625,10 @@ def main():
618625
core = lock_core(path_locked, path_cores)
619626

620627
if args.time and (not args.cpu_work and not args.gpu_work):
621-
log_error("If --time is provided, then --cpu-work and/or --gpu-work must also be provided.")
628+
log_error("If --time is provided, at least one of --cpu-work and --gpu-work must also be provided.")
622629
sys.exit(1)
623630

624-
# Compute the (feasible) number of chunks
631+
# Compute the (feasible) number of chunks based on the arguments
625632
num_chunks = compute_num_chunks(args)
626633
log_debug(f"Executing benchmark with {num_chunks} chunks.")
627634

@@ -718,39 +725,52 @@ def main():
718725

719726
# All benchmarks have been specified, we can just go through the steps blindly
720727
# log_info(f"Starting {args.name} Benchmark")
721-
for step_index, step in enumerate(steps):
722-
log_debug(f"**** STEP {step_index} ***")
723-
io_read_process = step["io_read_benchmark"].run()
724-
io_write_process = step["io_write_benchmark"].run()
725-
[cpu_benchmark_process, memory_benchmark_process] = step["cpu_benchmark"].run()
726-
gpu_benchmark_process = step["gpu_benchmark"].run()
727-
728-
# If time based, sleep the required amount of time and kill the process
729-
if args.time:
730-
time.sleep(float(args.time) / num_chunks)
728+
729+
current_proc_handles = []
730+
try:
731+
for step_index, step in enumerate(steps):
732+
log_debug(f"**** STEP {step_index} ***")
733+
io_read_process = step["io_read_benchmark"].run()
734+
current_proc_handles += [io_read_process]
735+
io_write_process = step["io_write_benchmark"].run()
736+
[cpu_benchmark_process, memory_benchmark_process] = step["cpu_benchmark"].run()
737+
current_proc_handles += [cpu_benchmark_process, memory_benchmark_process]
738+
gpu_benchmark_process = step["gpu_benchmark"].run()
739+
current_proc_handles += [gpu_benchmark_process]
740+
current_proc_handles[:] = [io_read_process, cpu_benchmark_process, memory_benchmark_process, gpu_benchmark_process]
741+
742+
# If time based, sleep the required amount of time and kill the process
743+
if args.time:
744+
time.sleep(float(args.time) / num_chunks)
745+
if cpu_benchmark_process is not None:
746+
cpu_benchmark_process.terminate_along_with_children()
747+
if gpu_benchmark_process is not None:
748+
gpu_benchmark_process.terminate()
749+
750+
# Wait for the I/O processes to be done
751+
if io_read_process is not None:
752+
io_read_process.wait()
753+
if io_write_process is not None:
754+
io_write_process.wait()
755+
756+
# Wait for the CPU process to be done
731757
if cpu_benchmark_process is not None:
732-
cpu_benchmark_process.terminate_along_with_children()
758+
cpu_benchmark_process.wait()
759+
760+
# Kill the Memory process
761+
if memory_benchmark_process is not None:
762+
memory_benchmark_process.terminate_along_with_children()
763+
memory_benchmark_process.wait()
764+
765+
# Wait for the GPU Process to be done
733766
if gpu_benchmark_process is not None:
734-
gpu_benchmark_process.terminate()
735-
736-
# Wait for the I/O processes to be done
737-
if io_read_process is not None:
738-
io_read_process.wait()
739-
if io_write_process is not None:
740-
io_write_process.wait()
741-
742-
# Wait for the CPU process to be done
743-
if cpu_benchmark_process is not None:
744-
cpu_benchmark_process.wait()
745-
746-
# Kill the Memory process
747-
if memory_benchmark_process is not None:
748-
memory_benchmark_process.terminate_along_with_children()
749-
memory_benchmark_process.wait()
750-
751-
# Wait for the GPU Process to be done
752-
if gpu_benchmark_process is not None:
753-
gpu_benchmark_process.wait()
767+
gpu_benchmark_process.wait()
768+
except KeyboardInterrupt:
769+
log_debug("Detected Keyboard interrupt: cleaning up processes...")
770+
kill_current_handles(current_proc_handles)
771+
sys.exit(1)
772+
finally:
773+
kill_current_handles(current_proc_handles)
754774

755775
# Cleanups
756776
if core:

0 commit comments

Comments
 (0)