Portál AbcLinuxu, 24. dubna 2024 08:42

Pomalá fce Gdk::Pixbuf::create_from_file() na Windows

16.6.2013 11:53 | Přečteno: 1609× | Programování | Výběrový blog | poslední úprava: 16.6.2013 11:56

Narazil jsem na problém s rychlostí fce Gdk::Pixbuf::create_from_file() v Gtkmm 2.22 pod Windows. Pokud se použije pro načtení cca 4MB JPEGu 5600x3700, tak jí to trvá cca 10s.

Na Linuxu to trvá této fci cca 350ms. Pod Wine se tento problém neprojevuje, načtení trvá jen o něco málo déle než na Linuxu. Použil jsem ftp.gnome.org/pub/GNOME/binaries/win32/gtkmm/2.22. Zkoušel jsem i některé starší verze knihovny, ale problém přetrvával.

Něchtělo se mi ztrácet čas zbytečnou kompilací celé knihovny a všech jejich závislostí, tak jsem hledal zda-li se nedají sehnat binárky někde jinde. A našel jsem je např. v OpenSUSE 12.3 ve verzi 2.24.2, tyto binárky fungují bez problémů i ve Windows.

Vývoj dělám v Debian Wheezy a verzi pro Windows kompiluji cross-kompilátorem z projektu MinGW, který je jeho součástí. Binárky pro Windows testuji většinou pod Wine a na čistých Windows až před vydáním další ostré verze.

Uvítal jsem, že je yum součástí Debianu:

# aptitude install yum

Přidáme repozitář s potřebnými balíčky:

# vim /etc/yum/repos.d/opensuse.repo
[windows_mingw_win32]
name=Cross-toolchain for 32-bit windows and 32-bit windows packages (openSUSE_12.3)
type=rpm-md
baseurl=http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_12.3/
gpgcheck=1
gpgkey=http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_12.3/repodata/repomd.xml.key
enabled=1

Zjistíme v jakých balíčcích se nachází knihovna Gtkmm a nainstalujeme je:

# yum search gtkmm2
=== Matched: gtkmm2 ===
mingw32-gtkmm2.noarch : C++ bindings for GTK+2
mingw32-gtkmm2-debug.noarch : Debug information for package mingw32-gtkmm2
mingw32-gtkmm2-devel.noarch : C++ bindings for GTK+2 (devel)

# yum install mingw32-gtkmm2-devel.noarch mingw32-gtkmm2.noarch

Dotážeme se kde se nachází řídící soubory pro pkgconfig, abychom mohli pohodlně předávat potřebné parametry kompilátoru:

# rpm -q -l mingw32-gtkmm2-devel.noarch |grep pkgconfig
/usr/i686-w64-mingw32/sys-root/mingw/lib/pkgconfig/gdkmm-2.4.pc
/usr/i686-w64-mingw32/sys-root/mingw/lib/pkgconfig/gtkmm-2.4.pc

# PKG_CONFIG_PATH=/usr/i686-w64-mingw32/sys-root/mingw/lib/pkgconfig pkg-config --cflags --libs gtkmm-2.4

Vzhledem k tomu, že nechci instalovat závislosti cross-kompilátoru z OpenSUSE, tak jsem použil Windows verzi kompilátoru a spouštím jí pod Wine:

# yum install mingw32-gcc.noarch mingw32-gcc-c++.noarch

Třeba se to bude někomu hodit. Pokud má někdo nějaké tipy a zkušenosti k tématu, budu rád, když se o ně podělíte v diskuzi.

Zjistíme kde má MinGW knihovny:

$ yum whatprovides '*/libstdc++-6.dll'
/usr/i686-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll

Vypíšeme seznam knihoven, které musíme přibalit k binárce:

$ ./dll_dependencies.py gdk_pixbuf_create_from_file.exe /usr/i686-w64-mingw32/sys-root/mingw/bin 
libgcc_s_sjlj-1.dll
libgdkmm-2.4-1.dll
libcairomm-1.0-1.dll
libcairo-2.dll
libfontconfig-1.dll
libfreetype-6.dll
zlib1.dll
libxml2-2.dll
libpixman-1-0.dll
libpng15-15.dll
libsigc-2.0-0.dll
libstdc++-6.dll
libgdk_pixbuf-2.0-0.dll
libgio-2.0-0.dll
libglib-2.0-0.dll
libintl-8.dll
libgmodule-2.0-0.dll
libgobject-2.0-0.dll
libffi-6.dll
libjasper-1.dll
libjpeg-8.dll
libtiff-5.dll
liblzma-5.dll
libgdk-win32-2.0-0.dll
libpango-1.0-0.dll
libpangocairo-1.0-0.dll
libpangoft2-1.0-0.dll
libharfbuzz-0.dll
libpangowin32-1.0-0.dll
libglibmm-2.4-1.dll
libgtk-win32-2.0-0.dll
libatk-1.0-0.dll
libpangomm-1.4-1.dll
libgtkmm-2.4-1.dll
libatkmm-1.6-1.dll
libgiomm-2.4-1.dll

dll_dependencies.py

#!/usr/bin/python

import os
import sys
from subprocess import Popen, PIPE

DLLS_BLACKLIST = [
    "KERNEL32.dll",
    "msvcrt.dll",
    "USER32.dll",
    "GDI32.dll",
    "WS2_32.dll",
    "MSIMG32.DLL",
    "ADVAPI32.dll",
    "DNSAPI.DLL",
    "ole32.dll",
    "SHELL32.DLL",
    "WINMM.DLL",
    "SHLWAPI.DLL",
    "IMM32.DLL",
    "USP10.dll",
    "COMCTL32.DLL",
    "COMDLG32.DLL",
    "WINSPOOL.DRV",
]

class DllDependencies:
    def __init__(self, program_exe, dlls_path):
        self.dlls_path = dlls_path
        self.result = []
        self.get_dlls(program_exe)

        print "\n".join(self.result)

    def get_dlls(self, program_exe):
        if (not os.path.isfile(program_exe)):
            print "%s not found" % program_exe
            return

        pipe = Popen("objdump -x %s |\
                      grep 'DLL Name' |\
                      sort |\
                      uniq" % program_exe,
                     shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    
        for line in pipe.stdout.readlines():
            dll = line.strip().split()[2]
            if ((dll not in DLLS_BLACKLIST) and (dll not in self.result)):
                self.result.append(dll)
                dll = "%s/%s" % (self.dlls_path, dll)
                self.get_dlls(dll)

def main():
    if (len(sys.argv) != 3):
        print "Usage: %s PROGRAM_EXE DLLS_PATH" % sys.argv[0]
        sys.exit(-1)

    DllDependencies(sys.argv[1], sys.argv[2])

if __name__ == '__main__':
    main()

Makefile:

GPP = g++ -O2 -Wall
#W_GPP = i686-w64-mingw32-g++ -O2 -Wall
W_GPP = /usr/i686-w64-mingw32/sys-root/mingw/bin/g++.exe -O2 -Wall

GTKMM = `pkg-config --cflags --libs gtkmm-2.4`

PKG_CONFIG_PATH = /usr/i686-w64-mingw32/sys-root/mingw/lib/pkgconfig
W_GTKMM_CFLAGS = `PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --cflags gtkmm-2.4`
W_GTKMM_LIBS = `PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --libs gtkmm-2.4`

all: gdk_pixbuf_create_from_file gdk_pixbuf_create_from_file.exe

gdk_pixbuf_create_from_file: gdk_pixbuf_create_from_file.cpp
	$(GPP) $(GTKMM) -o gdk_pixbuf_create_from_file gdk_pixbuf_create_from_file.cpp

gdk_pixbuf_create_from_file.exe: gdk_pixbuf_create_from_file.cpp
	$(W_GPP) $(W_GTKMM_CFLAGS) -o gdk_pixbuf_create_from_file.exe gdk_pixbuf_create_from_file.cpp $(W_GTKMM_LIBS)

gdk_pixbuf_create_from_file.cpp:

#include <gtkmm.h>
#include <glib.h>
#include <iostream>

#ifdef WIN32
// Windows
#include <windows.h>
// UINT64
//#include <basetsd.h>
#else
// Linux
#include <sys/time.h>
#include <ctime>
// uint64_t
//#include <stdint.h>
#endif

void print_timestamp(const char *p_msg)
{
    static guint64 milliseconds_begin = 0;
    guint64 milliseconds;

    // http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
#ifdef WIN32
    // Windows
    FILETIME ft;
    LARGE_INTEGER li;
    
    // Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
    // to a LARGE_INTEGER structure.
    GetSystemTimeAsFileTime(&ft);
    li.LowPart = ft.dwLowDateTime;
    li.HighPart = ft.dwHighDateTime;
    
    milliseconds = li.QuadPart;
    milliseconds -= 116444736000000000LL; // Convert from file time to UNIX epoch time.
    milliseconds /= 10000; // From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals
#else
    // Linux
    struct timeval tv;
    
    gettimeofday(&tv, NULL);
    
    milliseconds = tv.tv_usec;

    // Convert from micro seconds (10^-6) to milliseconds (10^-3)
    milliseconds /= 1000;
    
    // Adds the seconds (10^0) after converting them to milliseconds (10^-3)
    milliseconds += (tv.tv_sec * 1000);
#endif

    if (milliseconds_begin == 0) {
        milliseconds_begin = milliseconds;
    }

    std::cout << "timestamp - " << p_msg << ": " << (milliseconds - milliseconds_begin) << "ms" << std::endl;
    milliseconds_begin = milliseconds;
}

int main(int argc, char *argv[])
{
    Glib::RefPtr<Gdk::Pixbuf> image;

    Gtk::Main kit(argc, argv);

    print_timestamp("BEGIN");
    image = Gdk::Pixbuf::create_from_file("image.jpeg");
    print_timestamp("END");
}
       

Hodnocení: 100 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (2) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Diskuse byla administrátory uzamčena

16.6.2013 12:00 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Pomalá fce Gdk::Pixbuf::create_from_file() na Windows
OT: btw, v C++11 už bude možné vypustit ten ifdef WIN32 díky std::chrono.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.6.2013 12:12 Jardík
Rozbalit Rozbalit vše Re: Pomalá fce Gdk::Pixbuf::create_from_file() na Windows
Super, ale na co proboha ta 32bit šmejďárna? Vždyť jsou tam i 64bit balíčky.
16.6.2013 15:13 smazáno | skóre: 18 | blog: smazáno
Rozbalit Rozbalit vše Re: Pomalá fce Gdk::Pixbuf::create_from_file() na Windows
Silenost :-)
16.6.2013 19:24 JZD | skóre: 14 | blog: Na_dvorku
Rozbalit Rozbalit vše Re: Pomalá fce Gdk::Pixbuf::create_from_file() na Windows
To chce tučňáka.
Víra znamená vyznávat to, o čem člověk dobře ví, že to není pravda. Mlčeti platina, mluviti v gajzu, býti v hajzlu.
20.6.2013 18:32 GeoRW | skóre: 13 | blog: GeoRW | Bratislava
Rozbalit Rozbalit vše Re: Pomalá fce Gdk::Pixbuf::create_from_file() na Windows
tak toto by som kvoli Windows vobec neriesil :-)
"This is to be taken with a grain of salt." ACBF - Advanced Comic Book Format

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.