Bug 233935

Summary: gt2k does not handle tiff G4 well: nautilus takes a few minutes for a 2K bytes file.
Product: [Fedora] Fedora Reporter: Tim Taiwanese Liim <tim.liim>
Component: gtk2Assignee: Matthias Clasen <mclasen>
Status: CLOSED UPSTREAM QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: 6   
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2007-03-26 21:35:09 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
sample file that caused gtk2 slowness. none

Description Tim Taiwanese Liim 2007-03-26 02:47:30 UTC
Description of problem:
    Using nautilus, in "View as List," when previewing a 2K-byte tiff
    file with "G4 Fax" compression, /usr/lib/libgdk_pixbuf-2.0.so.0
    in gtk2 takes a minutes before responding.

    The method in question is correct_total() in
    gtk+-2.10.8/gdk-pixbuf/pixops/pixops.c


Version-Release number of selected component (if applicable):
    gtk2-2.10.8-1 in FC6.

How reproducible:
    always

Steps to Reproduce:
1. mkdir ~/t1
   cd ~/t1
   wget http://formosa.homelinux.com/pub/t11.tif
2. nautilus ~/t1
3. change display mode from "View as Icons" to "View as List".
  
Actual results:
- preview icon was shown after a few MINUTES.

Expected results:
- preview icon be shown in one second.

Additional info:
1. info about image:
    B/W document (ie. color depth=1)
    saved in TIFF with "G4 fax" compression.
        (Other choices for compression are "G3 fax", "packedbits", 
        "uncompressed".  When the same image is saved in non-G4
        compression, nautilus is ok to display (ie. no lengthy 
        delay))

2. If nautlius is allowed to complete the "View as List", it seems
   that nautilus caches the result and no longer exhibits the delay.
   To reproduce problem: 
   method1: use ~/t2, ~/t3, ... (use new dir each time)
   method2: rm -rf ~/.nautilus; pkill nautilus

Comment 1 Tim Taiwanese Liim 2007-03-26 02:47:30 UTC
Created attachment 150866 [details]
sample file that caused gtk2 slowness.

Comment 2 Tim Taiwanese Liim 2007-03-26 02:50:29 UTC
3. use dbx to determine where the busy loop is:
   - attach to nautilus when it's in busy loop, and hit control-C:
        #0  0x4a9fa948 in gdk_pixbuf_alpha_mode_get_type ()
           from /usr/lib/libgdk_pixbuf-2.0.so.0
     which comes from gtk2-2.10.8-1.fc6.

   Here is the busy loop, between +6096~+6190.
        0x4a9fa940 <gdk_pixbuf_alpha_mode_get_type+6096>:       mov   
0xffffff70(%ebp),%edx
        0x4a9fa946 <gdk_pixbuf_alpha_mode_get_type+6102>:       mov    (%edx),%ecx
        0x4a9fa948 <gdk_pixbuf_alpha_mode_get_type+6104>:       add    %eax,%ecx
        0x4a9fa94a <gdk_pixbuf_alpha_mode_get_type+6106>:       mov   
%ecx,0xfffffe9c(%ebp)
        0x4a9fa950 <gdk_pixbuf_alpha_mode_get_type+6112>:       js    
0x4a9fa97a <gdk_pixbuf_alpha_mode_get_type+6154>
        0x4a9fa952 <gdk_pixbuf_alpha_mode_get_type+6114>:       sub   
%eax,0xfffffe94(%ebp)
        0x4a9fa958 <gdk_pixbuf_alpha_mode_get_type+6120>:       mov    %ecx,(%edx)
        0x4a9fa95a <gdk_pixbuf_alpha_mode_get_type+6122>:       mov   
0xfffffe94(%ebp),%ecx
        0x4a9fa960 <gdk_pixbuf_alpha_mode_get_type+6128>:       test   %ecx,%ecx
        0x4a9fa962 <gdk_pixbuf_alpha_mode_get_type+6130>:       jle   
0x4a9fafa7 <gdk_pixbuf_alpha_mode_get_type+7735>
        0x4a9fa968 <gdk_pixbuf_alpha_mode_get_type+6136>:       cmp   
%eax,0xfffffe94(%ebp)
        0x4a9fa96e <gdk_pixbuf_alpha_mode_get_type+6142>:       jge   
0x4a9fafa7 <gdk_pixbuf_alpha_mode_get_type+7735>
        0x4a9fa974 <gdk_pixbuf_alpha_mode_get_type+6148>:       mov   
0xfffffe94(%ebp),%eax
        0x4a9fa97a <gdk_pixbuf_alpha_mode_get_type+6154>:       subl  
$0x1,0xffffff3c(%ebp)
        0x4a9fa981 <gdk_pixbuf_alpha_mode_get_type+6161>:       js    
0x4a9faf80 <gdk_pixbuf_alpha_mode_get_type+7696>
        0x4a9fa987 <gdk_pixbuf_alpha_mode_get_type+6167>:       test   %eax,%eax
        0x4a9fa989 <gdk_pixbuf_alpha_mode_get_type+6169>:       je    
0x4a9faf80 <gdk_pixbuf_alpha_mode_get_type+7696>
        0x4a9fa98f <gdk_pixbuf_alpha_mode_get_type+6175>:       mov   
0xfffffe94(%ebp),%ecx
        0x4a9fa995 <gdk_pixbuf_alpha_mode_get_type+6181>:       subl  
$0x4,0xffffff70(%ebp)
        0x4a9fa99c <gdk_pixbuf_alpha_mode_get_type+6188>:       test   %ecx,%ecx
        0x4a9fa99e <gdk_pixbuf_alpha_mode_get_type+6190>:       jne   
0x4a9fa940 <gdk_pixbuf_alpha_mode_get_type+6096>
   but look at gdk-pixbuf/gdk-pixbuf-enum-types.c, line 9-line 21
        GType
        gdk_pixbuf_alpha_mode_get_type (void)
        {
          static GType etype = 0;
          if (etype == 0) {
            static const GEnumValue values[] = {
              { GDK_PIXBUF_ALPHA_BILEVEL, "GDK_PIXBUF_ALPHA_BILEVEL", "bilevel" },
              { GDK_PIXBUF_ALPHA_FULL, "GDK_PIXBUF_ALPHA_FULL", "full" },
              { 0, NULL, NULL }
            };
            etype = g_enum_register_static (g_intern_static_string
("GdkPixbufAlphaMode"), values);
          }
          return etype;
        }
   It's quite possible that gdb is reporting wrong symbols (ie. the method
   name gdk_pixbuf_alpha_mode_get_type is scapegoat).



4. try to build libgdk_pixbuf-2.0.so.0 from source tree.
   4.1 download and install gtk2-2.10.8-1.fc6.src.rpm in /usr/src/redhat
   4.2 rpmbuild -bc --target i686      SPECS/gtk2.spec
   4.3 export LD_LIBRARY_PATH=/usr/src/redhat/BUILD/gtk+-2.10.8/gdk-pixbuf/.libs
       gdb nautilus
   - this time the infinite loop is at
            0x00aff630 <pixops_process+608>:        mov    0xffffff70(%ebp),%edx
            0x00aff636 <pixops_process+614>:        mov    (%edx),%ecx
            0x00aff638 <pixops_process+616>:        add    %eax,%ecx
            0x00aff63a <pixops_process+618>:        mov    %ecx,0xfffffe9c(%ebp)

            0x00aff640 <pixops_process+624>:        js     0xaff66a
<pixops_process+666>
            0x00aff642 <pixops_process+626>:        sub    %eax,0xfffffe94(%ebp)
                                                                  ^c
            0x00aff648 <pixops_process+632>:        mov    %ecx,(%edx)
            0x00aff64a <pixops_process+634>:        mov    0xfffffe94(%ebp),%ecx
            0x00aff650 <pixops_process+640>:        test   %ecx,%ecx
        if (c<=0) go 1492
            0x00aff652 <pixops_process+642>:        jle    0xaff9a4
<pixops_process+1492>
            0x00aff658 <pixops_process+648>:        cmp    %eax,0xfffffe94(%ebp)
        if (eax >= c) go 1492
            0x00aff65e <pixops_process+654>:        jge    0xaff9a4
<pixops_process+1492>
            0x00aff664 <pixops_process+660>:        mov    0xfffffe94(%ebp),%eax
                                                                ^ c
            0x00aff66a <pixops_process+666>:        subl   $0x1,0xffffff3c(%ebp)
                                                                 ^ copy of i
        ?if (i<0) go 1453
            0x00aff671 <pixops_process+673>:        js     0xaff97d
<pixops_process+1453>
            0x00aff677 <pixops_process+679>:        test   %eax,%eax
        if c==0 goto 1453
            0x00aff679 <pixops_process+681>:        je     0xaff97d
<pixops_process+1453>
            0x00c5c67f <pixops_process+687>:        mov    0xfffffe94(%ebp),%ecx
                                                                ^^c 
            0x00c5c685 <pixops_process+693>:        subl   $0x4,0xffffff70(%ebp)
            0x00c5c68c <pixops_process+700>:        test   %ecx,%ecx
        if c!=0 go 608
            0x00c5c68e <pixops_process+702>:        jne    0xc5c630
<pixops_process+608>

    4.4 compare this code with <gdk_pixbuf_alpha_mode_get_type+6096> listed
        in #3: they are identical.  Very likely gdb identified correct_total()
        as <gdk_pixbuf_alpha_mode_get_type+6096>.

    4.5 This slow loop is the optimized code for
        correct_total (int    *weights, 
                       int    n_x, 
                       int    n_y,
                       int    total, 
                       double overall_alpha)
        {
          int correction = (int)(0.5 + 65536 * overall_alpha) - total;
          int remaining, c, d, i;

          if (correction != 0)
            {
              remaining = correction;
              for (d = 1, c = correction; c != 0 && remaining != 0; d++, c =
correction / d) 
                for (i = n_x * n_y - 1; i >= 0 && c != 0 && remaining != 0; i--) 
                  if (*(weights + i) + c >= 0) 
                    {
                      *(weights + i) += c;
                      remaining -= c;
                      if ((0 < remaining && remaining < c) ||
                          (0 > remaining && remaining > c))
                        c = remaining;
                    }
            }
        }




Comment 3 Matthias Clasen 2007-03-26 21:35:09 UTC
This is the well-known problem of gdk-pixbuf being not very clever when scaling
down images a lot. This is tracked upstream at
http://bugzilla.gnome.org/show_bug.cgi?id=80925