Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial Internet of Things >> Integrado

Como garantir o melhor desempenho da máquina de estado Qt


Se você usa Qt para desenvolvimento de aplicativos e se usa máquinas de estado, é provável que esteja utilizando a estrutura de máquina de estado do Qt. Portanto, você definirá a máquina de estado usando C ++ ou SCXML simples. Uma abordagem alternativa é gerar código C ++ a partir de diagramas de máquina de estado. Este artigo compara essas abordagens, levando em consideração a funcionalidade, a aplicabilidade e o desempenho.

Aposto que, como desenvolvedor de software, você já implementou toneladas de declarações de switch-case mais ou menos complicadas. Isso é pelo menos verdadeiro para mim, e muito dessa codificação de switch-case era essencialmente nada além de implementar máquinas de estado diversas. Esta é a maneira mais fácil de iniciar a programação de máquinas de estado se você não tiver mais nada em mãos do que a linguagem de programação de sua escolha. Embora o início seja fácil, esse código se torna cada vez menos passível de manutenção à medida que a complexidade da máquina de estado aumenta. No final, você ficará convencido de que não deseja continuar implementando máquinas de estado manualmente dessa forma. (A propósito - estou assumindo que você sabe o que são máquinas de estado.)

Implementando máquinas de estado

Existem diferentes alternativas para implementar máquinas de estado. Uma das melhores maneiras - especialmente quando você está usando uma linguagem de programação orientada a objetos como C ++ - é aplicando o padrão de estado. Essa abordagem usa classes de estado e frequentemente também classes de transição. Uma máquina de estado é então definida criando instâncias de classes de estado e conectando-as usando instâncias de classes de transição. Nesse caso, uma estrutura ajuda muito a reduzir o tamanho do código e o esforço de implementação.

A estrutura da máquina de estado Qt é um bom exemplo. Esta API permite “configurar” uma máquina de estado usando código compacto. Você não precisa se preocupar com os detalhes da semântica de execução da máquina de estado, pois eles já são implementados pelo framework. Você ainda precisa escrever código e, à medida que sua máquina de estado se torna mais complexa e contém algumas dezenas ou mesmo centenas de estados, será realmente difícil obter uma visão geral. Uma imagem vale mais que mil palavras, e o conhecido conceito de diagramas de estado ajuda a superar essa restrição. O próprio Qt fornece suporte para State Chart XML (SCXML), que é um padrão W3C. Como escrever XML manualmente não é divertido, Qt Creator também inclui um editor gráfico de estados simples.

Independentemente da abordagem de implementação concreta, usar uma sintaxe gráfica é a melhor escolha para editar e compreender máquinas de estado. Esses modelos gráficos não só podem ser representados textualmente por linguagens como SCXML, mas também podem ser usados ​​para gerar qualquer tipo de código-fonte de linguagem de programação, como uma máquina de estado baseada em switch-case em C ++ simples - ou código C ++ que configura instâncias de QStateMachine. Usando uma ferramenta que faz essa transformação para você, você pode evitar a dor de escrever código de máquina de estado à mão. Ele eleva todas as três abordagens de implementação ao mesmo nível de usabilidade. No entanto, as implementações ainda são fundamentalmente diferentes. Este artigo é sobre como comparar seu comportamento em tempo de execução e, especialmente, seu desempenho.


UnsplashPhoto de Austris Augusts no Unsplash

Os concorrentes

E quanto ao desempenho? Como as abordagens disponíveis diferem em relação aos ciclos de CPU necessários? Para obter alguns números concretos, configurei um conjunto de testes de desempenho. A primeira parte compara as diferentes estratégias de implementação. Estes são os concorrentes:

  1. interpretador SCXML - a máquina de estado de teste é definida usando SCXML e executada por QSCXMLStateMachine da Qt classe.
  2. Padrão de estado - a máquina de estado de teste é implementada usando QStateMachine aulas.
  3. Código C ++ simples - a máquina de estado de teste é implementada por uma classe C ++ que aplica uma abordagem básica baseada em casos de switch.

Observação:o código para esses exemplos pode ser encontrado aqui.

As duas primeiras variantes implicam no uso de conceitos Qt como sinais e slots, bem como o uso de uma fila de eventos Qt, enquanto uma implementação C ++ simples não requer esta infraestrutura. Para tornar as abordagens mais comparáveis, o conjunto de testes inclui mais dois cenários de teste:

Isso torna possível comparar o impacto do uso de sinais e slots por um lado e o uso de QEvents por outro lado, em comparação com a implementação C ++ simples, uma vez que o código de execução da máquina de estado é idêntico em todos os casos, mas apenas empacotado de forma diferente.

A máquina de estado de teste

Para testar todos os cinco competidores, defini a máquina de estado mostrada na fig. 1 para o cenário de teste básico.


Figura 1:A máquina de estado de teste, criada com YAKINDU Statechart Tools. (Fonte:Autor)

A máquina de estado de teste é uma máquina de estado plano simples. Ele define seis estados A para F e percorre os estados. Dois eventos de entrada e1 e e2 são definidos, que ativam alternadamente as transições de estado. Quando ocorre uma transição de estado, também uma ação simples é executada. Cada ação de transição simplesmente adiciona 10 a uma variável de gráfico de estado chamada x . A transição do estado F para A além disso, aumenta (ou emite) o para fora evento o .


Figura 2:A máquina de estado de teste como um modelo SCXML no Qt Creator. (Fonte:Autor)

Esta máquina de estado foi definida usando YAKINDU Statechart Tools, que suporta a geração de SCXML. Este SCXML pode ser adicionado ao projeto Qt e pode ser editado no Qt Creator. Como você pode ver na fig. 2, a máquina de estado tem uma estrutura idêntica à da fig. 1, mas alguns detalhes, como as ações de transição, não são visíveis no Qt Creator. As ferramentas de gráfico de estatística YAKINDU fornecem mais algumas vantagens, mas não as discutirei aqui.

Mais importante aqui é o fato de que YAKINDU Statechart Tools também pode gerar classes de máquina de estado C ++ baseadas em casos de switch simples. Ele também fornece uma opção para gerar classes habilitadas para Qt com sinais e slots, então isso é útil. Usando esta ferramenta, eu só tive que implementar a máquina de estado baseada em padrões de estado usando QStateMachine à mão. Não havia gerador de código disponível para essa variante. No entanto, consegui economizar muito esforço de implementação, enquanto obtive máquinas de estado semanticamente equivalentes para os testes de desempenho apenas usando uma única definição de gráfico de estado.

Todos os casos de teste seguem o mesmo esquema. Como eu queria medir o tempo médio necessário para processar eventos individuais, cada teste capturou um milhão de iterações de um único loop de estado. Cada loop de estado executa todos os eventos necessários para visitar todos os estados e processar todas as transições e ações de transição. Então, um loop de estado começa e termina com o estado A sendo ativo. Isso significa que para cada caso de teste, 6 milhões em eventos e ações de transição e 1 milhão out eventos com suas ações de transição associadas são processados. Os testes foram executados como um aplicativo de linha de comando e registraram o tempo das iterações como um único lote. O consumo de tempo por evento pode então ser simplesmente determinado dividindo o tempo medido pela soma do número de em eventos e fora eventos. Os testes foram realizados várias vezes e foram escolhidos os resultados da medição com os valores mais baixos.

Os testes foram realizados usando código otimizado sem informações de depuração no meu antigo MacBook Pro (meados de 2014), com CPU Core i7 Quad Core 2.4GHz. Claro, os números concretos serão diferentes em diferentes máquinas e sistemas operacionais. No entanto, isso não é relevante, pois eu queria comparar as diferentes abordagens de implementação umas em relação às outras. Essas diferenças relativas serão comparáveis ​​em diferentes plataformas de hardware e sistema operacional.

Vamos dar uma olhada nos números de desempenho

Sim - acho que quase todos esperariam que uma implementação simples de C ++ fosse mais rápida do que as outras alternativas, mas a magnitude das diferenças é realmente impressionante.


Figura 3:Comparação do tempo de processamento de um único evento. (Fonte:Autor)

O processamento de eventos únicos usando C ++ simples levou em média 7 nanossegundos. Usar o SCXML exigiu 33.850 nanossegundos - isso é um fator de cerca de 4800 e uma enorme diferença! Para comparação, a luz viaja mais de 10 quilômetros, enquanto a máquina de estado SCXML processa apenas uma única transição, enquanto a mesma transição na máquina de estado C ++ simples deixa muito tempo para a luz viajar pouco mais de 2 metros. Isso implica ordens de magnitudes muito diferentes para os ciclos da CPU e o consumo de energia.

É claro que os números concretos dependem da máquina e do procedimento de teste usado. Discutirei esse tópico mais tarde. Mas vamos discutir os outros números primeiro. Todos os três primeiros cenários de teste incluem uma lógica de transição de estado idêntica, que foi gerada pelas YAKINDU Statechart Tools, mas cada uma envolvida de maneiras diferentes.

Usar sinais e slots para lidar com eventos levou 72 ns em média ao usar conexões diretas. Portanto, esse mecanismo impõe uma sobrecarga mínima de ~ 90%, em comparação com a lógica da máquina de estado real. Neste ponto, não quero argumentar que o uso de sinais e slots torna os aplicativos lentos. Em vez disso, prefiro afirmar que implementações de código simples de máquinas de estado são extremamente rápidas .

Comparar isso com o terceiro cenário dá uma boa impressão da sobrecarga de desempenho causada pelo uso da fila de eventos. Nesse cenário, todos os eventos de gráfico de estado são roteados pela fila de eventos. Com 731 ns por evento, é necessário um fator de ~ 10 em comparação com sinais e slots e ~ 100 em comparação com C ++ simples.

Podemos supor que uma sobrecarga comparável também se aplica aos outros dois cenários “simples QStateMachine ”E“ máquina de estado SCXML ”- ambos requerem uma fila de eventos ativa. Portanto, quando a sobrecarga da fila de eventos presumida é subtraída dos 5200 ns por evento, obtemos um consumo de tempo aproximado de QStateMachine quadro de 4500ns por evento. Em comparação com a abordagem de código simples, implementações de máquina de estado baseadas em QStateMachine são lentas. Este é um fator de cerca de 635, em comparação com a implementação de código C ++ simples.

Finalmente, vamos dar uma olhada no interpretador SCXML. Envolve a interpretação do código JavaScript e adiciona outro fator de ~ 7. Em comparação com a abordagem de código simples, implementações de máquina de estado baseadas em SCXML são muito lentas.

E quanto às máquinas de estado hierárquico e ortogonal?

Até agora, acabei de criar o perfil de uma máquina de estado plano simples. Mas os gráficos de estado fornecem muito mais recursos, e os dois recursos estruturais mais importantes são hierarquia e ortogonalidade. Então, qual é o impacto do uso desses recursos em relação ao tempo de execução da máquina de estado?

Primeiro, para medir o impacto das hierarquias, defini uma variante hierárquica da máquina de estado a ser perfilada, mostrada na fig. 4


Figura 4:Gráfico de estados de teste hierárquico. (Fonte:Autor)

Ele fornece exatamente o mesmo comportamento que a máquina de estado plano, mas adiciona alguns estados compostos. Manter a funcionalidade idêntica, mas apenas alterar a estrutura, torna possível descobrir quanta sobrecarga a variante estrutural implica, se houver.

Em segundo lugar, para medir o impacto da ortogonalidade, repliquei a máquina de estado plano na forma de quatro regiões ortogonais. Todos eles têm exatamente a mesma funcionalidade. Portanto, a máquina de estado resultante (veja a fig. 5) fará quatro vezes o trabalho que a máquina de estado simples faz.


Figura 5:Gráfico de estados do teste ortogonal. (Fonte:Autor)

Para a criação de perfil, escolhi as implementações C ++ simples e SCXML, porque essas eram as variantes mais rápidas e lentas. O diagrama da fig. 6 mostra os resultados. É muito encorajador que o uso de hierarquias em gráficos de estados não tenha nenhum impacto mensurável no desempenho em ambas as variantes de implementação.


Figura 6:Impacto de desempenho de hierarquias e ortogonalidade. (Fonte:Autor)

Outro resultado positivo é que o uso da ortogonalidade também não tem impacto negativo. Ao contrário, embora se pudesse esperar pelo menos quatro vezes o tempo de processamento para realizar quatro vezes o trabalho, os aumentos efetivos no tempo de execução com fatores ~ 2,4 e ~ 3,1 são significativamente menores do que 4.

Por que isso acontece? A razão para isso é que há uma parte geral do processamento da máquina de estado que é independente do processamento de estados e eventos individuais. Essa parte leva 52% (ou 3,5 ns por evento) para a máquina de estado C ++ simples, em comparação com 28% (ou 9,3 mil ns por evento) para SCXML. Finalmente, os estados ortogonais têm menos impacto ao usar o código C ++ gerado em comparação com o SCXML.

Conclusão

O C ++ simples é de longe mais eficiente do que todas as alternativas. O uso de sinais e slots ou a fila de eventos Qt são mecanismos de estrutura que facilitam a implementação e manutenção de aplicativos complexos de máquina de estado. A estrutura da máquina de estado do Qt requer ambos os mecanismos. Usando o código C ++ gerado, você tem a escolha.

Em muitos cenários, especialmente os interativos, até mesmo as máquinas de estado SCXML são rápidas o suficiente e podem fornecer mais flexibilidade, tornando o comportamento configurável ao alternar as definições de gráfico de estado em tempo de execução.

Integrado

  1. Como escolher o melhor software CAD de design de joias
  2. As melhores marcas CNC
  3. Como escolher a máquina CNC certa
  4. Como Garantir Preparação para Emergências no Armazém
  5. Como monitorar o desempenho da equipe técnica?
  6. Como escolher o melhor freio de turbina eólica
  7. Como escolher a máquina de cartonagem certa
  8. Como escolher a máquina de corte a jato de água certa
  9. Como escolher a melhor máquina de dobrar chapas de metal
  10. Como escolher a melhor bomba submersível?