BmapFlasher: improve flashing speed
authorArtem Bityutskiy <artem.bityutskiy@intel.com>
Tue, 6 Nov 2012 13:41:29 +0000 (15:41 +0200)
committerArtem Bityutskiy <artem.bityutskiy@intel.com>
Thu, 8 Nov 2012 08:10:40 +0000 (10:10 +0200)
Improve flashing speed by switching to the 'noop' I/O scheduler for the block
device we are flashing to. This gives ~20% write speed imporvement.

Also limit the write buffering in order make the flashing - we do not need that
and we better leave the memory for other applications.

Change-Id: Ideca1b4ee786c91606e91813d2ffe451380506d3
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
bmaptools/BmapFlasher.py

index a657a85..4be30a1 100644 (file)
@@ -187,10 +187,56 @@ class BmapFlasher:
         # Turn the block device file descriptor into a file object
         try:
             self._f_bdev = os.fdopen(self._f_bdev, "wb")
-        except IOError as err:
+        except OSError as err:
             os.close(self._f_bdev)
             raise Error("cannot open block device '%s': %s" \
-                        % (self._bdev_path, err.strerror))
+                        % (self._bdev_path, err))
+
+    def _tune_block_device(self):
+        """" Tune the block device for better performance:
+             1. Switching to the 'noop' I/O scheduler if it is available.
+                Sequential write to the block device becomes a lot faster
+                comparing to CFQ.
+             2. Limit the write buffering - we do not need the kernel to buffer
+                a lot of the data we send to the block device, because we write
+                sequentially. Limit the buffering. """
+
+        # Construct the path to the sysfs directory of our block device
+        st_rdev = os.fstat(self._f_bdev.fileno()).st_rdev
+        sysfs_base = "/sys/dev/block/%s:%s/" \
+                      % (os.major(st_rdev), os.minor(st_rdev))
+
+        # Switch to the 'noop' I/O scheduler
+        scheduler_path = sysfs_base + "queue/scheduler"
+        try:
+            f_scheduler = open(scheduler_path, "w")
+        except OSError as err:
+            # If we can't find the file, no problem, this stuff is just an
+            # optimization.
+            f_scheduler = None
+            pass
+
+        if f_scheduler:
+            try:
+                f_scheduler.write("noop")
+            except IOError as err:
+                pass
+            f_scheduler.close()
+
+        # Limit the write buffering
+        ratio_path = sysfs_base + "bdi/max_ratio"
+        try:
+            f_ratio = open(ratio_path, "w")
+        except OSError as err:
+            f_ratio = None
+            pass
+
+        if f_ratio:
+            try:
+                f_ratio.write("1")
+            except IOError as err:
+                pass
+            f_ratio.close()
 
     def __init__(self, image_path, bdev_path, bmap_path = None):
         """ Initialize a class instance:
@@ -366,6 +412,9 @@ class BmapFlasher:
             The 'verify' argument defines whether the SHA1 checksum has to be
             verified while writing. """
 
+        if self.target_is_block_device:
+            self._tune_block_device()
+
         if not self._f_bmap:
             self._write_entire_image(sync)
             return