Sort queue of blocks to visit by blend file and on-disk order
This gives a small speedup to dependency tracing.
This commit is contained in:
parent
09a0866c14
commit
cc20b0bfd5
@ -121,7 +121,7 @@ class BlendFile:
|
|||||||
fileobj.close()
|
fileobj.close()
|
||||||
raise exceptions.BlendFileError("File is not a blend file", path)
|
raise exceptions.BlendFileError("File is not a blend file", path)
|
||||||
|
|
||||||
self.blocks = []
|
self.blocks = [] # BlendFileBlocks, in disk order.
|
||||||
self.code_index = collections.defaultdict(list)
|
self.code_index = collections.defaultdict(list)
|
||||||
self.structs = []
|
self.structs = []
|
||||||
self.sdna_index_from_id = {}
|
self.sdna_index_from_id = {}
|
||||||
@ -333,6 +333,7 @@ class BlendFile:
|
|||||||
raise exceptions.SegmentationFault('address does not exist', address) from None
|
raise exceptions.SegmentationFault('address does not exist', address) from None
|
||||||
|
|
||||||
|
|
||||||
|
@functools.total_ordering
|
||||||
class BlendFileBlock:
|
class BlendFileBlock:
|
||||||
"""
|
"""
|
||||||
Instance of a struct.
|
Instance of a struct.
|
||||||
@ -405,6 +406,14 @@ class BlendFileBlock:
|
|||||||
self.addr_old == other.addr_old and
|
self.addr_old == other.addr_old and
|
||||||
self.bfile.filepath == other.bfile.filepath)
|
self.bfile.filepath == other.bfile.filepath)
|
||||||
|
|
||||||
|
def __lt__(self, other: 'BlendFileBlock') -> bool:
|
||||||
|
"""Order blocks by file path and offset within that file."""
|
||||||
|
if not isinstance(other, BlendFileBlock):
|
||||||
|
raise NotImplemented()
|
||||||
|
my_key = self.bfile.filepath, self.file_offset
|
||||||
|
other_key = other.bfile.filepath, other.file_offset
|
||||||
|
return my_key < other_key
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
def __bool__(self) -> bool:
|
||||||
"""Data blocks are always True."""
|
"""Data blocks are always True."""
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -35,17 +35,21 @@ class _BlockIterator:
|
|||||||
limit_to: typing.Set[blendfile.BlendFileBlock] = frozenset(),
|
limit_to: typing.Set[blendfile.BlendFileBlock] = frozenset(),
|
||||||
) -> typing.Iterator[blendfile.BlendFileBlock]:
|
) -> typing.Iterator[blendfile.BlendFileBlock]:
|
||||||
"""Expand blocks with dependencies from other libraries."""
|
"""Expand blocks with dependencies from other libraries."""
|
||||||
|
if limit_to:
|
||||||
|
self._queue_named_blocks(bfile, limit_to)
|
||||||
|
else:
|
||||||
|
self._queue_all_blocks(bfile)
|
||||||
|
|
||||||
|
blocks_per_lib = yield from self._visit_blocks(bfile, limit_to)
|
||||||
|
yield from self._visit_linked_blocks(blocks_per_lib)
|
||||||
|
|
||||||
|
def _visit_blocks(self, bfile, limit_to):
|
||||||
bpath = bfile.filepath.absolute().resolve()
|
bpath = bfile.filepath.absolute().resolve()
|
||||||
root_dir = bpathlib.BlendPath(bpath.parent)
|
root_dir = bpathlib.BlendPath(bpath.parent)
|
||||||
|
|
||||||
# Mapping from library path to data blocks to expand.
|
# Mapping from library path to data blocks to expand.
|
||||||
blocks_per_lib = collections.defaultdict(set)
|
blocks_per_lib = collections.defaultdict(set)
|
||||||
|
|
||||||
if limit_to:
|
|
||||||
self._queue_named_blocks(bfile, limit_to)
|
|
||||||
else:
|
|
||||||
self._queue_all_blocks(bfile)
|
|
||||||
|
|
||||||
while self.to_visit:
|
while self.to_visit:
|
||||||
block = self.to_visit.popleft()
|
block = self.to_visit.popleft()
|
||||||
assert isinstance(block, blendfile.BlendFileBlock)
|
assert isinstance(block, blendfile.BlendFileBlock)
|
||||||
@ -75,6 +79,9 @@ class _BlockIterator:
|
|||||||
self.blocks_yielded.add((bpath, block.addr_old))
|
self.blocks_yielded.add((bpath, block.addr_old))
|
||||||
yield block
|
yield block
|
||||||
|
|
||||||
|
return blocks_per_lib
|
||||||
|
|
||||||
|
def _visit_linked_blocks(self, blocks_per_lib):
|
||||||
# We've gone through all the blocks in this file, now open the libraries
|
# We've gone through all the blocks in this file, now open the libraries
|
||||||
# and iterate over the blocks referred there.
|
# and iterate over the blocks referred there.
|
||||||
for lib_bpath, idblocks in blocks_per_lib.items():
|
for lib_bpath, idblocks in blocks_per_lib.items():
|
||||||
@ -95,6 +102,7 @@ class _BlockIterator:
|
|||||||
# to do with them anyway.
|
# to do with them anyway.
|
||||||
self.to_visit.extend(block for block in bfile.blocks
|
self.to_visit.extend(block for block in bfile.blocks
|
||||||
if block.code != b'DATA')
|
if block.code != b'DATA')
|
||||||
|
self._sort_queue()
|
||||||
|
|
||||||
def _queue_named_blocks(self,
|
def _queue_named_blocks(self,
|
||||||
bfile: blendfile.BlendFile,
|
bfile: blendfile.BlendFile,
|
||||||
@ -106,6 +114,7 @@ class _BlockIterator:
|
|||||||
The queued blocks are loaded from the actual blend file, and
|
The queued blocks are loaded from the actual blend file, and
|
||||||
selected by name.
|
selected by name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for to_find in limit_to:
|
for to_find in limit_to:
|
||||||
assert to_find.code == b'ID'
|
assert to_find.code == b'ID'
|
||||||
name_to_find = to_find[b'name']
|
name_to_find = to_find[b'name']
|
||||||
@ -116,9 +125,22 @@ class _BlockIterator:
|
|||||||
if block.id_name == name_to_find:
|
if block.id_name == name_to_find:
|
||||||
log.debug('Queueing %r from file %s', block, bfile.filepath)
|
log.debug('Queueing %r from file %s', block, bfile.filepath)
|
||||||
self.to_visit.append(block)
|
self.to_visit.append(block)
|
||||||
|
self._sort_queue()
|
||||||
|
|
||||||
def _queue_dependencies(self, block: blendfile.BlendFileBlock):
|
def _queue_dependencies(self, block: blendfile.BlendFileBlock):
|
||||||
self.to_visit.extend(expanders.expand_block(block))
|
self.to_visit.extend(expanders.expand_block(block))
|
||||||
|
self._sort_queue()
|
||||||
|
|
||||||
|
def _sort_queue(self):
|
||||||
|
"""Sort the queued blocks by file and by offset.
|
||||||
|
|
||||||
|
This allows us to go through the blend files sequentially.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def sort_key(block: blendfile.BlendFileBlock):
|
||||||
|
return block.bfile.filepath, block.file_offset
|
||||||
|
|
||||||
|
self.to_visit = collections.deque(sorted(self.to_visit, key=sort_key))
|
||||||
|
|
||||||
|
|
||||||
def iter_blocks(bfile: blendfile.BlendFile) -> typing.Iterator[blendfile.BlendFileBlock]:
|
def iter_blocks(bfile: blendfile.BlendFile) -> typing.Iterator[blendfile.BlendFileBlock]:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user