Замеряем производительность Qt

    Решила продолжить цикл статей об ОС «Аврора» (до недавнего времени называвшейся Sailfish). За время, что я работаю с этой ОС, у меня накопились разные наблюдения, которые касаются производительности приложений на Qt и системы в целом, ибо девайсами разнообразными обвешана, аки ёлка новогодняя, все мелочи при запуске подмечаю. Думаю, что это может быть интересно и полезно коллегам, кто тоже работает с Qt (или в скором времени будет работать). Предлагайте, что можно протестировать ещё.



    Я программирую на Qt и часто обсуждаю с коллегами, iOS-разработчиками, сходства, различия и преимущества подходов. В какой-то момент мы всё-таки решили перейти от слов к делу и провести замеры. Android-программиста, готового участвовать в наших развлечениях, мы так и не нашли, так что сравнение с участием цифр и таблиц будет только для Swift и C++.

    Хочу напомнить, что Qt/C++ не навязывает свой механизм управления памятью, и пользователь сам решает этот вопрос в рамках доступных в C++ возможностей, в то время как в Swift используется подсчёт ссылок, а в Java — сборщик мусора. Таким образом у программиста появляется возможность взаимодействовать с памятью эффективнее. Для того, чтобы отправить http-запрос или считать данные из базы данных, Qt полагается на собственные силы, а не использует готовые фреймворки, которые предоставляет ОС. Исключения — взаимодействие с клавиатурой, отрисовка стартового окна приложения, вывод уведомлений и другие вещи.

    Тест 1.


    Первым делом мы решили написать простенький алгоритм (решето Эратосфена), позапускать его на больших числах и сравнить время вычислений. Запускали на iPhone 7.

    Программа на Swift:

    swift
    //
    //  ViewController.swift
    //  Eratosthenes
    //
    //  Created by Dmitry Shadrin on 22/11/2018.
    //  Copyright  2018 Digital Design. All rights reserved.
    //
    
    import UIKit
    
    class ViewController: UIViewController {
    
      @IBOutlet weak var digitTextField: UITextField!
      @IBOutlet weak var timeLabel: UILabel!
    
      @IBAction func startAction(_ sender: UIButton) {
        guard let text = digitTextField.text,
             let number = Int(text)
             else { return }
            prime(n: number)
        }
    
        func prime(n: Int) {
            let startTime = DispatchTime.now()
            let _ = PrimeSequence(upTo: n)
                .reduce(into: [], { $0.append($1) }) // Тот самый массив с числами
                
            let endTime = DispatchTime.now()
            let time = (endTime.uptimeNanoseconds - startTime.uptimeNanoseconds)
            timeLabel.text = "\(time)"
        }
    }
    
    public struct PrimeSequence: Sequence {
        private let iterator: AnyIterator<Int>
        
        public init(upTo limit: Int) {
            self.iterator = AnyIterator(EratosthenesIterator(upTo: limit))
        }
    
        public func makeIterator() -> AnyIterator<Int> {
            return iterator
        }
    }
    
    private struct EratosthenesIterator: IteratorProtocol {
        let n: Int
        var composite: [Bool]
        var current = 2
        
        init(upTo n: Int) {
            self.n = n
            self.composite = [Bool](repeating: false, count: n + 1)
        }
    
        mutating func next() -> Int? {
            while current <= self.n {
                if !composite[current] {
                    let prime = current
                    for multiple in stride(from: current * current,
                                           through: self.n, by: current) {
                        composite[multiple] = true
                    }
                    current += 1
                    return prime
                }
                current += 1
            }
            return nil
        }
    }


    Подробно останавливаться на коде не буду, линейный Эратосфен не очевиден для понимания, тем более если один из языков вам не знаком. Вот ссылка с описанием: https://e-maxx.ru/algo/prime_sieve_linear, кому интересно, может проверить на честность. Кстати, версия swift оказалась чуть более оптимизирована в мелочах (можете их поискать), что не помешало плюсовой версии всё-таки выиграть в производительности.

    Программа на Qt:
    #include "eratosthenes.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <QVector>
    #include <QDebug>
    #include <vector>
    #include <cmath>
     
    Eratosthenes::Eratosthenes(QObject *parent)
    {
    	time = 0;
    }          
     
    void Eratosthenes::qtFunction(int n)
    {
    	clock_t start, end;
    	start = clock();
     
    	std::vector<int> lp = std::vector<int>(n + 1, 0);
    	std::vector<int> pr;
    	// зарезервируем памяти под элементы с запасом
    	pr.reserve(std::sqrt(n) / 2);
     
    	for (int i = 2; i <= n; ++i) {
        	        if (lp[i] == 0) {
            	        lp[i] = i;
            	        pr.emplace_back(i);
        	        }
     
        	        for (int j = 0; j < pr.size() && pr[j] <= lp[i] && i * pr[j] <= n; ++j) {
            	        lp[i * pr[j]] = pr[j];
        	        }
    	}
     
    	end = clock();
    	time = (end - start) / (double)CLOCKS_PER_SEC;
    	pTimeChanged();
     
    	qDebug() << "Количество простых чисел" << pr.size() << "Время" << time;
    }

    Запускаем программу. Приложения имеют поле для ввода числа n, кнопку старт и поле с итоговым временем:


    Swift — слева, Qt — справа.

    Результат. Приведу таблицу замеров для разных n и в разные моменты времени:

    Как видите, приложение на С++ в ~1.5 раза быстрее нативного при идентичных алгоритмах.

    Тест 2.


    Естественно, вычисления в контексте мобильных приложений — штука важная, но далеко не единственная. Поэтому мы нарисовали ListView, состоящий из 1000 элементов, каждый из которых содержит текст и картинку, чтобы посмотреть ещё и на скорость отрисовки графических элементов. Ниже, в видеороликах, можно увидеть результат:

    Qt:

    Swift:


    Визуально разница не заметна.

    Тест 3.


    В ОС Sailfish мы имеем ядро Linux и графическую нативную оболочку на Qt, а это уже само по себе наталкивает на мысли о неплохой производительности этой ОС. Я часто замечаю, что Inoi R7 выигрывает по скорости выполнения некоторых задач, хотя рядом лежит и тем же самым занимается Samsung Galaxy S8. Так, например, Samsung Galaxy S8 отправляет, принимает, обрабатывает, упаковывает в БД и т.д. 10К http-запросов примерно за 3-4 минуты, а Inoi R7 всё то же самое делает минут 5-6. Учитывая разницу в производительности железа, результат впечатляющий.

    Для более честной проверки производительности ОС я решила посмотреть на скорость отклика тача.

    Test.cpp:


    #include "mypainter.h"
    #include <QPainter>
     
    MyPainter::MyPainter(QQuickItem *parent) : QQuickPaintedItem(parent)
    {
    }
     
    void MyPainter::paint(QPainter *painter)
    {
    	QPen pen;
    	pen.setWidth(10);
    	pen.setColor(Qt::red);
    	painter->setPen(pen);
    	painter->drawPolyline(pol);
    }
     
    void MyPainter::xyCanged(int x, int y)
    {
    	pol.append(QPoint(x, y));
    	update();
    }
    

    Test.qml:


    import QtQuick 2.9
    import QtQuick.Window 2.2
    import Painter 1.0
     
    Window {
    	visible: true
     
    	Painter
    	{
        	id: painter
        	anchors.fill: parent
        	MouseArea
        	{
            	anchors.fill: parent
     
            	onPressed:
            	{
                	painter.xyCanged(mouseX, mouseY)
            	}
     
            	onMouseXChanged:
            	{
                	painter.xyCanged(mouseX, mouseY)
            	}
     
            	onMouseYChanged:
            	{
                	painter.xyCanged(mouseX, mouseY)
         	   }
        	}
    	}
    }
    

    Просто и незатейливо. Телефона, поддерживающего Sailfish и Android, в личном пользовании меня нет, потому пришлось искать у коллег телефон максимально близкий по характеристикам к Inoi r7, но на Android. Что внезапно оказалось очень сложно, учитывая, что сижу я в офисе мобильной разработки.

    Sony Xperia Z5 compact:
    Процессор — Qualcomm Snapdragon 810 MSM8994, 2000 MHz
    Количество ядер процессора — 8
    Видеопроцессор — Adreno 430
    Объем встроенной памяти — 32 Гб
    Объем оперативной памяти — 2 Гб


    Inoi R7:
    Процессор — Qualcomm Snapdragon 212 MSM8909AA, 1200 МГц
    Количество ядер процессора — 4
    Видеопроцессор — Adreno 304
    Объем встроенной памяти — 16 Гб
    Объем оперативной памяти — 2 Гб


    Sony всё-таки оказалась мощнее, но для уравнения шансов включим на ней режим энергосбережения, всё равно это не приведёт к полному равенству мощности девайсов. На видео можно заметить, что на Android линия получается не настолько плавная, как на Sailfish.

    Слева — Sony, справа — Inoi:



    Не спорю, это все не очень серьёзный показатель, нужно сравнивать не только возможности чистого языка, но и разные библиотеки, нативные и кроссплатформенные, сравнивать их производительность и удобство в использовании, потому что очень мало приложений, которые используют только ListView и решето Эратосфена. Хотя все эти мелочи вместе для меня выглядят весьма убедительно.

    Минусы


    Конечно, всё не так радужно с Qt, как я пытаюсь тут расписать, минусы есть. Например, работой с TextInput на Android можно пытать особо чувствительных к костылям перфекционистов, потому что на каждом девайсе Qt умудряется ставить абсолютно уникальные палки в колёса при взаимодействии с клавиатурой. На одном телефоне картинка уезжает вверх, на другом — стоит на месте, но не работает EnterKey, на третьем всегда вводятся только заглавные буквы, и никак его не переубедить переключить на строчные. Продолжать можно до бесконечности. И всё это ещё и тормозит! (Ворчания актуальны только для Android, на Sailfish таких проблем не возникает, всё отлично работает). Кроме того, на Qt сложно добиться нативности внешнего вида приложения.

    Вывод


    Главный вывод, который можно сделать: Qt, будучи кроссплатформенным инструментом, не уступает в производительности нативным средствам разработки. Он отлично подойдёт для программ, в которых помимо GUI есть ещё много математики, и в особенности для корпоративных приложений, где много нюансов и мало сотрудников, чтобы для каждой ОС не создавать самостоятельную версию. Корпоративным пользователям больше важны функции, чем нативность UI. Для «Авроры» Qt — нативное средство для разработки приложений, что, вероятно, даёт ещё какой-то прирост к производительности.

    Было бы интересно испытать «Аврору» на мощном железе, вроде моего Galaxy S8.
    Digital Design
    51,89
    Компания
    Поделиться публикацией

    Комментарии 36

      +4
      Sony Xperia Z5 compact:
      Процессор — Qualcomm Snapdragon 810 MSM8994, 2000 MHz
      Количество ядер процессора — 8
      Видеопроцессор — Adreno 430
      Объем встроенной памяти — 32 Гб
      Объем оперативной памяти — 2 Гб

      Inoi R7:
      Процессор — Qualcomm Snapdragon 212 MSM8909AA, 1200 МГц
      Количество ядер процессора — 4
      Видеопроцессор — Adreno 304
      Объем встроенной памяти — 16 Гб
      Объем оперативной памяти — 2 Гб

      Sony всё-таки оказалась мощнее, <...> На видео можно заметить, что на Android линия получается не настолько плавная, как на Sailfish.

      image
        +2

        Эм, разве это так очевидно? Тут не уточняется, но вроде на Inoi как раз Sailfish, а на Sony — Android, т.е. на более слабом телефоне отрисовка выходит лучше, чем на более мощном. Без энергосбережения ещё было бы интересно попробовать, возможно, тут эффект не от снижения частоты процессора, а от менее частых опросов конкретно тача.

          0
          Честно говоря, я не заметила разницы от включения энергосбережения. Снимала с ним для морального уравнивания шансов)
        0
        Под сейлфиш есть полтора приложения, под айос и андроид миллионы, о чем тут еще говорить? Даже Гейтс недавно сказал что без экосистемы операционная система сейчас никому не нужна (конечно кроме нескольких тысяч нердов, но на них не заработаешь). А то что там где-то как то что-то считается быстрее — да кого это волнует уже?
          0

          Насколько я помню, в Sailfish есть поддержка Android-приложений, т.е. именно количество так остро сказываться не будет. Да и разве нужны миллионы? Навскидку нужно отсилы 50 самых нежных приложений, и до 1000 желательных, без остального вполне можно жить.
          Но вообще, конечно, сама операционка, как приемник MeeGo, в свое время вселяла надежду. Я Вам как пользователь последней могу с уверенностью сказать — уже при широком распространении Android в 2012-2013 году мне вполне комфортно было, а некоторые вещи и вовсе были ощутимо лучше, например камера: на Nokia N9 стояла оптика Carl Zeiss, в сочетании с нативной реализацией приложения получался просто выдающийся результат. Были и другие хорошие приложения. В общем, сплошь приятный опыт. Было бы здорово, если бы за ОСь взялась крупная контора, а не частная компания с непонятными целями...

            0
            Вот на этих вполне заработаешь.
            Для работы миллионы свистоперделок в AppStore не нужны.
              0
              Я не продаю эту ОС, а подмечаю ее приятные стороны с точки зрения разработчика. Комментарий с рассуждениями о механизмах работы с памятью под рекламно-маркетинговым постом был бы настолько же уместен, как этот здесь.
                0

                Не полтора. Проблема только небольшим набором приложений.
                Во-первых, с банковскими, которые можно надежно ставить только из магазина, но которых в магазине Sailfish просто нет.
                Во-вторых, нет нативного офиса (ставится андроидовский).
                В-третьих, нет некоторого количества полезных для разных узких применений экзотических приложений (впрочем, часть их доступна из андроидовских).
                Остальное (по полезной функциональности, а не по конкретным приложениям) вполне доступно в достаточно качественном исполнении (не хуже, чем на андроиде).

              • НЛО прилетело и опубликовало эту надпись здесь
                  0
                  Честно говоря, другими языками я владею заметно хуже, чем С++, так что не могу объективно сравнить)
                  А qml считается очень простым, и на нем можно писать полноценные приложения)
                  • НЛО прилетело и опубликовало эту надпись здесь
                      +1
                      Не совсем. Я просто восхваляю Qt перед нативными средствами разработки)
                  +2
                  Эм… а где в первом «тесте» что-то кьютовое кроме неиспользуемого QObject'а, вывода qDebug и eventLoop'a?

                  Ну и:
                  Я часто замечаю, что Inoi R7 выигрывает по скорости

                  Samsung Galaxy S8 <...> за 3-4 минуты, а Inoi R7 <...> минут 5-6

                  У меня оператор сравнения в голове сломался?
                    0
                    1. А в чем проблема использования чистых плюсов/си в Qt? Это разве запрещено?
                    2. Учтите мощность железа и он обязательно починится)
                      +1
                      1. Пост озаглавлен: "Заменяем производительность Qt", объявлен кьютишный контейнер QVector, но он не используется. Так-то это сравнение плюсОв и свифта, а Qt тут совсем ни при чём.
                      2. Чудес бюджетный проц не творит — он медленнее (судя по попугаям) 810 снэпа на, примерно, 30%, что и показывают примерные замеры.
                        0
                        1. Инструмент, а не библиотека.
                        2. По всем характеристикам Samsung лучше в 2 и более раз, а не на 30%.
                          +1

                          Samsung лучше в 2 и более раз, но и потребителей этого перфоманса тоже побольше, чем в бюджетном телефоне.
                          В первую очередь: Qt это именно библиотека. Код из первого примера скомпилируется и без неё.

                        0
                        2. Я, конечно, не эксперт, но возможно, чисто случайно, это стоило бы упомянуть в том же абзаце.
                      0
                      Я прошёл путь от программирования на ASM «Минск-32» и ЕС ЭВМ до MS ASM и C# (для меня он выше по программисткой производительности, чем C++ с его нестабильной разудалой архитектурой). Я ровесник Билла Гейтса, который ушёл на пенсию. С обидой смотрел, как правители спали более полувека, не давая развития (не давая заказов) массовой микроэлектронике и программированию: слишком дёшево доставалась наёмная инженерная сила советской власти во всё её время существования. За это и расплачивается сейчас вся страна. Дерзайте! Слишком много упущено, но если выбросить «аджайлы» и вместо них заняться системной разработкой при наличии госзаказа и отсутствии «распила» (ещё совсем недавно убедился в обратном в Белоруссии) — в чём очень сомневаюсь при Путине, то можно резко сэкономить по времени. Своя операционная система необходима была всегда по многим причинам и в безопасности — в первую очередь.
                        0
                        Мы тоже надеемся, что все срастется)
                          0
                          Так «Аврора»Sailfish такая же «своя» как сертифицированная ОС «Цитадель». То, что купили лицензию у финов — не делает её отечественной.
                          0
                          Я правильно понял что вы используете Qt для кроссплатформенной разработки? Если да, то скажите как вы боритесь с тем что кросплатформенность у него мозаичная (некоторые части работают только на отдельных платформах) и насколько это вообще критично если постоянно разрабатывать на нем fulltime?
                          На всякий случай опишу откуда взялся вопрос — у меня есть pet project на qt который я по мере надобности обновляю на новую версию. C выходом os x mojave (и изменений в ней из-за черной темы) пришлось обновляться до новой версии 5.12 и вот тут меня ждал сюрприз — в iOS 5.12 + не запускаются компоненты из Controls 1 (по крайней мере без танцев с бубном, подробно если честно я так и не посмотрел потому как до недавнего времени продолжал пользоваться давно собранной версией с 5.11), а альтернатива того что мне нужно (в основном диалоги)в 5.13 в свою очередь не работает в андроид согласно документации. Конечно, это все решаемо- можно и разными версиями собирать, и всякие платформоспецифические обертки написать, но я в серьез задумался «а надо ли оно мне» или же все-таки послать qt с его не полной кроссплатформенностью (а это не первый раз так, я даже несколько багов в свое время заводил на тему того что очередная фича не работает на той или иной платформе) и посмотреть на что-то еще. Может быть, если писать на qt постоянно на работе это не так критично вот и хочу услышать ваше мнение

                          Кстати по поводу вашего второго теста — у меня было что-то подобное и если картинки заранее подготовлены и правильного размера, то все хорошо, но вот если их надо ресайзить прямо по месту, то qt сливает — таблица еле скроллится, мне пришлось добавлять кеш для подготовленных картинок. Может в более новых версиях qt это и не так, но раньше все было очень плохо
                            0
                            Очень ярко выражена эта недокроссплатформенность в Sailfish, для них это нативный инструмент и различия колоссальны. Например, у меня main.cpp сделан через условную компиляцию для Sailfish и всех остальных. И такого много.
                            По поводу GUI:
                            Я не использую QQC вообще, все на голом QtQuick, ибо это единственная точка пересечения Sailfish с остальными ОС) так что да, пишу велосипеды, иногда сложные, но это весело)
                              0
                              Спасибо за ответ. Голый QtQuick это как-то совсем жесть, хотя я его тоже использовал когда Controls назывались QtDesktop components и не входили в поставку qt.
                              0
                              Controls 1 давно deprecated, не развиваются и considered for removal:

                              wiki.qt.io/New_Features_in_Qt_5.11 (см. раздел Deprecated Modules),

                              переползайте на Controls 2. С ними я особых проблем не замечал ни на iOS, ни на Android.
                                0
                                Я выше написал, фактически единственное что мне было нужно это Dialogs, а точнее FileDialog и его в Controls 2 нету, а тот что есть в Qt.labs.platform (не проверял) согласно документации не поддерживается в android.
                                  0

                                  Ну, FileDialog — это такое… Кроссплатформенность его на мобильниках весьма условна, на том же iOS он абсолютно бесполезен. Так что Qt'шников можно понять.

                                    0
                                    так на iOS он как раз вроде бы есть, а вот на android его нет хотя уж там-то он вроде нужен
                                      0

                                      Ну если так, то это, конечно, забавно :)

                              0

                              Быстродействие быстродействием. Но справедливости ради, если брать open-source лицензию Qt, то я готов жертвовать быстродействием ради экономии ~30Мб места (и это с отбрасыванием ненужных модулей/плагинов). Под мобильные платформы, как мне кажется, экономия по памяти важнее экономии по скорости

                                0
                                Кстати, уточню вопрос — раз Кьют родной, то наверное и тянуть его .dll/.so с каждым приложением для Сэйлфиш не нужно? Какой минимальный размер получается у приложения?
                                  +1
                                  На SFOS не нужно тянуть Qt, конечно.
                                  Типичные размеры можно посмотреть на openrepos.net
                                  Например, клиент Телеграм размером меньше мегабайта.
                                  +3

                                  Клиент facebook непонятно чем забивает 150 мегабайт. Но им все же пользуются. Тоже и для всяких электронподелок

                                  0
                                  Например, работой с TextInput на Android можно пытать особо чувствительных к костылям перфекционистов, потому что на каждом девайсе Qt умудряется ставить абсолютно уникальные палки в колёса при взаимодействии с клавиатурой.

                                  На Android слишком много клавиатур, которые работают «немного по-разному», разные производители любят ставить разные клавиатуры, например, Sony ставит SwiftKey вместо GBoard. Но проблемы постепенно чинятся, утверждается, что в 5.12.5 и далее input on android будет almost perfect:

                                  bugreports.qt.io/browse/QTBUG-43156
                                  codereview.qt-project.org/c/qt/qtbase/+/264060

                                  :)
                                    0
                                    А вот интересно, проблема с зоопарком клавиатур только у Qt или какая-нибудь Android Studio тоже от этого страдает?
                                      0
                                      Нативные компоненты, по идее, меньше всего страдают, потому что клавиатуры при разработке тестируются на совместимость именно с ними. Но в целом я регулярно вижу в отзывах на произвольные приложения в Google Play жалобы на проблемы с определённой клавиатурой. В целом я сталкивался с тем, что от GBoard например при нажатии Enter приходит именно символ \n, а от SwiftKey — только событие нажатия клавиши Enter, и это нужно обработать и перевести в символ самостоятельно. Такие вот мелкие различия там явно есть.

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое