summaryrefslogtreecommitdiffstats
path: root/tools/releasetools/blockimgdiff.py
diff options
context:
space:
mode:
authorTao Bao <tbao@google.com>2015-08-17 09:45:13 -0700
committerTao Bao <tbao@google.com>2015-08-26 15:00:38 -0700
commit1fc67631eedbfba07e005d85aadae6e1b91d8d93 (patch)
treed225377d408e4d9a37da9920e8c3557f16cb6036 /tools/releasetools/blockimgdiff.py
parentd47d8e14880132c42a75f41c8041851797c75e35 (diff)
downloadbuild-1fc67631eedbfba07e005d85aadae6e1b91d8d93.zip
build-1fc67631eedbfba07e005d85aadae6e1b91d8d93.tar.gz
build-1fc67631eedbfba07e005d85aadae6e1b91d8d93.tar.bz2
Revise stash for BBOTAs when needed.
When generating incremental BBOTAs (v2 and above), we need to ensure that the needed runtime stash is below the given threshold. If it's running out of space on /cache, we replace the command that uses a stash with a "new" command instead. This may increase the OTA package size, since it is carrying more full blocks instead of patches. It gets even worse for large files that span a number of blocks, because currently we will store all the blocks for the file as "new" blocks if stashing cannot be satisfied. We may further optimize by splitting them into smaller chunks so that most of them can still be stashed. Bug: 22430577 Change-Id: Ieae5243d461e3f899f613f76a380f6f7c3edb356 (cherry picked from commit 82c47981bd0602a1c7b50dfabf9a6a2412993bae)
Diffstat (limited to 'tools/releasetools/blockimgdiff.py')
-rw-r--r--tools/releasetools/blockimgdiff.py77
1 files changed, 77 insertions, 0 deletions
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index a007f81..6afa7a5 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -174,6 +174,12 @@ class Transfer(object):
return (sum(sr.size() for (_, sr) in self.stash_before) -
sum(sr.size() for (_, sr) in self.use_stash))
+ def ConvertToNew(self):
+ assert self.style != "new"
+ self.use_stash = []
+ self.style = "new"
+ self.src_ranges = RangeSet()
+
def __str__(self):
return (str(self.id) + ": <" + str(self.src_ranges) + " " + self.style +
" to " + str(self.tgt_ranges) + ">")
@@ -268,6 +274,10 @@ class BlockImageDiff(object):
self.ReverseBackwardEdges()
self.ImproveVertexSequence()
+ # Ensure the runtime stash size is under the limit.
+ if self.version >= 2 and common.OPTIONS.cache_size is not None:
+ self.ReviseStashSize()
+
# Double-check our work.
self.AssertSequenceGood()
@@ -507,6 +517,73 @@ class BlockImageDiff(object):
max_stashed_blocks, max_stashed_size, max_allowed,
max_stashed_size * 100.0 / max_allowed))
+ def ReviseStashSize(self):
+ print("Revising stash size...")
+ stashes = {}
+
+ # Create the map between a stash and its def/use points. For example, for a
+ # given stash of (idx, sr), stashes[idx] = (sr, def_cmd, use_cmd).
+ for xf in self.transfers:
+ # Command xf defines (stores) all the stashes in stash_before.
+ for idx, sr in xf.stash_before:
+ stashes[idx] = (sr, xf)
+
+ # Record all the stashes command xf uses.
+ for idx, _ in xf.use_stash:
+ stashes[idx] += (xf,)
+
+ # Compute the maximum blocks available for stash based on /cache size and
+ # the threshold.
+ cache_size = common.OPTIONS.cache_size
+ stash_threshold = common.OPTIONS.stash_threshold
+ max_allowed = cache_size * stash_threshold / self.tgt.blocksize
+
+ stashed_blocks = 0
+
+ # Now go through all the commands. Compute the required stash size on the
+ # fly. If a command requires excess stash than available, it deletes the
+ # stash by replacing the command that uses the stash with a "new" command
+ # instead.
+ for xf in self.transfers:
+ replaced_cmds = []
+
+ # xf.stash_before generates explicit stash commands.
+ for idx, sr in xf.stash_before:
+ if stashed_blocks + sr.size() > max_allowed:
+ # We cannot stash this one for a later command. Find out the command
+ # that will use this stash and replace the command with "new".
+ use_cmd = stashes[idx][2]
+ replaced_cmds.append(use_cmd)
+ print(" %s replaced due to an explicit stash of %d blocks." % (
+ use_cmd, sr.size()))
+ else:
+ stashed_blocks += sr.size()
+
+ # xf.use_stash generates free commands.
+ for _, sr in xf.use_stash:
+ stashed_blocks -= sr.size()
+
+ # "move" and "diff" may introduce implicit stashes in BBOTA v3. Prior to
+ # ComputePatches(), they both have the style of "diff".
+ if xf.style == "diff" and self.version >= 3:
+ assert xf.tgt_ranges and xf.src_ranges
+ if xf.src_ranges.overlaps(xf.tgt_ranges):
+ if stashed_blocks + xf.src_ranges.size() > max_allowed:
+ replaced_cmds.append(xf)
+ print(" %s replaced due to an implicit stash of %d blocks." % (
+ xf, xf.src_ranges.size()))
+
+ # Replace the commands in replaced_cmds with "new"s.
+ for cmd in replaced_cmds:
+ # It no longer uses any commands in "use_stash". Remove the def points
+ # for all those stashes.
+ for idx, sr in cmd.use_stash:
+ def_cmd = stashes[idx][1]
+ assert (idx, sr) in def_cmd.stash_before
+ def_cmd.stash_before.remove((idx, sr))
+
+ cmd.ConvertToNew()
+
def ComputePatches(self, prefix):
print("Reticulating splines...")
diff_q = []