dispatcher status callback
Right now it's called every 100 work items. This number is completely arbitrary and should probably be tuned.
This commit is contained in:
@@ -42,7 +42,10 @@ class Dispatcher(object):
|
|||||||
def render_all(self, tilesetlist, status_callback):
|
def render_all(self, tilesetlist, status_callback):
|
||||||
"""Render all of the tilesets in the given
|
"""Render all of the tilesets in the given
|
||||||
tilesetlist. status_callback is called periodically to update
|
tilesetlist. status_callback is called periodically to update
|
||||||
status. """
|
status. The callback should take the following arguments:
|
||||||
|
(phase, items_completed, total_items), where total_items may
|
||||||
|
be none if there is no useful estimate.
|
||||||
|
"""
|
||||||
# TODO use status callback
|
# TODO use status callback
|
||||||
|
|
||||||
# setup tilesetlist
|
# setup tilesetlist
|
||||||
@@ -63,14 +66,52 @@ class Dispatcher(object):
|
|||||||
return ((tset, workitem) for workitem in tset.iterate_work_items(p))
|
return ((tset, workitem) for workitem in tset.iterate_work_items(p))
|
||||||
work_iterators.append(make_work_iterator(tileset, phase))
|
work_iterators.append(make_work_iterator(tileset, phase))
|
||||||
|
|
||||||
|
# keep track of total jobs, and how many jobs are done
|
||||||
|
total_jobs = 0
|
||||||
|
for tileset, phases in zip(tilesetlist, num_phases):
|
||||||
|
if phase < phases:
|
||||||
|
jobs_for_tileset = tileset.get_phase_length(phase)
|
||||||
|
# if one is unknown, the total is unknown
|
||||||
|
if jobs_for_tileset is None:
|
||||||
|
total_jobs = None
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
total_jobs += jobs_for_tileset
|
||||||
|
finished_jobs = 0
|
||||||
|
|
||||||
|
# do the first status update
|
||||||
|
self._status_update(status_callback, phase, finished_jobs, total_jobs, force=True)
|
||||||
|
|
||||||
# go through these iterators round-robin style
|
# go through these iterators round-robin style
|
||||||
for tileset, (workitem, deps) in util.roundrobin(work_iterators):
|
for tileset, (workitem, deps) in util.roundrobin(work_iterators):
|
||||||
self._pending_jobs.append((tileset, workitem, deps))
|
self._pending_jobs.append((tileset, workitem, deps))
|
||||||
self._dispatch_jobs()
|
finished_jobs += self._dispatch_jobs()
|
||||||
|
self._status_update(status_callback, phase, finished_jobs, total_jobs)
|
||||||
|
|
||||||
# after each phase, wait for the work to finish
|
# after each phase, wait for the work to finish
|
||||||
while len(self._pending_jobs) > 0 or len(self._running_jobs) > 0:
|
while len(self._pending_jobs) > 0 or len(self._running_jobs) > 0:
|
||||||
self._dispatch_jobs()
|
finished_jobs += self._dispatch_jobs()
|
||||||
|
self._status_update(status_callback, phase, finished_jobs, total_jobs)
|
||||||
|
|
||||||
|
def _status_update(self, callback, phase, completed, total, force=False):
|
||||||
|
# always called with force=True at the beginning, so that can
|
||||||
|
# be used to set up state. After that, it is called after
|
||||||
|
# every _dispatch_jobs() often; this function is used to
|
||||||
|
# decide how often the actual status callback should be
|
||||||
|
# called.
|
||||||
|
if force:
|
||||||
|
self._last_status_update = completed
|
||||||
|
if callback:
|
||||||
|
callback(phase, completed, total)
|
||||||
|
return
|
||||||
|
|
||||||
|
if callback is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
update_interval = 100 # XXX arbitrary
|
||||||
|
if self._last_status_update < 0 or completed >= self._last_status_update + update_interval or completed < self._last_status_update:
|
||||||
|
self._last_status_update = completed
|
||||||
|
callback(phase, completed, total)
|
||||||
|
|
||||||
def _dispatch_jobs(self):
|
def _dispatch_jobs(self):
|
||||||
# helper function to dispatch pending jobs when their
|
# helper function to dispatch pending jobs when their
|
||||||
@@ -105,6 +146,8 @@ class Dispatcher(object):
|
|||||||
for job in dispatched_jobs:
|
for job in dispatched_jobs:
|
||||||
self._pending_jobs.remove(job)
|
self._pending_jobs.remove(job)
|
||||||
|
|
||||||
|
return len(finished_jobs)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the Dispatcher. This should be called when you are
|
"""Close the Dispatcher. This should be called when you are
|
||||||
done with the dispatcher, to ensure that it cleans up any
|
done with the dispatcher, to ensure that it cleans up any
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ get_num_phases()
|
|||||||
other phases... all work done by one phase is done before the next phase is
|
other phases... all work done by one phase is done before the next phase is
|
||||||
started.
|
started.
|
||||||
|
|
||||||
|
get_phase_length(phase)
|
||||||
|
This method returns an integer indicating how many work items there are in
|
||||||
|
this phase. This number is used for purely informational purposes. It can
|
||||||
|
be exact, or an estimate. If there is no useful information on the size of
|
||||||
|
a phase, return None.
|
||||||
|
|
||||||
iterate_work_items(phase)
|
iterate_work_items(phase)
|
||||||
Takes a phase number (a non-negative integer). This method should return an
|
Takes a phase number (a non-negative integer). This method should return an
|
||||||
iterator over work items and a list of dependencies i.e. (work_item, [d1,
|
iterator over work items and a list of dependencies i.e. (work_item, [d1,
|
||||||
@@ -228,6 +234,12 @@ class TileSet(object):
|
|||||||
"""
|
"""
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def get_phase_length(self, phase):
|
||||||
|
"""Returns the number of work items in a given phase, or None if there
|
||||||
|
is no good estimate.
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
|
||||||
def iterate_work_items(self, phase):
|
def iterate_work_items(self, phase):
|
||||||
"""Iterates over the dirty tiles in the tree at level depth-phase. So
|
"""Iterates over the dirty tiles in the tree at level depth-phase. So
|
||||||
the first phase iterates over the deepest tiles in the tree, and works
|
the first phase iterates over the deepest tiles in the tree, and works
|
||||||
|
|||||||
Reference in New Issue
Block a user