Luca Ottaviano Ottimizzare applicazioni Qt Gui Firenze, 8 luglio 2013
Chi sono Luca Ottaviano lottaviano@develer.com @lucaotta Sviluppatore su sistemi embedded presso Develer Qt certified developer Sviluppatore Python
Prerequisiti Conoscenza dei meccanismi di base di Qt Signal/slots Implicit sharing Gestione della memoria tramite parent/child Conoscenza di Qt GUI Programma compilato su PC!
La vostra applicazione è compilabile su PC, vero? Ciclo code build test molto più veloce Strumenti di debugging più comodi Possibilità di profilazione Unit test Doppia implementazione
Tips and tricks Test dell'architettura nei file di progetto Abilitare selettivamente il codice usando macro Compilare sempre su PC e almeno una volta al giorno su board
Strumenti di profiling Callgrind: tempo di esecuzione Massif: occupazione di memoria Qml profiler: tempo di esecuzione specifico per QML
Evitare i calcoli floating point
Floating point: tipologie Soft: emulazione completa Softfp: passare i parametri all'fpu nei registri interi Hardfp: parametri di funzioni nei registri FPU Disponibile da GCC 4.5 Cortex-A8 Riferimenti: http://wiki.debian.org/armhardfloatport/vfpcomparison
Floating point: performance Emulazione molto lenta (50x 100x) di hard float Su processori piccoli (250 Mhz) si sente Pochi calcoli sono ammessi
Esempio: widget di un grafico
Invocazione di funzioni tramite signal/slot
Signal/slots Spezzano il flusso del codice Difficile fare review Sono sincroni (tranne un tipo) Sono LENTI! Circa 100x rispetto a chiamare lo slot direttamente Evitarli nei loop stretti
Esempio: loop stretto con segnali Widget::Widget(QObject *parent): QObject(parent){ connect(this, &Widget::sig1, this, &Widget::doSomething); } int Widget::entryPoint(int var) { for (int i = 0; i < var; ++i) { emit sig1(i); // dosomething(i); } return var; } int Widget::doSomething(int i) { return i + i; }
Esempio: loop stretto con segnali (2) int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; QTime start; start.start(); w.entrypoint(10000000); qdebug() << "Time elapsed:" << start.elapsed(); } return a.exec();
Esempio: risultati Debug (= senza ottimizzazione) Signal/slot = 853 ms Function call = 35 ms Release (= -02) Signal/slot = 705 ms Function call = 0 ms (!) _ZN6Widget10entryPointEi(): 401ac0: 89 f0 mov %esi,%eax 401ac2: c3 retq
Styling tramite CSS
QWidget e i CSS Non abusare dei CSS La valutazione di un CSS è lenta Preferire uno stylesheet a livello di applicazione Minimizza l'uso di memoria Usare le property per cambiare CSS applicato
Esempio: property vs nuovo stylesheet // MyWidget.cpp... Qstring s = "QWidget[SecondFgColor=\"true\"] {color:#6fb2ff;}" this >setstylesheet(s);... // CSS QWidget[SecondFgColor="true"] {color:#6fb2ff;} // MyWidget.cpp... this >setproperty("secondfgcolor", true); this >style() >polish(this);...
Gestione della memoria
Tempo di vita degli oggetti In C++ allocare un oggetto con new è un leak......a meno che non si distrugga con delete...oppure si assegni il parent del Qobject ATTENZIONE! Finchè il parent resta vivo, gli oggetti restano in vita Esempio: QTcpServer::nextPendingConnection()
Gestione della memoria (1) int main (int argc, char **argv) { // setup the GUI and Qapplication //... QPixmap splashpixmap( ":/img/splash.png" ); QSplashScreen splash(splashpixmap); splash.show(); } splash.finish(&main_window); return app.exec()
Gestione della memoria (2) MySplashScreen::MySplashScreen(const QString &path) : QSplashScreen(QPixmap(path)) { } int main(int argc, char **argv) { // setup the GUI and Qapplication //... MySplashScreen *splash = new MySplashScreen(":/img/splash.png"); splash >setattribute(qt::wa_deleteonclose); splash >show(); } splash >finish(&main_window); return app.exec();
Le dimensioni contano Usare immagini di dimensioni giuste Si usa solo la memoria necessaria Attenzione a QpushButton e Qicon Attenzione al GUI Designer! Non condivide le pixmap tra form diverse
Usare hardware adeguato 1 pixmap 1024 x 768 x 32 sono 2.3 Mb di RAM ~3.5% su un sistema con 64 Mb 10 icone 50 x 50 x 32 sono 100 kb di RAM ~ 1% su un sistema con 64 Mb Di solito ci sono centinaia di icone!
Font prerenderizzati (QPF2) Font non scalabili (bitmap) Dimensione fissa Poco costo di CPU per gestirli (rispetto ai TTF) Possono gestire tutte le lingue
Scrivere widget custom I widget standard sono generici Non molto efficienti Ottimizzare usando il QPainter Non riscrivere prima di aver fatto profiling!
Let's Talk office +39 055 3984627 (218) e-mail lottaviano@develer.com web www.develer.com twitter @lucaotta Credits Le immagini sono prese dal libro Pro Git http://git-scm.com/book