Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial Internet of Things >> Embedded

Maximizing Performance of Qt State Machines

If you develop applications with Qt and employ state machines, you’re likely using Qt’s state‑machine framework. You can define the machine in plain C++ or SCXML, or generate C++ code from state‑chart diagrams. This article evaluates these options in terms of functionality, applicability, and performance.

As a software developer, you’ve probably written countless switch‑case blocks. For many, this is the simplest way to implement state machines when no higher‑level tool is available. However, as complexity grows, maintenance becomes a challenge, and hand‑crafted switch‑case logic is no longer sustainable.

Implementing state machines

When working with an object‑oriented language like C++, the state pattern is a proven strategy. It models each state as a class, and transitions as optional separate classes. A state machine is constructed by creating instances of these classes and wiring them together. A framework can significantly reduce boilerplate.

Qt’s state‑machine API lets you configure a machine with concise code, leaving the execution semantics to the framework. While this simplifies implementation, the source code can still grow large when a machine contains dozens or hundreds of states, making the overall design hard to grasp.

Qt also supports State Chart XML (SCXML), the W3C standard for state‑chart descriptions. Writing XML by hand is tedious, so Qt Creator offers a simple graphical editor.

Irrespective of the implementation technique, a graphical model is the most effective way to edit and understand a state machine. Graphical models can be expressed in text via SCXML, or used to generate source code in any language, including switch‑case C++ or QStateMachine construction. By delegating the transformation to a tool, you avoid the pain of manual code and bring all approaches to the same usability level. The implementations, however, remain fundamentally distinct. This article focuses on runtime behaviour, especially performance.

Maximizing Performance of Qt State Machines
UnsplashPhoto by Austris Augusts on Unsplash

The competitors

How do the approaches differ in CPU usage? To answer this, I created a benchmark suite. The first part compares the different implementation strategies. These are the competitors:

  1. SCXML interpreter – the test machine is defined in SCXML and executed by Qt’s QSCXMLStateMachine class.
  2. State pattern – the test machine is implemented using QStateMachine classes.
  3. Plain C++ code – the test machine is implemented by a C++ class that uses a basic switch‑case approach.

Note: Code for these examples can be found here.

The first two variants imply the use of Qt concepts like signals and slots as well as the use of a Qt event queue, while a plain C++ implementation does not require this infrastructure. To make the approaches more comparable, the test suite includes two additional scenarios:

This allows us to isolate the impact of signals/slots and the event queue on execution time while keeping the core state‑transition logic identical.

The test state machine

For all five variants I used the state machine illustrated in Figure 1 for the basic test scenario.

Maximizing Performance of Qt State Machines
Figure 1: The test state machine, as created with YAKINDU Statechart Tools. (Source: Author)

The machine has six flat states A–F, cycles through them, and reacts to two input events e1 and e2 that alternately trigger transitions. Each transition action adds 10 to a variable x; the transition from F to A also emits the output event o.

Maximizing Performance of Qt State Machines
Figure 2: The test state machine as an SCXML model in Qt Creator. (Source: Author)

I defined the machine with YAKINDU Statechart Tools, which can generate both SCXML and plain switch‑case C++ code. The generated code also supports Qt signals and slots. I implemented the QStateMachine variant manually, but all other implementations stem from the same state‑chart definition.

Each test ran one million iterations of a single state loop. A loop starts and ends with state A active, and processes the 6 million input events, 1 million output events, and their associated transition actions. The tests were executed as a command‑line application, and the time for the entire batch was recorded. The per‑event time was derived by dividing the total time by the number of events processed. The lowest values from repeated runs were used.

Benchmarks were performed on a 2014 MacBook Pro with a 2.4 GHz quad‑core i7 in an optimized release build. Exact numbers will vary on other hardware, but relative differences remain consistent.

Performance figures

Processing a single event with plain C++ took an average of 7 ns, whereas SCXML required 33 850 ns – a factor of about 4 800. Using signals and slots added ~72 ns per event (~90 % overhead). Routing through the Qt event queue added ~731 ns per event (~10× signals, ~100× plain C++). After subtracting queue overhead, the QStateMachine framework costs ~4 500 ns per event – roughly 635× slower than plain C++. The SCXML interpreter, which interprets JavaScript, adds another ~7× factor, making it the slowest variant.

Maximizing Performance of Qt State Machines
Figure 3: Single event processing time compared. (Source: Author)

Impact of hierarchy and orthogonality

I also profiled hierarchical and orthogonal variants of the same machine. The hierarchical machine (Figure 4) and the orthogonal machine (Figure 5) have identical behavior but different structure.

Maximizing Performance of Qt State Machines
Figure 4: Hierarchical test statechart. (Source: Author)

Maximizing Performance of Qt State Machines
Figure 5: Orthogonal test statechart. (Source: Author)

Results, shown in Figure 6, indicate that adding hierarchy does not introduce measurable overhead in either implementation. Orthogonality also does not double the runtime as one might expect; the increase is about 2.4× for plain C++ and 3.1× for SCXML, far below the theoretical four‑fold cost.

Maximizing Performance of Qt State Machines
Figure 6: Performance impact of hierarchies and orthogonality. (Source: Author)

Conclusion

Plain C++ delivers the best performance. Signals, slots, and the Qt event queue trade speed for convenience and maintainability, while the QStateMachine framework is the slowest of the three core variants. SCXML is often fast enough for interactive applications and offers the advantage of runtime reconfiguration. When maximum speed is critical, hand‑crafted switch‑case code is the recommended approach.

Embedded

  1. Enhancing Tungsten‑Copper Alloy Performance: Proven Strategies and Processing Techniques
  2. Designing a Finite‑State Machine in VHDL: A Practical Traffic Light Example
  3. Choosing the Ideal CNC Router: A Comprehensive Guide
  4. Top CNC Machine Brands for Precision and Reliability
  5. Choosing the Ideal CNC Machine: A Practical Guide
  6. Choosing the Ideal CNC Machine for Rapid Prototyping
  7. Choosing the Right Sheet Metal Folding Machine: A Comprehensive Guide
  8. Choosing the Right CNC Machine Shop: A Professional Guide
  9. Maximizing Precision and Efficiency in Low-Speed EDM Machining
  10. Choosing the Right Submersible Pump: Expert Tips & Key Features