Implement subprocess termination
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
@@ -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):
|
||||
"""
|
||||
|
@@ -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"
|
||||
|
Reference in New Issue
Block a user