当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > 如何确保最佳的Qt状态机性能

如何确保最佳的Qt状态机性能 时间:2020-05-11      来源:原创

如果使用Qt进行应用程序开发,并且使用状态机,则可能是在使用Qt状态机框架。因此,您将使用普通的C ++或SCXML定义状态机。一种替代方法是从状态机图生成C ++代码。本文比较了这些方法,并考虑了功能,适用性和性能。

我敢打赌,作为软件开发人员,您已经实现了许多或多或少复杂的开关案例语句。至少对我而言,这是正确的,而且大多数切换情况编码基本上只不过是实现各种状态机而已。如果您除了自己选择的编程语言之外别无其他东西,这是启动对状态机进行编程的最简单方法。尽管开始很容易,但是随着状态机复杂性的增加,此类代码变得越来越难维护。最后,您将确信您不想继续以这种方式手动实现状态机。(顺便说一句,我假设您知道什么是状态机。)

实现状态机

实现状态机有多种选择。更好的方法之一(尤其是当您使用诸如C ++的面向对象的编程语言时)是应用状态模式。这种方法使用状态类,通常还使用过渡类。然后,通过创建状态类的实例并使用过渡类的实例进行连接来定义状态机。在这种情况下,框架有助于减少代码大小和实施工作。

在Qt的状态机框架就是一个很好的例子。该API允许您使用紧凑代码“配置”状态机。您不必在乎状态机执行语义的细节,因为框架已经实现了这些细节。您仍然必须编写代码,并且随着您的状态机变得越来越复杂并且包含数十个甚至数百个状态,将很难获得概述。一幅图片价值一千个单词,而众所周知的状态图概念有助于克服这一限制。Qt本身提供对状态图XML(SCXML)的支持,这是W3C标准。由于手工编写XML并不有趣,因此Qt Creator还包含一个简单的图形状态图编辑器。

与具体的实现方法无关,使用图形语法是编辑和理解状态机的最佳选择。这样的图形化模型不仅可以用SCXML之类的语言来表示,而且还可以用于生成任何种类的编程语言源代码,例如纯C ++中基于开关案例的状态机或设置QStateMachine实例的C ++代码。。使用为您进行这种转换的工具,您可以避免手写状态机代码的痛苦。它将所有三种实现方法提升到相同的可用性级别。尽管如此,实现方式还是根本不同的。本文是关于比较它们的运行时行为,尤其是它们的性能。

竞争对手

那么性能呢?对于所需的CPU周期,可用的方法有何不同?为了获得一些具体数字,我设置了一个性能测试套件。第一部分比较了不同的实施策略。这些是竞争对手:

SCXML解释器–测试状态机使用SCXML定义,并由Qt的QSCXMLStateMachine类执行。

状态模式–测试状态机是使用QStateMachine类实现的。

普通的C ++代码–测试状态机由C ++类实现,该类采用基于开关案例的基本方法。

注意:这些示例的代码可以在此处找到。

前两个变体意味着使用Qt概念(例如信号和时隙)以及Qt事件队列,而普通的C ++实现不需要此基础结构。为了使这些方法更具可比性,该测试套件包括两个以上的测试方案:

带有信号和插槽的普通C ++代码–测试状态机具有与上述相同的实现,但是使用信号和插槽将其集成到应用程序中。

带有QEvent的纯C ++代码–使用纯C ++代码方法,但利用Qt事件队列来处理输入和输出事件。

与普通的C ++实现相比,这使得一方面可以比较信号和时隙的使用影响,另一方面可以比较QEvents的使用,因为状态机执行代码在所有情况下都是相同的,只是包装在一起不一样。

测试状态机

为了测试所有五个竞争对手,我定义了图2所示的状态机。基本测试方案为1。

图1:使用YAKINDU Statechart Tools创建的测试状态机。

测试状态机是一个简单的平面状态机。它定义了六个状态A到F,并在这些状态之间循环。定义了两个输入事件e1和e2,它们交替触发状态转换。当发生状态转换时,还将执行一个简单的动作。每个过渡动作仅将10添加到名为x的状态图变量中。从状态F到A的转换还会引发(或发出)出事件o。

图2:测试状态机作为Qt Creator中的SCXML模型。

该状态机是使用YAKINDU Statechart Tools定义的,该工具支持SCXML的生成。该SCXML可以添加到Qt项目中,并且可以在Qt Creator中进行编辑。如您在图中所见。如图2所示,状态机具有与图1相同的结构。1,但某些细节(例如过渡动作)在Qt Creator中不可见。YAKINDU Statechart Tools提供了更多优势,但是我在这里不再讨论。

这里更重要的是YAKINDU Statechart Tools还可以生成基于普通的基于切换案例的C ++状态机类。它还提供了生成带有信号和插槽的启用Qt的类的选项,因此非常方便。使用该工具,我只需要手工使用QStateMachine实现基于状态模式的状态机。没有适用于该变体的代码生成器。但是,我能够节省大量实现工作,而仅通过使用单个状态图定义就可以获得用于性能测试的语义等效状态机。

所有测试用例都遵循相同的方案。当我想测量处理单个事件的平均时间时,每个测试捕获了一个状态循环的一百万次迭代。每个状态循环执行访问所有状态并处理所有转换和转换动作所需的所有事件。因此,状态循环以状态A处于活动状态开始和结束。这意味着,对于每个测试用例6000000 中的事件和过渡动作和百万出与它们相关联的过渡动作事件被处理。测试是作为命令行应用程序执行的,并以单批记录了迭代时间。然后,可以通过将测得的时间除以in的数量之和来简单地确定每个事件的时间消耗。事件和出去事件。测试进行了几次,并选择了最低值的测量结果。

测试是在我的旧版(2014年中)使用MacBook Pro(配备Core i7四核CPU 2.4GHz)的情况下使用优化代码执行的,没有调试信息。当然,具体数字在不同的机器和操作系统上会有所不同。但是,这无关紧要,因为我想相互比较不同的实现方法。这些相对差异将在不同的硬件和OS平台上具有可比性。

让我们看一下性能指标

是的-我想几乎每个人都希望纯C ++实现比其他替代方案更快,但是差异的幅度确实令人震惊。

图3:比较单个事件的处理时间。

使用纯C ++处理单个事件平均花费7纳秒。使用SCXML需要33,850纳秒-这是大约4800的倍数,并且差异巨大!为了进行比较,光行进超过10公里,而SCXML状态机仅处理一次转换,而普通C ++状态机中的同一转换只为光行进超过2米留了很多时间。这意味着CPU周期和能耗的数量级差异很大。

当然,具体数字取决于机器和所使用的测试程序。稍后我将讨论这个主题。但是,让我们先讨论其他数字。前三个测试方案都包含一个相同的状态转换逻辑,该逻辑由YAKINDU Statechart Tools生成,但是每种包装方式都不同。

使用直接连接时,使用信号和插槽处理事件平均需要72ns。因此,与实际的状态机逻辑相比,此机制的开销至少为〜90%。在这一点上,我不想争辩说使用信号和时隙会使应用程序变慢。相反,我宁愿声称状态机的纯代码实现非常快。

将此与第三种情况进行比较,可以很好地了解使用事件队列导致的性能开销。在这种情况下,所有状态图事件都通过事件队列进行路由。每个事件731ns,与信号和时隙相比,花费约10倍,与普通C ++相比,花费约100倍。

我们可以假设其他两个场景“普通QStateMachine ”和“ SCXML状态机” 也具有可比的开销–它们都需要活动的事件队列。因此,如果从每个事件的5200ns中减去假定的事件队列开销,那么每个事件4500ns的QStateMachine框架的时间消耗就很大。与普通代码方法相比,基于QStateMachine的状态机实现速度较慢。与纯C ++代码实现相比,这大约是635的倍数。

最后,让我们看一下SCXML解释器。它涉及解释JavaScript代码,并增加了〜7的另一个因数。与普通代码方法相比,基于SCXML的状态机实现非常慢。

分层和正交状态机呢?

到目前为止,我仅介绍了一个简单的平面状态机。但是状态图提供了更多功能,而两个最重要的结构特征是层次结构和正交性。那么,这些功能的使用对状态机运行时间有何影响?

首先,为了测量层次结构的影响,我定义了要配置的状态机的层次结构变体,如图2所示。4。

图4:分层测试状态图。

它提供与平面状态机完全相同的行为,但增加了一些复合状态。保持功能相同,而只是更改结构,就可以找出结构变体所暗示的开销(如果有)。

其次,为了测量正交性的影响,我以四个正交区域的形式复制了平面状态机。它们都具有完全相同的功能。因此,最终的状态机(见图5)将完成简单状态机所做工作的四倍。

图5:正交测试状态图。

对于概要分析,我选择了普通的C ++和SCXML实现,因为它们是最快和最慢的变体。图中的图。结果示于图6。令人鼓舞的是,在两种状态变体中,在状态图中使用层次结构都不会对性能产生任何可衡量的影响。

图6:层次结构和正交性对性能的影响。

另一个积极的结果是,使用正交性也没有任何负面影响。相反,尽管人们可能期望完成至少四倍的处理时间才能完成四倍的工作,但是运行时的有效增加(〜2.4和〜3.1倍)明显小于4。

为什么会这样呢?这样做的原因是,状态机处理的大部分内容独立于单个状态和事件的处理。对于普通的C ++状态机,此部分花费52%(或每个事件3.5ns),而对于SCXML,此部分花费28%(或每个事件9300ns)。最后,与使用SCXML相比,使用生成的C ++代码时正交状态的影响较小。

结论

到目前为止,Plain C ++比所有替代方法都高效。使用信号和插槽或Qt事件队列是框架机制,可简化实现和维护复杂状态机应用程序的过程。Qt状态机框架需要这两种机制。使用生成的C ++代码,您可以选择。

在许多情况下,尤其是交互式情况,甚至SCXML状态机也足够快,并且它们可以通过在运行时切换状态图定义使行为可配置,从而提供更大的灵活性。

上一篇:如何为带有小型PCB的移动设备获得更好的无线性能

下一篇:开发套件支持Azure RTOS

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部