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
Created attachment 150866 [details] sample file that caused gtk2 slowness.
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; } } }
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