Medindo o desempenho do Qt

Decidi continuar a série de artigos sobre o Aurora OS (até recentemente chamado Sailfish). Durante o tempo em que trabalho com este sistema operacional, acumulei várias observações relacionadas ao desempenho de aplicativos no Qt e no sistema como um todo, porque ele é pendurado em uma variedade de dispositivos, como uma árvore de Natal, noto todas as pequenas coisas na inicialização. Eu acho que isso pode ser interessante e útil para colegas que também trabalham com o Qt (ou irão trabalhar em breve). Sugira que você pode testar mais.



Eu programa no Qt e frequentemente discuto com colegas, desenvolvedores de iOS, as semelhanças, diferenças e benefícios das abordagens. Em algum momento, ainda decidimos mudar de palavras para ações e fazer medições. Não encontramos um programador Android pronto para participar de nosso entretenimento; portanto, uma comparação com a participação de números e tabelas será apenas para Swift e C ++.

Quero lembrá-lo de que o Qt / C ++ não impõe seu mecanismo de gerenciamento de memória, e o próprio usuário resolve esse problema no âmbito dos recursos disponíveis no C ++, enquanto no Swift é usada a contagem de referência e no Java é um coletor de lixo. Assim, o programador tem a oportunidade de interagir com a memória com mais eficiência. Para enviar uma solicitação http ou ler dados de um banco de dados, o Qt conta com seus próprios pontos fortes e não usa estruturas prontas que o sistema operacional fornece. Exceções - interação com o teclado, desenhando a janela inicial do aplicativo, exibindo notificações e outras coisas.

Teste 1


Primeiro, decidimos escrever um algoritmo simples (a peneira de Eratóstenes), executá-lo em grandes números e comparar o tempo de cálculo. Lançado no iPhone 7.

Programa 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 } } 


Não vou me debruçar sobre o código em detalhes, o eratóstenes linear não é óbvio para a compreensão, especialmente se uma das línguas não lhe é familiar. Aqui está um link com uma descrição: https://e-maxx.ru/algo/prime_sieve_linear , que está interessado, pode verificar a honestidade. A propósito, a versão rápida acabou sendo um pouco mais otimizada nas pequenas coisas (você pode procurá-las), o que não impediu a versão positiva de obter o desempenho.

Programa 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; } 

Execute o programa. Os aplicativos têm um campo para inserir o número n, um botão de início e um campo com um tempo total:


Swift - à esquerda, Qt - à direita.

Resultado. Vou dar uma tabela de medidas para diferentes n e em diferentes momentos:

Como você pode ver, um aplicativo C ++ é aproximadamente 1,5 vezes mais rápido que um aplicativo nativo com algoritmos idênticos.

Teste 2


Naturalmente, a computação no contexto de aplicativos móveis é uma coisa importante, mas longe de ser a única. Portanto, desenhámos um ListView composto por 1000 elementos, cada um contendo texto e uma imagem, para observar a velocidade de renderização de elementos gráficos. Abaixo, nos vídeos, você pode ver o resultado:

Qt:

Swift:


Visualmente, a diferença não é perceptível.

Teste 3


No sistema operacional Sailfish, temos um kernel Linux e um shell nativo gráfico no Qt, e isso por si só sugere pensamentos sobre o bom desempenho desse sistema operacional. Costumo notar que o Inoi R7 vence em termos de velocidade de algumas tarefas, embora o Samsung Galaxy S8 faça o mesmo. Assim, por exemplo, o Samsung Galaxy S8 envia, recebe, processa, empacota em um banco de dados, etc. Solicitações de http de 10.000 em cerca de 3-4 minutos, e o Inoi R7 faz a mesma coisa por 5-6 minutos. Dada a diferença no desempenho do ferro, o resultado é impressionante.

Para um teste mais honesto do desempenho do sistema operacional, decidi analisar a velocidade de resposta do carrinho de mão.

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) } } } } 

Simples e despretensioso. Como não tenho um telefone compatível com Sailfish e Android para uso pessoal, tive que procurar nos meus colegas um telefone o mais próximo possível do Inoi r7, mas no Android. O que de repente se tornou muito difícil, considerando que estou sentado em um escritório de desenvolvimento móvel.

Sony Xperia Z5 compact:
Processador - Qualcomm Snapdragon 810 MSM8994, 2000 MHz
O número de núcleos do processador - 8
Processador de vídeo - Adreno 430
A quantidade de memória interna - 32 GB
A quantidade de RAM - 2 GB

Inoi R7:
Processador - Qualcomm Snapdragon 212 MSM8909AA, 1200 MHz
O número de núcleos do processador - 4
Processador de vídeo - Adreno 304
A quantidade de memória interna - 16 GB
A quantidade de RAM - 2 GB

A Sony ainda se mostrou mais poderosa, mas, para a equação de probabilidades, ativamos o modo de economia de energia, mesmo assim, isso não levará à completa igualdade de poder dos dispositivos. No vídeo, você pode ver que no Android a linha não é tão suave quanto no Sailfish.

Esquerda - Sony, direita - Inoi:



Não discuto, esse não é um indicador muito sério, você precisa comparar não apenas os recursos de uma linguagem pura, mas também bibliotecas diferentes, nativas e multiplataforma, para comparar seu desempenho e facilidade de uso, porque existem muito poucos aplicativos que usam apenas a peneira ListView e Eratóstenes. Embora todas essas coisinhas pareçam muito convincentes para mim.

Contras


Claro, nem tudo é tão bom com o Qt, como eu tento pintar aqui, há contras. Por exemplo, trabalhando com o TextInput no Android, você pode torturar perfeccionistas especialmente sensíveis a muletas, porque em cada dispositivo o Qt consegue colocar paus absolutamente únicos nas rodas ao interagir com o teclado. Em um telefone, a imagem é exibida, no outro ela fica parada, mas a EnterKey não funciona; no terceiro, somente as letras maiúsculas são sempre inseridas e não há como convencê-la a mudar para minúscula. Você pode continuar ad infinitum. E tudo isso também diminui! (Os grunhidos são relevantes apenas para o Android, não existem problemas no Sailfish, tudo funciona bem). Além disso, no Qt, é difícil obter a aparência nativa do aplicativo.

Conclusão


A principal conclusão que pode ser tirada: Qt, sendo uma ferramenta de plataforma cruzada, não é inferior em desempenho às ferramentas de desenvolvimento nativas. É perfeito para programas em que, além da GUI, ainda há muita matemática, e especialmente para aplicativos corporativos, onde existem muitas nuances e poucos funcionários, para não criar uma versão independente para cada sistema operacional. As funções são mais importantes para usuários corporativos que a interface do usuário nativa. Para o Aurora, o Qt é uma ferramenta nativa para desenvolvimento de aplicativos, o que provavelmente dá outro impulso no desempenho.

Seria interessante testar o Aurora em um hardware poderoso como o meu Galaxy S8.

Source: https://habr.com/ru/post/pt457622/


All Articles