SlideShare a Scribd company logo
emBO++ 2017
'EMBEDDING' A META
STATE MACHINE
Kris Jusiak, Quantlab
| |kris@jusiak.net @krisjusiak linkedin.com/in/kris-jusiak
1
2
AGENDA
Connection example
Implementation
Naive
Enum/Switch
Variant (C++17)
State Machine Language (SML)
[Boost].SML
Overview
SML vs Boost.MSM vs Boost.Statechart
Design in a nutshell
Summary
3 . 1
STORY: CONNECTION (BDD STYLE)
enario 1: Establishing connection 
Given the connection is disconnected 
When the user requests to connect 
Then the establish request should be sent 
And the system should wait for estaliblished event 
Scenario 2: Keeping connection 
  Given the connection is connected 
  When the valid ping is recieved 
  Then the timeout should be reset 
enario 3: Connection timeout 
Given the connection is connected 
When the timeout is recieved 
Then the establish should be called 
And connecting process start again 
Scenario 4: Disconnecting 
  Given the connection is connected 
  When the disconnect event is recieve
  Then the close should be called 
  And user should get disconnected 
3 . 2
CONNECTION: STATE DIAGRAM (UML 2.5)
Transition - Uni ed Modeling Language (UML)
3 . 3
CONNECTION - HELPERS/DETAILS
void resetTimeout() { std::puts("resetTimeout"); } 
void establish() { std::puts("establish"); } 
void close() { std::puts("close"); } 
bool is_valid(const Ping&) { return true; } 
3 . 4
CONNECTION (V1) - NAIVE IMPLEMENTATION
class ConnectionV1 { 
    bool disconnected = true, connected = false, connecting = false; 
public: 
    void connect() { 
        if (disconnected || connected) { 
            establish(); 
            disconnected = false; 
            connecting = true; 
        } 
    } 
    void disconnect() { 
        if (connecting || connected) { 
            close(); 
            connected = false; 
            disconnected = true; 
        } 
    } 
3 . 5
CONNECTION (V1) - NAIVE IMPLEMENTATION
    void established() {
        connecting = false; 
        connected = true; 
    } 
    void ping(const Ping& event) { 
        if (connected && is_valid(event)) { 
            resetTimeout(); 
        } 
    } 
    void timeout() { connect(); } 
}; 
3 . 6
CONNECTION (V1) - BENCHMARK
GCC-7 Clang-3.9
Compilation time 0.101s 0.122s
sizeof(ConnectionV1) 3b 3b
Executable size 6.2K 6.2K
Connect:
ASM x86-64
main: 
  sub     rsp, 8 
  mov     edi, OFFSET FLAT:.LC1 
  call    puts 
  xor     eax, eax 
  add     rsp, 8 
  ret 
https://godbolt.org/g/0qpgvv
3 . 7
CONNECTION (V1) - SUMMARY
(+) Quick compilation times
(+) Good performance
(-) Uses more size than required
(-) Hard to follow
(-) Hard to extend and maintain
(-) Hard to test
3 . 8
CONNECTION (V2) - ENUM/SWITCH
IMPLEMENTATION
class ConnectionV2 { 
    enum class State : unsigned char { DISCONNECTED, CONNECTING, CONNECTED } state; 
public: 
    void connect() { 
        switch(state) { 
            default: break; 
            case State::DISCONNECTED: 
            case State::CONNECTED: establish(); state = State::CONNECTING; break; 
        } 
    } 
    void disconnect() { 
        switch(state) { 
            default: break; 
            case State::CONNECTING: 
            case State::CONNECTED: close(); state = State::DISCONNECTED; break; 
        } 
    } 
3 . 9
CONNECTION (V2) - ENUM/SWITCH
IMPLEMENTATION
    void established() {
        state = State::CONNECTED; 
    } 
    void ping(const Ping& event) { 
        if (state == State::CONNECTED && is_valid(event)) { 
            resetTimeout(); 
        } 
    } 
    void timeout() { connect(); } 
}; 
3 . 10
CONNECTION (V2) - BENCHMARK
GCC-7 Clang-3.9
Compilation time 0.112s 0.118s
sizeof(ConnectionV2) 1b 1b
Executable size 6.2K 6.2K
Connect:
ASM x86-64
main: 
  sub     rsp, 8 
  mov     edi, OFFSET FLAT:.LC1 
  call    puts 
  xor     eax, eax 
  add     rsp, 8 
  ret 
https://godbolt.org/g/3Qphjb
3 . 11
CONNECTION (V2) - SUMMARY
(+) Quick compilation times
(+) Good performance
(+) Minimal size used
(-) Hard to follow
(-) Hard to extend and maintain
(-) Hard to test
3 . 12
CONNECTION (V3) - C++17 VARIANT
IMPLEMENTATION
class ConnectionV3 { 
    struct Disconnected { }; 
    struct Connecting { }; 
    struct Connected { }; 
    std::variant<Disconnected, Connecting, Connected> state; 
public: 
    void connect() { 
        std::visit(overload{ 
            [&](Disconnected) { establish(); state = Connecting{}; }, 
            [&](Connected) { establish(); state = Connecting{}; }, 
            [](auto) { }
        }, state); 
    } 
3 . 13
CONNECTION (V3) - C++17 VARIANT
IMPLEMENTATION
    void disconnect() { 
        std::visit(overload{ 
            [&](Connecting) { close(); state = Disconnected{}; }, 
            [&](Connected) { close(); state = Disconnected{}; }, 
            [](auto) { }
        }, state); 
    } 
    void established() {
        state = Connected{}; 
    } 
    void ping(const Ping& event) { 
        if (std::get_if<Connected>(&state) && is_valid(event)) { 
            resetTimeout(); 
        } 
    } 
    void timeout() { connect(); } 
}; 
3 . 14
CONNECTION (V3) - BENCHMARK
GCC-7 Clang-3.9
Compilation time 0.272s 0.269s
sizeof(ConnectionV3) 2b 8b
Executable size 6.2K 6.2K
Connect:
ASM x86-64
main: 
        sub     rsp, 56
        xor     eax, eax 
        lea     rsi, [rsp+16] 
        lea     rdi, [rsp+32] 
        mov     WORD PTR [rsp+16], ax 
        mov     QWORD PTR [rsp+8], rsi 
        movq    xmm0, QWORD PTR [rsp+8] 
        ... 
https://godbolt.org/g/yf1BjN
3 . 15
CONNECTION (V3) - SUMMARY
(+) Data connected with the state naturally
(+) Quick compilation times
(-) Poor performance
(-) Uses more size than required (different on GCC and
Clang)
(-) Hard to follow
(-) Hard to extend and maintain
(-) Hard to test
3 . 16
LET'S GO BACK TO THE CONNECTION STATE
DIAGRAM (UML 2.5)
3 . 17
CONNECTION: TRANSITION TABLE
REPRESENTATION (UML 2.5)
3 . 18
CONNECTION: TRANSITION TABLE TEXT
REPRESENTATION (UML 2.5)
* ­> Disconnected : connect / establish              ­> Connecting 
     Connecting   : established                      ­> Connected 
     Connected    : ping [ is_valid ] / resetTimeout 
     Connected    : timeout                          ­> Connecting 
     Connected    : disconnect                       ­> Disconnected 
3 . 19
LET'S INTRODUCE [BOOST].SML
CONNECTION (V4)
sml::sm connectionV4 = [] { // C++17 template arg. deduction for class templates 
  return transition_table{ 
    * "Disconnected"_s + connect / establish                = "Connecting"_s, 
      "Connecting"_s   + established                        = "Connected"_s, 
      "Connected"_s    + ping [ is_valid ] / resetTimeout, 
      "Connected"_s    + timeout / establish                = "Connecting"_s, 
      "Connected"_s    + disconnect / close                 = "Disconnected"_s 
  }; 
}; 
3 . 20
CONNECTION (V4) - [BOOST].SML
ACTIONS
const auto establish = []{ std::puts("establish!"); }; 
const auto disconnect = []{ std::puts("disconnect!"); }; 
GUARDS
const auto is_valid = [](auto event){ return true; }; 
3 . 21
CONNECTION (V4) - BENCHMARK
GCC-7 Clang-3.9
Compilation time 0.151s 0.169s
sizeof(ConnectionV4) 1b 1b
Executable size 6.2K 6.2K
Connect:
ASM x86-64
main: 
        subq    $8, %rsp 
        movl    $.LC0, %edi 
        call    puts 
        xorl    %eax, %eax 
        addq    $8, %rsp 
        ret 
https://godbolt.org/g/6z6UF4
3 . 22
CONNECTION (V4) - SUMMARY
(+) Quick compilation times
(+) Good performance
(+) Minimal size used
(+) Easy to follow
(+) Easty to extend and maintain
(+) Easy to test
(-) Library has to be used (C++14)
3 . 23
CONNECTION - BENCHMARK
Naive Enum/Switch Variant [Boost].SML
Compilation
time
0.101s 0.112s 0.269s 0.151s
sizeof(sm) 3b 1b 2b/8b 1b
Executable
size
6.2K 6.2K 6.2K 6.2K
Performance
(connect)
inlined inlined not-
inlined
inlined
3 . 24
MORE REALIST BENCHMARK
Events States Transitions Process Events
50 50 50 1'000'000
3 . 25
MORE REALIST BENCHMARK
MAIN
int main() { 
  for (auto i = 0; i < 1'000'000; ++i) {
    if (rand() % 2) sm.process_event(e1()); 
    if (rand() % 2) sm.process_event(e2()); 
    if (rand() % 2) sm.process_event(e3()); 
    ... 
    if (rand() % 2) sm.process_event(e100()); 
  } 
} 
CXXFLAGS
$CXX ­std=c++1z ­O3 ­flto ­fno­exceptions ­DNDEBUG benchmark.cpp 
3 . 26
MORE REALIST - RESULTSBENCHMARK
Enum/Switch Variant [Boost].SML
Compilation
time
0.132s 15.321s 0.582s
Execution time 679ms 827ms 622ms
Memory usage 1b 2b/8b 1b
Executable size 15K 187K 34K
Line of Code
(LOC)
~300 (no
macros)
~300 ~50
Median / 100 runs
4 . 1
[BOOST].SML
UML-2.5 State Machine Language
https://github.com/boost-experimental/sml
4 . 2
[BOOST].SML
One header - 2k LOC - (boost/sml.hpp) / generated
Neither Boost nor STL is required
Quick compilation-times (-Wall -Wextra -Werror -pedantic
-pedantic-errors)
Blazing fast run-time (Generated at compile-time)
No 'virtual's (-fno-rtti)
Optional support for 'exception's (-fno-exceptions)
Supported compilers (C++14)
, , ,Clang-3.4+ XCode-6.1+ GCC-5.2+ MSVC-2015+
4 . 3
- API (SIMPLIFIED)[BOOST].SML
/** 
 * Makes transition table from DSL 
 * @tparam Ts... transitions (transitional) 
 */ 
template <class... Ts> requires transitional<Ts>()... 
struct transition_table; 
/** 
 * Helper function to make transition_table (C++14) 
 * @tparam Ts... transitions (transitional) 
 * @return transition_table 
 */ 
template <class... Ts> requires transitional<Ts>()... 
constexpr auto make_transition_table(Ts&&...) noexcept; 
4 . 4
- API (SIMPLIFIED)[BOOST].SML
/** 
 * State Machine
 * 
 * @tparam T Callable object returning transition_table 
 * @tparam TPolicies policies to be applied such as 
 *                   thread safe, exception safe, etc. 
 */ 
template<class T, 
         class... TPolicies> requires callable<transition_table, T>() 
class sm; 
/** 
 * Process event
 * Complexity ­ O(1) 
 * @param TEvent event to be processed 
 */ 
template<class TEvent> 
constexpr void process_event(const TEvent&); 
4 . 5
- FEATURES[BOOST].SML
UML (2.5)
Transition
Anonymous, Internal, Self, Local transition
Guard, Action
Unexpected, Deffered, Any event
State
Entry/Exit Actions, Initial, Terminate state
Composite/Sub state
Explicit entry/exit, Fork
Shallow History, Deep History
Orthogonal regions
Non-UML
Logging, State visitor, Diagram gen., Run-time dispatch
4 . 6
- FEATURES[BOOST].SML
We DON'T pay for features we are NOT using!
For example, if the state machine doesn't use
orthogonal regions, the code responsible for
handling them won't be even generated
- MORE REALISTIC EXAMPLE (SYSTEM)[BOOST].SML
4 . 7
Enum/Switch? No, thank you!
4 . 8
- MORE REALISTIC EXAMPLE (SYSTEM)[BOOST].SML
uct Connection { 
uto operator()() const { 
 return transition_table{ 
   "Disconnected"_s(H) + connect / []{establish();}               = "Connecting"_s, 
   "Connecting"_s      + established                              = "Connected"_s, 
   "Connected"_s       + ping [ is_valid ] / []{resetTimeout();} 
   "Connected"_s       + timeout / []{establish();}               = "Connecting"_s, 
   "Connected"_s       + disconnect / []{close();}                = "Disconnected"_s 
 }; 
; 
uct System { 
uto operator()() const { 
 return transition_table{ 
  * "Idle"_s          + power_up [ has_battery and is_healthy] / connect = state<Connectio
    state<Connection> + suspend                                          = "Suspended"_s, 
    "Suspended"_s     + resume                                           = state<Connectio
  // ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ 
  * "Watchdog"_s      + tick / resetTimeout 
    "Watchdog"_s      + timeout                                          = X 
 }; 
4 . 9
- MORE REALISTIC EXAMPLE (SYSTEM)[BOOST].SML
int main() { 
  using namespace sml; 
  sm<System> system; 
  system.process_event(power_up{}); 
  assert(system.is(state<Connection>, "Watchdog"_s)); 
  system.process_event(suspend{}); 
  assert(system.is("Suspended"_s, "Watchdog"_s)); 
  system.process_event(timeout{}); 
  assert(system.is(X)); // true if any state is in terminated state (X) 
} 
4 . 10
[BOOST].SML VS BOOST.MSM-EUML VS
BOOST.STATECHART
4 . 11
OVERVIEW
Library [Boost].SML Boost.MSM-
eUML
Boost.Statechart
Standard C++14 C++98/03 C++98/03
Version 1.0.1 1.63 1.63
License Boost 1.0 Boost 1.0 Boost 1.0
Linkage header only header only header only
4 . 12
(SAME AS BEFORE)BENCHMARK
Events States Transitions Process Events
50 50 50 1'000'000
4 . 13
- RESULTSBENCHMARK
[Boost].SML Boost.MSM-
eUML
Boost.Statechart
Compilation
time
0.582s 1m15.935s 5.671s
Execution
time
622ms 664ms 2282ms
Memory
usage
1b 120b 224b
Executable
size
34K 611K 211K
5 . 1
DESIGN IN A NUTSHELL[BOOST].SML
5 . 2
TRANSITIONAL CONCEPT
template <class T> 
concept bool transitional() { 
  return requires(T transition) { 
    typename T::src_state; 
    typename T::dst_state; 
    typename T::event; 
    T::property; // initial, history state, etc. 
    { transition.execute(const typename T::Event&) } ­> optional<state_t>; 
  } 
}; 
5 . 3
FRONT END
DOMAIN SPECIFIC LANGUAGE (DSL)
atic_assert(std::is_same< 
decltype( 
  transition_table{ 
    * "Disconnected"_s + connect / establish = "Connecting"_s, 
      "Connecting"_s   + established         = "Connected"_s 
  } 
), 
transition_table< 
  // ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ /
  //         src_state              dst_state            event        guard   action    /
  // ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ /
  transition<state<"Disconnected">, state<"Connecting">, connect,     always, establish>,
  transition<state<"Connecting">,   state<"Connected">,  established, always, none> 
> 
}); 
5 . 4
BACK-END
GENERATED AT COMPILE TIME MAPPING PER EVENT AND STATE
ing mappings_t = type_list< 
pair<connect, type_list< 
  transitions< 
    transition<state<"Disconnected">, state<"Connecting">, connect, always, establish> 
  >, 
  transitions<>, // Connecting (unexpected event) 
  transitions<>  // Connected  (unexpected event) 
>, 
pair<established, type_list< 
  transitions<>, // Disconnected (unexpected event) 
  transitions< 
    transition<state<"Connecting">, state<"Connected">,  established, always, none> 
  >, 
  transitions<>  // Connected (unexpected event) 
> 
5 . 5
BACK-END
PROCESS EVENT - JUMP TABLE - (SIMPLIFIED)
template<class TEvent> 
constexpr void process_event(const TEvent& event) { 
  process_event_impl(event, get_mappings_t<TEvent>{}); 
} 
template<class... Transitions, class TEvent> 
constexpr void process_event_impl(const TEvent& event, type_list<Transitions...>) { 
  const static (*dispatch_table[])(const TEvent&) = {  
    &Transitions::template execute<TEvent>... 
  }; 
  dispatch_table[current_state](event); // Complexity: O(1) ­ jump table 
} 
6 . 1
SUMMARY
6 . 2
IF YOU LIKE IT OR NOT, YOUR CODE WON'T BE
STATEFUL (MOST LIKELY)
6 . 3
IMPLICIT/HAND WRITTEN STATE MACHINES
ARE HARD TO
Reason about
Maintain / Extend
Test
6 . 4
STATE MACHINES ARE MORE THAN JUST SIMPLE
TRANSITIONS
UML-2.5
6 . 5
LEVERAGING ZERO-COST LIBRARIES WILL BOOST
YOUR DESIGN AND/OR PERFRORMANCE
/[Boost].SML Boost.MSM
7
QUESTIONS?
ost].SML
cumentation
urce Code
it online!
http://boost-experimental.github.io/sml
https://github.com/boost-experimental/sml
http://boost-experimental.github.io/sml/examples
https://godbolt.org/g/UX6eWt
-
| |kris@jusiak.net @krisjusiak linkedin.com/in/kris-jusiak

More Related Content

PDF
The future of RISC-V Supervisor Binary Interface(SBI)
PPTX
ARM Processor architecture
PPTX
Motherboards
PDF
HP versus Dell - A Server Comparison
PDF
motherboard
PDF
Microprocessor Introduction
PPT
Floating point units
PPT
7 motherboards
The future of RISC-V Supervisor Binary Interface(SBI)
ARM Processor architecture
Motherboards
HP versus Dell - A Server Comparison
motherboard
Microprocessor Introduction
Floating point units
7 motherboards

What's hot (20)

PPTX
RISC-V Introduction
PDF
Browsing Linux Kernel Source
PPTX
Gabinete at
PDF
Board Bringup
PPTX
Risc and cisc
PDF
Introduction to BeagleBone Black
ODP
How to Conserve IPv4 Addresses
PDF
How to install Kali Linux? | Edureka
PDF
Linux Porting
PPTX
Embedded system
PDF
Logging kernel oops and panic
PDF
Microcontroller pic 16 f877 registers memory ports
PDF
Testing real-time Linux. What to test and how
PDF
Intro to Embedded OS, RTOS and Communication Protocols
PPTX
Flash memory
PPTX
Computer Organisation & Architecture (chapter 1)
PPTX
Bagian –bagian motherboard dan fungsinya
PPTX
Printer sharing
PPTX
Introduction to armv8 aarch64
PPTX
Instruction Set Architecture: MIPS
RISC-V Introduction
Browsing Linux Kernel Source
Gabinete at
Board Bringup
Risc and cisc
Introduction to BeagleBone Black
How to Conserve IPv4 Addresses
How to install Kali Linux? | Edureka
Linux Porting
Embedded system
Logging kernel oops and panic
Microcontroller pic 16 f877 registers memory ports
Testing real-time Linux. What to test and how
Intro to Embedded OS, RTOS and Communication Protocols
Flash memory
Computer Organisation & Architecture (chapter 1)
Bagian –bagian motherboard dan fungsinya
Printer sharing
Introduction to armv8 aarch64
Instruction Set Architecture: MIPS
Ad

Viewers also liked (6)

PDF
Profiling your Applications using the Linux Perf Tools
PDF
A possible future of resource constrained software development
PDF
standardese - a WIP next-gen Doxygen
PDF
Programming at Compile Time
PDF
Data-driven HAL generation
PDF
Device-specific Clang Tooling for Embedded Systems
Profiling your Applications using the Linux Perf Tools
A possible future of resource constrained software development
standardese - a WIP next-gen Doxygen
Programming at Compile Time
Data-driven HAL generation
Device-specific Clang Tooling for Embedded Systems
Ad

Similar to 'Embedding' a meta state machine (20)

PPT
M03 2 Behavioral Diagrams
PDF
Proposed pricing model for cloud computing
PPT
Drupal CMS: generating reports with the Forena module.
PDF
Keep Them out of the Database
PDF
Trivadis TechEvent 2016 Oracle Client Failover - Under the Hood by Robert Bialek
PDF
Percona xtra db cluster(pxc) non blocking operations, what you need to know t...
ODP
Formal Verification of Web Service Interaction Contracts
PPT
IBM Informix dynamic server 11 10 Cheetah Sql Features
PPTX
OOPS USING C++(UNIT 2)
DOC
Dbmsmanual
DOCX
Azure Service Bus Performance Checklist
PDF
OOW19 - Killing database sessions
PPTX
Database Mirror for the exceptional DBA – David Izahk
PPT
Java Database Connectivity Java Database
PDF
ThruPut Manager AE+: Automation for Production Control and Capacity Management
DOCX
Oracle pl sql
DOCX
Part APurposeThis laboratory provides some experience work.docx
ODP
Architecture your android_application
PDF
ADVANCED WORKSHOP IN MATLAB
PPT
Less09 Data
M03 2 Behavioral Diagrams
Proposed pricing model for cloud computing
Drupal CMS: generating reports with the Forena module.
Keep Them out of the Database
Trivadis TechEvent 2016 Oracle Client Failover - Under the Hood by Robert Bialek
Percona xtra db cluster(pxc) non blocking operations, what you need to know t...
Formal Verification of Web Service Interaction Contracts
IBM Informix dynamic server 11 10 Cheetah Sql Features
OOPS USING C++(UNIT 2)
Dbmsmanual
Azure Service Bus Performance Checklist
OOW19 - Killing database sessions
Database Mirror for the exceptional DBA – David Izahk
Java Database Connectivity Java Database
ThruPut Manager AE+: Automation for Production Control and Capacity Management
Oracle pl sql
Part APurposeThis laboratory provides some experience work.docx
Architecture your android_application
ADVANCED WORKSHOP IN MATLAB
Less09 Data

Recently uploaded (20)

PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Empathic Computing: Creating Shared Understanding
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
Machine learning based COVID-19 study performance prediction
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PPTX
1. Introduction to Computer Programming.pptx
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Getting Started with Data Integration: FME Form 101
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
Tartificialntelligence_presentation.pptx
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Big Data Technologies - Introduction.pptx
PPTX
Spectroscopy.pptx food analysis technology
Programs and apps: productivity, graphics, security and other tools
Encapsulation_ Review paper, used for researhc scholars
Reach Out and Touch Someone: Haptics and Empathic Computing
Empathic Computing: Creating Shared Understanding
Dropbox Q2 2025 Financial Results & Investor Presentation
Network Security Unit 5.pdf for BCA BBA.
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
Diabetes mellitus diagnosis method based random forest with bat algorithm
Group 1 Presentation -Planning and Decision Making .pptx
Machine learning based COVID-19 study performance prediction
Assigned Numbers - 2025 - Bluetooth® Document
1. Introduction to Computer Programming.pptx
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Getting Started with Data Integration: FME Form 101
Digital-Transformation-Roadmap-for-Companies.pptx
Tartificialntelligence_presentation.pptx
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Big Data Technologies - Introduction.pptx
Spectroscopy.pptx food analysis technology

'Embedding' a meta state machine

  • 1. emBO++ 2017 'EMBEDDING' A META STATE MACHINE Kris Jusiak, Quantlab | |kris@jusiak.net @krisjusiak linkedin.com/in/kris-jusiak
  • 2. 1 2 AGENDA Connection example Implementation Naive Enum/Switch Variant (C++17) State Machine Language (SML) [Boost].SML Overview SML vs Boost.MSM vs Boost.Statechart Design in a nutshell Summary
  • 3. 3 . 1 STORY: CONNECTION (BDD STYLE) enario 1: Establishing connection  Given the connection is disconnected  When the user requests to connect  Then the establish request should be sent  And the system should wait for estaliblished event  Scenario 2: Keeping connection    Given the connection is connected    When the valid ping is recieved    Then the timeout should be reset  enario 3: Connection timeout  Given the connection is connected  When the timeout is recieved  Then the establish should be called  And connecting process start again  Scenario 4: Disconnecting    Given the connection is connected    When the disconnect event is recieve   Then the close should be called    And user should get disconnected 
  • 4. 3 . 2 CONNECTION: STATE DIAGRAM (UML 2.5) Transition - Uni ed Modeling Language (UML)
  • 5. 3 . 3 CONNECTION - HELPERS/DETAILS void resetTimeout() { std::puts("resetTimeout"); }  void establish() { std::puts("establish"); }  void close() { std::puts("close"); }  bool is_valid(const Ping&) { return true; } 
  • 6. 3 . 4 CONNECTION (V1) - NAIVE IMPLEMENTATION class ConnectionV1 {      bool disconnected = true, connected = false, connecting = false;  public:      void connect() {          if (disconnected || connected) {              establish();              disconnected = false;              connecting = true;          }      }      void disconnect() {          if (connecting || connected) {              close();              connected = false;              disconnected = true;          }      } 
  • 7. 3 . 5 CONNECTION (V1) - NAIVE IMPLEMENTATION     void established() {         connecting = false;          connected = true;      }      void ping(const Ping& event) {          if (connected && is_valid(event)) {              resetTimeout();          }      }      void timeout() { connect(); }  }; 
  • 8. 3 . 6 CONNECTION (V1) - BENCHMARK GCC-7 Clang-3.9 Compilation time 0.101s 0.122s sizeof(ConnectionV1) 3b 3b Executable size 6.2K 6.2K Connect: ASM x86-64 main:    sub     rsp, 8    mov     edi, OFFSET FLAT:.LC1    call    puts    xor     eax, eax    add     rsp, 8    ret  https://godbolt.org/g/0qpgvv
  • 9. 3 . 7 CONNECTION (V1) - SUMMARY (+) Quick compilation times (+) Good performance (-) Uses more size than required (-) Hard to follow (-) Hard to extend and maintain (-) Hard to test
  • 10. 3 . 8 CONNECTION (V2) - ENUM/SWITCH IMPLEMENTATION class ConnectionV2 {      enum class State : unsigned char { DISCONNECTED, CONNECTING, CONNECTED } state;  public:      void connect() {          switch(state) {              default: break;              case State::DISCONNECTED:              case State::CONNECTED: establish(); state = State::CONNECTING; break;          }      }      void disconnect() {          switch(state) {              default: break;              case State::CONNECTING:              case State::CONNECTED: close(); state = State::DISCONNECTED; break;          }      } 
  • 11. 3 . 9 CONNECTION (V2) - ENUM/SWITCH IMPLEMENTATION     void established() {         state = State::CONNECTED;      }      void ping(const Ping& event) {          if (state == State::CONNECTED && is_valid(event)) {              resetTimeout();          }      }      void timeout() { connect(); }  }; 
  • 12. 3 . 10 CONNECTION (V2) - BENCHMARK GCC-7 Clang-3.9 Compilation time 0.112s 0.118s sizeof(ConnectionV2) 1b 1b Executable size 6.2K 6.2K Connect: ASM x86-64 main:    sub     rsp, 8    mov     edi, OFFSET FLAT:.LC1    call    puts    xor     eax, eax    add     rsp, 8    ret  https://godbolt.org/g/3Qphjb
  • 13. 3 . 11 CONNECTION (V2) - SUMMARY (+) Quick compilation times (+) Good performance (+) Minimal size used (-) Hard to follow (-) Hard to extend and maintain (-) Hard to test
  • 14. 3 . 12 CONNECTION (V3) - C++17 VARIANT IMPLEMENTATION class ConnectionV3 {      struct Disconnected { };      struct Connecting { };      struct Connected { };      std::variant<Disconnected, Connecting, Connected> state;  public:      void connect() {          std::visit(overload{              [&](Disconnected) { establish(); state = Connecting{}; },              [&](Connected) { establish(); state = Connecting{}; },              [](auto) { }         }, state);      } 
  • 15. 3 . 13 CONNECTION (V3) - C++17 VARIANT IMPLEMENTATION     void disconnect() {          std::visit(overload{              [&](Connecting) { close(); state = Disconnected{}; },              [&](Connected) { close(); state = Disconnected{}; },              [](auto) { }         }, state);      }      void established() {         state = Connected{};      }      void ping(const Ping& event) {          if (std::get_if<Connected>(&state) && is_valid(event)) {              resetTimeout();          }      }      void timeout() { connect(); }  }; 
  • 16. 3 . 14 CONNECTION (V3) - BENCHMARK GCC-7 Clang-3.9 Compilation time 0.272s 0.269s sizeof(ConnectionV3) 2b 8b Executable size 6.2K 6.2K Connect: ASM x86-64 main:          sub     rsp, 56         xor     eax, eax          lea     rsi, [rsp+16]          lea     rdi, [rsp+32]          mov     WORD PTR [rsp+16], ax          mov     QWORD PTR [rsp+8], rsi          movq    xmm0, QWORD PTR [rsp+8]          ...  https://godbolt.org/g/yf1BjN
  • 17. 3 . 15 CONNECTION (V3) - SUMMARY (+) Data connected with the state naturally (+) Quick compilation times (-) Poor performance (-) Uses more size than required (different on GCC and Clang) (-) Hard to follow (-) Hard to extend and maintain (-) Hard to test
  • 18. 3 . 16 LET'S GO BACK TO THE CONNECTION STATE DIAGRAM (UML 2.5)
  • 19. 3 . 17 CONNECTION: TRANSITION TABLE REPRESENTATION (UML 2.5)
  • 20. 3 . 18 CONNECTION: TRANSITION TABLE TEXT REPRESENTATION (UML 2.5) * ­> Disconnected : connect / establish              ­> Connecting       Connecting   : established                      ­> Connected       Connected    : ping [ is_valid ] / resetTimeout       Connected    : timeout                          ­> Connecting       Connected    : disconnect                       ­> Disconnected 
  • 21. 3 . 19 LET'S INTRODUCE [BOOST].SML CONNECTION (V4) sml::sm connectionV4 = [] { // C++17 template arg. deduction for class templates    return transition_table{      * "Disconnected"_s + connect / establish                = "Connecting"_s,        "Connecting"_s   + established                        = "Connected"_s,        "Connected"_s    + ping [ is_valid ] / resetTimeout,        "Connected"_s    + timeout / establish                = "Connecting"_s,        "Connected"_s    + disconnect / close                 = "Disconnected"_s    };  }; 
  • 22. 3 . 20 CONNECTION (V4) - [BOOST].SML ACTIONS const auto establish = []{ std::puts("establish!"); };  const auto disconnect = []{ std::puts("disconnect!"); };  GUARDS const auto is_valid = [](auto event){ return true; }; 
  • 23. 3 . 21 CONNECTION (V4) - BENCHMARK GCC-7 Clang-3.9 Compilation time 0.151s 0.169s sizeof(ConnectionV4) 1b 1b Executable size 6.2K 6.2K Connect: ASM x86-64 main:          subq    $8, %rsp          movl    $.LC0, %edi          call    puts          xorl    %eax, %eax          addq    $8, %rsp          ret  https://godbolt.org/g/6z6UF4
  • 24. 3 . 22 CONNECTION (V4) - SUMMARY (+) Quick compilation times (+) Good performance (+) Minimal size used (+) Easy to follow (+) Easty to extend and maintain (+) Easy to test (-) Library has to be used (C++14)
  • 25. 3 . 23 CONNECTION - BENCHMARK Naive Enum/Switch Variant [Boost].SML Compilation time 0.101s 0.112s 0.269s 0.151s sizeof(sm) 3b 1b 2b/8b 1b Executable size 6.2K 6.2K 6.2K 6.2K Performance (connect) inlined inlined not- inlined inlined
  • 26. 3 . 24 MORE REALIST BENCHMARK Events States Transitions Process Events 50 50 50 1'000'000
  • 27. 3 . 25 MORE REALIST BENCHMARK MAIN int main() {    for (auto i = 0; i < 1'000'000; ++i) {     if (rand() % 2) sm.process_event(e1());      if (rand() % 2) sm.process_event(e2());      if (rand() % 2) sm.process_event(e3());      ...      if (rand() % 2) sm.process_event(e100());    }  }  CXXFLAGS $CXX ­std=c++1z ­O3 ­flto ­fno­exceptions ­DNDEBUG benchmark.cpp 
  • 28. 3 . 26 MORE REALIST - RESULTSBENCHMARK Enum/Switch Variant [Boost].SML Compilation time 0.132s 15.321s 0.582s Execution time 679ms 827ms 622ms Memory usage 1b 2b/8b 1b Executable size 15K 187K 34K Line of Code (LOC) ~300 (no macros) ~300 ~50 Median / 100 runs
  • 29. 4 . 1 [BOOST].SML UML-2.5 State Machine Language https://github.com/boost-experimental/sml
  • 30. 4 . 2 [BOOST].SML One header - 2k LOC - (boost/sml.hpp) / generated Neither Boost nor STL is required Quick compilation-times (-Wall -Wextra -Werror -pedantic -pedantic-errors) Blazing fast run-time (Generated at compile-time) No 'virtual's (-fno-rtti) Optional support for 'exception's (-fno-exceptions) Supported compilers (C++14) , , ,Clang-3.4+ XCode-6.1+ GCC-5.2+ MSVC-2015+
  • 31. 4 . 3 - API (SIMPLIFIED)[BOOST].SML /**   * Makes transition table from DSL   * @tparam Ts... transitions (transitional)   */  template <class... Ts> requires transitional<Ts>()...  struct transition_table;  /**   * Helper function to make transition_table (C++14)   * @tparam Ts... transitions (transitional)   * @return transition_table   */  template <class... Ts> requires transitional<Ts>()...  constexpr auto make_transition_table(Ts&&...) noexcept; 
  • 32. 4 . 4 - API (SIMPLIFIED)[BOOST].SML /**   * State Machine  *   * @tparam T Callable object returning transition_table   * @tparam TPolicies policies to be applied such as   *                   thread safe, exception safe, etc.   */  template<class T,           class... TPolicies> requires callable<transition_table, T>()  class sm;  /**   * Process event  * Complexity ­ O(1)   * @param TEvent event to be processed   */  template<class TEvent>  constexpr void process_event(const TEvent&); 
  • 33. 4 . 5 - FEATURES[BOOST].SML UML (2.5) Transition Anonymous, Internal, Self, Local transition Guard, Action Unexpected, Deffered, Any event State Entry/Exit Actions, Initial, Terminate state Composite/Sub state Explicit entry/exit, Fork Shallow History, Deep History Orthogonal regions Non-UML Logging, State visitor, Diagram gen., Run-time dispatch
  • 34. 4 . 6 - FEATURES[BOOST].SML We DON'T pay for features we are NOT using! For example, if the state machine doesn't use orthogonal regions, the code responsible for handling them won't be even generated
  • 35. - MORE REALISTIC EXAMPLE (SYSTEM)[BOOST].SML
  • 36. 4 . 7 Enum/Switch? No, thank you!
  • 37. 4 . 8 - MORE REALISTIC EXAMPLE (SYSTEM)[BOOST].SML uct Connection {  uto operator()() const {   return transition_table{     "Disconnected"_s(H) + connect / []{establish();}               = "Connecting"_s,     "Connecting"_s      + established                              = "Connected"_s,     "Connected"_s       + ping [ is_valid ] / []{resetTimeout();}     "Connected"_s       + timeout / []{establish();}               = "Connecting"_s,     "Connected"_s       + disconnect / []{close();}                = "Disconnected"_s   };  ;  uct System {  uto operator()() const {   return transition_table{    * "Idle"_s          + power_up [ has_battery and is_healthy] / connect = state<Connectio     state<Connection> + suspend                                          = "Suspended"_s,      "Suspended"_s     + resume                                           = state<Connectio   // ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­    * "Watchdog"_s      + tick / resetTimeout      "Watchdog"_s      + timeout                                          = X   }; 
  • 38. 4 . 9 - MORE REALISTIC EXAMPLE (SYSTEM)[BOOST].SML int main() {    using namespace sml;    sm<System> system;    system.process_event(power_up{});    assert(system.is(state<Connection>, "Watchdog"_s));    system.process_event(suspend{});    assert(system.is("Suspended"_s, "Watchdog"_s));    system.process_event(timeout{});    assert(system.is(X)); // true if any state is in terminated state (X)  } 
  • 39. 4 . 10 [BOOST].SML VS BOOST.MSM-EUML VS BOOST.STATECHART
  • 40. 4 . 11 OVERVIEW Library [Boost].SML Boost.MSM- eUML Boost.Statechart Standard C++14 C++98/03 C++98/03 Version 1.0.1 1.63 1.63 License Boost 1.0 Boost 1.0 Boost 1.0 Linkage header only header only header only
  • 41. 4 . 12 (SAME AS BEFORE)BENCHMARK Events States Transitions Process Events 50 50 50 1'000'000
  • 42. 4 . 13 - RESULTSBENCHMARK [Boost].SML Boost.MSM- eUML Boost.Statechart Compilation time 0.582s 1m15.935s 5.671s Execution time 622ms 664ms 2282ms Memory usage 1b 120b 224b Executable size 34K 611K 211K
  • 43. 5 . 1 DESIGN IN A NUTSHELL[BOOST].SML
  • 44. 5 . 2 TRANSITIONAL CONCEPT template <class T>  concept bool transitional() {    return requires(T transition) {      typename T::src_state;      typename T::dst_state;      typename T::event;      T::property; // initial, history state, etc.      { transition.execute(const typename T::Event&) } ­> optional<state_t>;    }  }; 
  • 45. 5 . 3 FRONT END DOMAIN SPECIFIC LANGUAGE (DSL) atic_assert(std::is_same<  decltype(    transition_table{      * "Disconnected"_s + connect / establish = "Connecting"_s,        "Connecting"_s   + established         = "Connected"_s    }  ),  transition_table<    // ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ /   //         src_state              dst_state            event        guard   action    /   // ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ /   transition<state<"Disconnected">, state<"Connecting">, connect,     always, establish>,   transition<state<"Connecting">,   state<"Connected">,  established, always, none>  >  }); 
  • 46. 5 . 4 BACK-END GENERATED AT COMPILE TIME MAPPING PER EVENT AND STATE ing mappings_t = type_list<  pair<connect, type_list<    transitions<      transition<state<"Disconnected">, state<"Connecting">, connect, always, establish>    >,    transitions<>, // Connecting (unexpected event)    transitions<>  // Connected  (unexpected event)  >,  pair<established, type_list<    transitions<>, // Disconnected (unexpected event)    transitions<      transition<state<"Connecting">, state<"Connected">,  established, always, none>    >,    transitions<>  // Connected (unexpected event)  > 
  • 47. 5 . 5 BACK-END PROCESS EVENT - JUMP TABLE - (SIMPLIFIED) template<class TEvent>  constexpr void process_event(const TEvent& event) {    process_event_impl(event, get_mappings_t<TEvent>{});  }  template<class... Transitions, class TEvent>  constexpr void process_event_impl(const TEvent& event, type_list<Transitions...>) {    const static (*dispatch_table[])(const TEvent&) = {       &Transitions::template execute<TEvent>...    };    dispatch_table[current_state](event); // Complexity: O(1) ­ jump table  } 
  • 49. 6 . 2 IF YOU LIKE IT OR NOT, YOUR CODE WON'T BE STATEFUL (MOST LIKELY)
  • 50. 6 . 3 IMPLICIT/HAND WRITTEN STATE MACHINES ARE HARD TO Reason about Maintain / Extend Test
  • 51. 6 . 4 STATE MACHINES ARE MORE THAN JUST SIMPLE TRANSITIONS UML-2.5
  • 52. 6 . 5 LEVERAGING ZERO-COST LIBRARIES WILL BOOST YOUR DESIGN AND/OR PERFRORMANCE /[Boost].SML Boost.MSM