Implement subprocess termination

This commit is contained in:
2018-08-06 12:27:30 +02:00
parent 49d0569c6b
commit 969776f4ad
3 changed files with 103 additions and 18 deletions

View File

@@ -41,6 +41,7 @@ def benchmarkBlenderWatched(command):
process = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
progress.render_process(process)
# Keep reading status while Blender is alive.
st = stats.Stats()
@@ -67,6 +68,8 @@ def benchmarkBlenderWatched(command):
# Clear line used by progress.
progress.progressClear()
progress.render_process(None)
if process.returncode != 0:
logger.ERROR("Rendering crashed")
return None
@@ -91,6 +94,8 @@ def benchmarkScene(ctx, scene):
"(this might take several minutes).")
warmup_command = command + ['--benchmark-warmup']
benchmarkBlenderWatched(warmup_command)
if progress.is_canceled():
return None
# Remove resutl of warmup round.
if ctx.image_output_dir:
full_image_output = os.path.join(ctx.image_output_dir, scene) + \
@@ -129,6 +134,8 @@ def benchmarkAll(ctx):
for scene in ctx.scenes:
file_stats = benchmarkScene(ctx, scene)
all_stats[scene] = file_stats
if progress.is_canceled():
break
return all_stats

View File

@@ -45,6 +45,12 @@ class DefaultProgressProvider:
def scene_stats(self, scene_name, stats):
pass
def render_process(self, process):
pass
def is_canceled(self):
return False
PROGRESS_PROVIDER = DefaultProgressProvider()
@@ -73,6 +79,12 @@ def scene(scene_name):
def scene_stats(scene_name, stats):
PROGRESS_PROVIDER.scene_stats(scene_name, stats)
def render_process(process):
PROGRESS_PROVIDER.render_process(process)
def is_canceled():
return PROGRESS_PROVIDER.is_canceled()
def setProvider(provider):
"""

View File

@@ -37,6 +37,7 @@ global_result_stats = None
global_result_dict = None
global_background_image_path = ""
global_scene_status = {}
global_cancel = False
images = {}
current_progress = 0.0
progress_lock = Lock()
@@ -207,10 +208,12 @@ class ProgressProviderSink:
current_progress = 0.0
current_step = ''
current_scene = ''
process = None
def __init__(self):
self.current_progress = 0.0
self.current_step = ''
self.process = None
def progress(self, count, total, prefix="", suffix=""):
progress_lock.acquire()
@@ -250,6 +253,13 @@ class ProgressProviderSink:
global_scene_status[scene_name] = "Crashed :("
progress_lock.release()
def render_process(self, process):
self.process = process
def is_canceled(self):
global global_cancel
return global_cancel
class LoggerProviderSink:
def HEADER(self, *args):
@@ -334,9 +344,13 @@ def convert_result_to_json_dict(ctx, results):
def benchmark_thread(ctx):
global progress_lock, global_result_platform, global_progress_status
global global_cancel
progress_lock.acquire()
global_progress_status = "Collecting system information..."
if global_cancel:
progress_lock.release()
return
progress_lock.release()
# This is all system information Blender knows.
@@ -355,9 +369,9 @@ def benchmark_thread(ctx):
progress_lock.acquire()
global_result_platform = construct_platform_string(blender_system_info)
progress_lock.release()
progress_lock.acquire()
if global_cancel:
progress_lock.release()
return
global_progress_status = "Prepating render..."
progress_lock.release()
@@ -372,6 +386,12 @@ def benchmark_thread(ctx):
"stats": all_stats if all_stats else {}
})
progress_lock.acquire()
if global_cancel:
progress_lock.release()
return
progress_lock.release()
global global_result_dict
global_result_dict = result
@@ -503,9 +523,12 @@ class BENCHMARK_OT_run(bpy.types.Operator):
def update_status(self, context):
global global_progress_status, global_background_image_path
global global_cancel
progress_lock.acquire()
step = self.progress_provider.current_step
if step == 'WARM_UP':
if global_cancel:
global_progress_status = "Cancelling..."
elif step == 'WARM_UP':
global_progress_status = "Rendering warm-up pass..."
elif step == 'RUN':
global current_progress
@@ -531,6 +554,7 @@ class BENCHMARK_OT_run(bpy.types.Operator):
def done(self, context):
global global_progress_status, global_result_stats, current_progress
global global_result_dict
wm = context.window_manager
wm.event_timer_remove(self.timer)
# Restore all modifications to the benchmark foundation.
@@ -542,17 +566,21 @@ class BENCHMARK_OT_run(bpy.types.Operator):
self.progress_provider = None
self.logger_provider = None
# Construct final stats string
global global_result_dict
global_result_stats = ""
for stat in global_result_dict["stats"]:
if global_result_stats:
global_result_stats += "\n"
if stat["result"] == "OK":
global_result_stats += "{}: {}" . format(stat["scene_name"],
util.humanReadableTimeDifference(stat["total_render_time"]))
else:
global_result_stats += "{}: {}" . format(stat["scene_name"],
stat["result"])
if global_cancel:
global_result_dict = None
self.init_sate()
else:
global_result_stats = ""
for stat in global_result_dict["stats"]:
if global_result_stats:
global_result_stats += "\n"
if stat["result"] == "OK":
global_result_stats += "{}: {}" . format(stat["scene_name"],
util.humanReadableTimeDifference(
stat["total_render_time"]))
else:
global_result_stats += "{}: {}" . format(stat["scene_name"],
stat["result"])
# TOGO(sergey): Use some more nice picture for the final slide.
global global_background_image_path
global_background_image_path = ""
@@ -569,12 +597,15 @@ class BENCHMARK_OT_run(bpy.types.Operator):
else:
self.done(context)
return {'FINISHED'}
elif event.type == 'ESC':
self.cancel_request(context)
return {'PASS_THROUGH'}
def invoke(self, context, event):
global global_result_platform, global_progress_status
global global_scene_status
global global_scene_status, global_cancel
global_cancel = False
global_result_platform = ""
global_progress_status = "Initializing..."
context.area.tag_redraw()
@@ -616,9 +647,44 @@ class BENCHMARK_OT_run(bpy.types.Operator):
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
def init_sate(self):
global global_result_platform
global global_progress_status
global global_result_stats
global global_result_dict
global global_background_image_path
global global_scene_status
global_result_platform = None
global_progress_status = None
global_result_stats = None
global_result_dict = None
global_background_image_path = ""
global_scene_status = {}
def cancel_request(self, context):
global global_cancel
progress_lock.acquire()
global_cancel = True
context.area.tag_redraw()
progress_lock.release()
if self.progress_provider.process:
import signal
# Corresponds to usual greeting of blender to hit Ctrl-C
# again to abort rendering.
self.progress_provider.process.send_signal(signal.SIGINT)
self.progress_provider.process.send_signal(signal.SIGINT)
def cancel(self, context):
# When users closes window
return
global global_cancel
print("CANCEL")
self.cancel_request(context)
if self.timer:
wm = context.window_manager
wm.event_timer_remove(self.timer)
if self.thread:
self.thread.join()
print("CANCELLED")
class BENCHMARK_OT_save(bpy.types.Operator):
bl_idname = "benchmark.save"