git-gui: Performance improvements for large file sets.
authorShawn O. Pearce <spearce@spearce.org>
Wed, 8 Nov 2006 00:30:54 +0000 (19:30 -0500)
committerShawn O. Pearce <spearce@spearce.org>
Wed, 8 Nov 2006 04:48:20 +0000 (23:48 -0500)
Loading 6900 newly added files required about 90 seconds on one system.
This is just far too long to perform a "status" type of operation.
git-status on the same system completes in just 8.2 seconds if it is
redirected to /dev/null.

Most of our performance improvement comes from moving all of the UI
updating out of the main fileevent handlers for the status process.
Instead we are only updating the file_states array and then only doing
the UI update when all states are known and have been finally determined.

The rescan execution is now down to almost 30 seconds for the same case,
a good (but not really all that impressive) improvement.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
git-gui

diff --git a/git-gui b/git-gui
index 48e1c5601f813826f1abcf832d3ea6419254c559..ed745ee52e5f812167ff7fb91890d72821341955 100755 (executable)
--- a/git-gui
+++ b/git-gui
@@ -236,10 +236,13 @@ proc status_eof {fd buf final} {
        if {[eof $fd]} {
                set $buf {}
                close $fd
+
                if {[incr status_active -1] == 0} {
                        unlock_index
 
                        set ui_status_value $final
+                       display_all_files
+
                        if {$ui_fname_value != {} && [array names file_states \
                                -exact $ui_fname_value] != {}}  {
                                show_diff $ui_fname_value
@@ -711,79 +714,103 @@ proc bsearch {w path} {
        return -[expr $lo + 1]
 }
 
+set next_icon_id 0
+
 proc merge_state {path state} {
-       global file_states
+       global file_states next_icon_id
 
        if {[array names file_states -exact $path] == {}}  {
-               set o __
-               set s [list $o none none]
+               set m __
+               set s [list $m icon[incr next_icon_id]]
        } else {
                set s $file_states($path)
-               set o [lindex $s 0]
+               set m [lindex $s 0]
        }
 
-       set m [lindex $s 0]
-       if {[string index $state 0] == "_"} {
+       if {[string index $state 0] == {_}} {
                set state [string index $m 0][string index $state 1]
-       } elseif {[string index $state 0] == "*"} {
+       } elseif {[string index $state 0] == {*}} {
                set state _[string index $state 1]
        }
 
-       if {[string index $state 1] == "_"} {
+       if {[string index $state 1] == {_}} {
                set state [string index $state 0][string index $m 1]
-       } elseif {[string index $state 1] == "*"} {
+       } elseif {[string index $state 1] == {*}} {
                set state [string index $state 0]_
        }
 
        set file_states($path) [lreplace $s 0 0 $state]
-       return $o
+       return $m
 }
 
 proc display_file {path state} {
-       global ui_index ui_other file_states
+       global ui_index ui_other file_states status_active
 
        set old_m [merge_state $path $state]
+       if {$status_active} return
+
        set s $file_states($path)
-       set m [lindex $s 0]
+       set new_m [lindex $s 0]
+       set new_col [mapcol $new_m $path]
+       set new_ico [mapicon $new_m $path]
 
-       if {[mapcol $m $path] == "o"} {
-               set ii 1
-               set ai 2
-               set iw $ui_index
-               set aw $ui_other
+       if {$new_col == {o}} {
+               set old_w $ui_index
+               set new_w $ui_other
        } else {
-               set ii 2
-               set ai 1
-               set iw $ui_other
-               set aw $ui_index
+               set old_w $ui_other
+               set new_w $ui_index
        }
 
-       set d [lindex $s $ii]
-       if {$d != "none"} {
-               set lno [bsearch $iw $path]
+       if {$new_col != [mapcol $old_m $path]} {
+               set lno [bsearch $old_w $path]
                if {$lno >= 0} {
                        incr lno
-                       $iw conf -state normal
-                       $iw delete $lno.0 [expr $lno + 1].0
-                       $iw conf -state disabled
-                       set s [lreplace $s $ii $ii none]
+                       $old_w conf -state normal
+                       $old_w delete $lno.0 [expr $lno + 1].0
+                       $old_w conf -state disabled
                }
+
+               set lno [expr abs([bsearch $new_w $path] + 1) + 1]
+               $new_w conf -state normal
+               $new_w image create $lno.0 \
+                       -align center -padx 5 -pady 1 \
+                       -name [lindex $s 1] \
+                       -image [mapicon $m $path]
+               $new_w insert $lno.1 "$path\n"
+               $new_w conf -state disabled
+       } elseif {$new_icon != [mapicon $old_m $path]} {
+               $new_w conf -state normal
+               $new_w image conf [lindex $s 1] -image $new_icon
+               $new_w conf -state disabled
        }
+}
 
-       set d [lindex $s $ai]
-       if {$d == "none"} {
-               set lno [expr abs([bsearch $aw $path] + 1) + 1]
-               $aw conf -state normal
-               set ico [$aw image create $lno.0 \
+proc display_all_files {} {
+       global ui_index ui_other file_states
+
+       $ui_index conf -state normal
+       $ui_other conf -state normal
+
+       foreach path [lsort [array names file_states]] {
+               set s $file_states($path)
+               set m [lindex $s 0]
+
+               if {[mapcol $m $path] == {o}} {
+                       set aw $ui_other
+               } else {
+                       set aw $ui_index
+               }
+
+               $aw image create end \
                        -align center -padx 5 -pady 1 \
-                       -image [mapicon $m $path]]
-               $aw insert $lno.1 "$path\n"
-               $aw conf -state disabled
-               set file_states($path) [lreplace $s $ai $ai [list $ico]]
-       } elseif {[mapicon $m $path] != [mapicon $old_m $path]} {
-               set ico [lindex $d 0]
-               $aw image conf $ico -image [mapicon $m $path]
+                       -name [lindex $s 1] \
+                       -image [mapicon $m $path]
+               $aw insert end "$path\n"
        }
+
+       $ui_index conf -state disabled
+       $ui_other conf -state disabled
 }
 
 proc with_update_index {body} {