Skip to content

Commit 188028d

Browse files
jedi7radimkarnis
authored andcommitted
feat(write-flash): apply compression only if it reduces the file size
1 parent a5c9090 commit 188028d

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

esptool/cmds.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -814,11 +814,24 @@ def write_flash(
814814
"Security features enabled, so not changing any flash settings."
815815
)
816816
calcmd5 = hashlib.md5(image).hexdigest()
817-
uncsize = len(image)
817+
uncsize = image_size = len(image)
818818
if compress:
819-
uncimage = image
820-
image = zlib.compress(uncimage, 9)
821-
compsize = len(image)
819+
compressed_image = zlib.compress(image, 9)
820+
compsize = len(compressed_image)
821+
# Only use compression if it actually reduces the file size
822+
if compsize < uncsize:
823+
image = compressed_image
824+
image_size = compsize
825+
else:
826+
# Compression didn't help, disable it for this file
827+
source = "input image" if name is None else f"file '{name}'"
828+
log.note(
829+
f"Cannot compress {source} more than the original size, "
830+
"will flash uncompressed. "
831+
f"Compressed size {compsize} bytes >= uncompressed {uncsize} bytes."
832+
)
833+
compress = False
834+
822835
original_image = image # Save the whole image in case retry is needed
823836
# Try again if reconnect was successful
824837
log.stage()
@@ -829,7 +842,7 @@ def write_flash(
829842
# to dynamically calculate the timeout based on the real write size
830843
decompress = zlib.decompressobj()
831844
esp.flash_defl_begin(
832-
uncsize, compsize, address, encrypted_write=encrypted
845+
uncsize, image_size, address, encrypted_write=encrypted
833846
)
834847
else:
835848
esp.flash_begin(uncsize, address, encrypted_write=encrypted)
@@ -839,7 +852,6 @@ def write_flash(
839852
t = time.time()
840853

841854
timeout = DEFAULT_TIMEOUT
842-
image_size = compsize if compress else uncsize
843855
while len(image) >= 0:
844856
if not no_progress:
845857
log.progress_bar(

test/test_esptool.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,36 @@ def test_compressible_non_trivial_file(self):
749749
finally:
750750
os.unlink(input_file.name)
751751

752+
def test_compression_auto_skipped_when_no_size_reduction(self):
753+
"""
754+
Test that compression is automatically skipped when it doesn't reduce file size.
755+
Uses truly random data which is hard to compress.
756+
"""
757+
try:
758+
input_file = tempfile.NamedTemporaryFile(delete=False)
759+
file_size = 64 * 1024 # 64KB of random data
760+
# Write truly random data that won't compress well
761+
for _ in range(file_size):
762+
input_file.write(struct.pack("B", random.randrange(0, 256)))
763+
input_file.close()
764+
765+
output = self.run_esptool(
766+
f"write-flash --compress 0x20000 {input_file.name}"
767+
)
768+
769+
# Verify that compression was skipped by checking the output message
770+
# When compression is used: "Wrote X bytes (Y compressed)"
771+
# When compression is skipped: "Wrote X bytes" (no "compressed")
772+
assert "Wrote" in output and "bytes" in output, (
773+
"Should have 'Wrote X bytes' message"
774+
)
775+
assert " compressed)" not in output, (
776+
f"Compression should have been skipped for random data, "
777+
f"but output shows compressed format: {output}"
778+
)
779+
finally:
780+
os.unlink(input_file.name)
781+
752782
@pytest.mark.quick_test
753783
def test_zero_length(self):
754784
# Zero length files are skipped with a warning

0 commit comments

Comments
 (0)