[gparted] Further improve speed of PipeCapture for non-watched output (#777973)



commit 25780c611bf99ce3f819d00c58616fa517a38b0f
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Sat Mar 18 15:35:07 2017 +0000

    Further improve speed of PipeCapture for non-watched output (#777973)
    
    For large output a lot of time is used copying capturebuf to callerbuf
    to provide a Glib::ustring copy of the buffer for the update callback.
    However update callbacks are only used when commands are run to apply
    operations by FileSystem::execute_command() and their output is
    incrementally displayed in the UI.  Whereas update callbacks are never
    used when commands are used to query information via
    Utils::execute_command().
    
    Stop performing interim copying of capturebuf to callerbuf when there
    are no update callbacks registered as it is unnecessary.
    
    Time to read portions of the recorded fsck.fat output via
    fat16::set_used_sectors() and intermediate copies aren't required:
    
                         1 MiB     10 MiB   122 MiB
        old code :   0.074 sec   1.41 sec   210 sec [3:30]
        new code :   0.063 sec   0.56 sec     6.57 sec
    
    Bug 777973 - Segmentation fault on bad disk

 include/PipeCapture.h |    1 +
 src/PipeCapture.cc    |   30 ++++++++++++++++++++++--------
 2 files changed, 23 insertions(+), 8 deletions(-)
---
diff --git a/include/PipeCapture.h b/include/PipeCapture.h
index d986b3f..95fc763 100644
--- a/include/PipeCapture.h
+++ b/include/PipeCapture.h
@@ -55,6 +55,7 @@ private:
        std::string capturebuf;         // Captured output as UTF-8 characters
        size_t line_start;              // Index into bytebuf where current line starts
        Glib::ustring & callerbuf;      // Reference to caller supplied buffer
+       bool callerbuf_uptodate;        // Has capturebuf changed since last copied to callerbuf?
 };
 
 } // namepace GParted
diff --git a/src/PipeCapture.cc b/src/PipeCapture.cc
index 053c3b2..52e45cc 100644
--- a/src/PipeCapture.cc
+++ b/src/PipeCapture.cc
@@ -37,6 +37,7 @@ PipeCapture::PipeCapture( int fd, Glib::ustring &buffer ) : fill_offset( 0 ),
 {
        readbuf = new char[READBUF_SIZE];
        callerbuf.clear();
+       callerbuf_uptodate = true;
        // tie fd to string
        // make channel
        channel = Glib::IOChannel::create_from_fd( fd );
@@ -95,10 +96,10 @@ bool PipeCapture::OnReadable( Glib::IOCondition condition )
        // is drained the partial current line, is pasted into capturebuf at the offset
        // where the last line starts.  (Capturebuf stores UTF-8 encoded characters in a
        // std::string for constant time access to line_start offset).  When readbuf
-       // is drained capturebuf is copied into callerbuf and signal_update slot fired.
-       // (Callerbuf stores UTF-8 encoded characters in a Glib::ustring).  When EOF is
-       // encountered capturebuf is copied into callerbuf if required and signal_eof slot
-       // fired.
+       // is drained and there are registered update callbacks, capturebuf is copied into
+       // callerbuf and signal_update slot fired.  (Callerbuf stores UTF-8 encoded
+       // characters in a Glib::ustring).  When EOF is encountered capturebuf is copied
+       // into callerbuf if required and signal_eof slot fired.
        //
        // Golden rule:
        // Use Glib::ustrings as little as possible for large amounts of data!
@@ -187,6 +188,7 @@ bool PipeCapture::OnReadable( Glib::IOCondition condition )
                                capturebuf.resize( line_start );
                                append_unichar_vector_to_utf8( capturebuf, linevec );
                                line_start = capturebuf.size();
+                               callerbuf_uptodate = false;
 
                                linevec.clear();
                                cursor = 0;
@@ -213,13 +215,20 @@ bool PipeCapture::OnReadable( Glib::IOCondition condition )
                        }
                }
 
-               // Paste partial line to capture buffer; copy that to callers buffer; and
-               // fire any update callbacks.
+               // Paste partial line to capture buffer.
                capturebuf.resize( line_start );
                append_unichar_vector_to_utf8( capturebuf, linevec );
+               callerbuf_uptodate = false;
 
-               callerbuf = capturebuf;
-               signal_update.emit();
+               if ( ! signal_update.empty() )
+               {
+                       // Performance optimisation, especially for large capture buffers:
+                       // only copy capture buffer to callers buffer and fire update
+                       // callbacks when there are any registered update callbacks.
+                       callerbuf = capturebuf;
+                       callerbuf_uptodate = true;
+                       signal_update.emit();
+               }
                return true;
        }
 
@@ -228,6 +237,11 @@ bool PipeCapture::OnReadable( Glib::IOCondition condition )
                std::cerr << "Pipe IOChannel read failed" << std::endl;
        }
 
+       if ( ! callerbuf_uptodate )
+       {
+               callerbuf = capturebuf;
+               callerbuf_uptodate = true;
+       }
        // signal completion
        signal_eof.emit();
        return false;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]