@@ -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+
598605def 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