The hardcoded 64KB FDT increment size causes excessive reallocations
when building FIT images with large artifacts (e.g., 250+ MB rootfs):

```
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    16118  297.130    0.018  305.189    0.019 libfdt.py:947(resize)
      870    9.876    0.011   15.211    0.017 fdt.py:56(BytesToValue)
    16118    8.024    0.000    8.024    0.000 {built-in method 
_libfdt.fdt_resize}
```

Add support for configurable increment size via --fdt-inc-size option,
with recommended value at least equal to total binary artifacts size
to minimize resize operations and reduce build time.

Signed-off-by: Nikita Shubin <[email protected]>
---
I think it might be usefull for some cases even if total blob size isn't
too large.

P.S. My Python is pretty rough, so I'd be grateful for any feedback 
or error spotting.
---
 tools/binman/cmdline.py       |  3 +++
 tools/binman/control.py       |  8 ++++++--
 tools/binman/entry.py         | 18 ++++++++++++++++++
 tools/binman/etype/fit.py     |  2 +-
 tools/binman/etype/section.py | 10 ++++++++++
 5 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py
index 9632ec115e5..3ff09050af7 100644
--- a/tools/binman/cmdline.py
+++ b/tools/binman/cmdline.py
@@ -136,6 +136,9 @@ controlled by a description in the board device tree.'''
             help="Don't use 'expanded' versions of entries where available; "
                  "normally 'u-boot' becomes 'u-boot-expanded', for example")
     _AddPreserve(build_parser)
+    build_parser.add_argument('-s', '--fdt-inc-size', type=int, default=65536,
+            help="FDT expansion increment size in bytes. Larger values reduce "
+                 "reallocations for big binaries at the cost of more RAM")
     build_parser.add_argument('-u', '--update-fdt', action='store_true',
         default=False, help='Update the binman node with offset/size info')
     build_parser.add_argument('--update-fdt-in-elf', type=str,
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 816f7c1eba2..be48619e925 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -745,7 +745,8 @@ def CheckForProblems(image):
 
 def ProcessImage(image, update_fdt, write_map, get_contents=True,
                  allow_resize=True, allow_missing=False,
-                 allow_fake_blobs=False):
+                 allow_fake_blobs=False,
+                 fdt_inc_size=65536):
     """Perform all steps for this image, including checking and # writing it.
 
     This means that errors found with a later image will be reported after
@@ -762,6 +763,7 @@ def ProcessImage(image, update_fdt, write_map, 
get_contents=True,
             of the entries), False to raise an exception
         allow_missing: Allow blob_ext objects to be missing
         allow_fake_blobs: Allow blob_ext objects to be faked with dummy files
+        fdt_inc_size: Set size hint for device tree generation
 
     Returns:
         True if one or more external blobs are missing or faked,
@@ -770,6 +772,7 @@ def ProcessImage(image, update_fdt, write_map, 
get_contents=True,
     if get_contents:
         image.SetAllowMissing(allow_missing)
         image.SetAllowFakeBlob(allow_fake_blobs)
+        image.SetFdtIncSize(fdt_inc_size)
         image.GetEntryContents()
     image.GetEntryOffsets()
 
@@ -945,7 +948,8 @@ def Binman(args):
             for image in images.values():
                 invalid |= ProcessImage(image, args.update_fdt, args.map,
                                        allow_missing=args.allow_missing,
-                                       allow_fake_blobs=args.fake_ext_blobs)
+                                       allow_fake_blobs=args.fake_ext_blobs,
+                                       fdt_inc_size=args.fdt_inc_size)
 
             # Write the updated FDTs to our output files
             for dtb_item in state.GetAllFdts():
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index ce7ef28e94b..d74f34372fd 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -147,6 +147,7 @@ class Entry(object):
         self.external = False
         self.allow_missing = False
         self.allow_fake = False
+        self.fdt_inc_size = 65536
         self.bintools = {}
         self.missing_bintools = []
         self.update_hash = True
@@ -1109,6 +1110,15 @@ features to produce new behaviours.
         """
         self.allow_fake = allow_fake
 
+    def SetFdtIncSize(self, fdt_inc_size):
+        """Set size hint for device tree
+
+        Args:
+            fdt_inc_size: Hint size
+        """
+        # This is meaningless for anything other than sections
+        pass
+
     def CheckMissing(self, missing_list):
         """Check if the entry has missing external blobs
 
@@ -1174,6 +1184,14 @@ features to produce new behaviours.
         """
         return self.allow_missing
 
+    def GetFdtIncSize(self):
+        """Get size hint for device tree
+
+        Returns:
+            fdt_inc_size: Hint size
+        """
+        return self.fdt_inc_size
+
     def record_missing_bintool(self, bintool):
         """Record a missing bintool that was needed to produce this entry
 
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index f28b1e6b4cb..c393a74514f 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -1039,7 +1039,7 @@ class Entry_fit(Entry_section):
         # Build a new tree with all nodes and properties starting from the
         # entry node
         fsw = libfdt.FdtSw()
-        fsw.INC_SIZE = 65536
+        fsw.INC_SIZE = self.GetFdtIncSize()
         fsw.finish_reservemap()
         to_remove = []
         loadables = []
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index 6a26d687056..a8a12f948a7 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -920,6 +920,16 @@ class Entry_section(Entry):
         for entry in self.GetEntries().values():
             entry.SetAllowMissing(allow_missing)
 
+    def SetFdtIncSize(self, fdt_inc_size):
+        """Set size hint for device tree
+
+        Args:
+            fdt_inc_size: Hint size
+        """
+        self.fdt_inc_size = fdt_inc_size
+        for entry in self.GetEntries().values():
+            entry.SetFdtIncSize(fdt_inc_size)
+
     def SetAllowFakeBlob(self, allow_fake):
         """Set whether a section allows to create a fake blob
 

---
base-commit: 7995bf8dea2d5b3eb7fcb836636f4773924ec35d
change-id: 20260226-fdt_size_hint-89355735cd16

Best regards,
-- 
Nikita Shubin

Reply via email to