summaryrefslogtreecommitdiffstats
path: root/test/src
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2016-01-15 13:42:06 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2016-01-15 13:42:06 (GMT)
commit38da34e8ba7956bed2e4703289ed70e3f6aade52 (patch)
treebaf0b424f395ae63fbf3f0d8123a3e59e1ef51d7 /test/src
parent613cf9fb6fe4b24bc7852d5a31953f6ff419e43c (diff)
downloaduscxml-38da34e8ba7956bed2e4703289ed70e3f6aade52.zip
uscxml-38da34e8ba7956bed2e4703289ed70e3f6aade52.tar.gz
uscxml-38da34e8ba7956bed2e4703289ed70e3f6aade52.tar.bz2
Working on C transformation
Diffstat (limited to 'test/src')
-rw-r--r--test/src/test-c-machine.cpp42
-rw-r--r--test/src/test-c-machine.machine.c350
-rw-r--r--test/src/test-lifecycle.cpp26
-rw-r--r--test/src/test-w3c.cpp146
4 files changed, 375 insertions, 189 deletions
diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp
index 390ca0a..c8848ac 100644
--- a/test/src/test-c-machine.cpp
+++ b/test/src/test-c-machine.cpp
@@ -6,7 +6,7 @@
#include <deque> // deque
#include <boost/algorithm/string.hpp> // trim
-//#define SCXML_VERBOSE
+#define SCXML_VERBOSE
#include "uscxml/config.h"
@@ -492,16 +492,20 @@ int exec_content_foreach_done(const scxml_ctx* ctx, const scxml_elem_foreach* fo
int exec_content_log(const scxml_ctx* ctx, const char* label, const char* expr) {
try {
- if (label != 0) {
-// printf("%s: %s\n", label, USER_DATA(ctx)->datamodel.evalAsString(expr).c_str());
- } else {
-// printf("%s\n", USER_DATA(ctx)->datamodel.evalAsString(expr).c_str());
- }
+ if (label != NULL) {
+ printf("%s%s", label, (expr != NULL ? ": " : ""));
+ }
+ if (expr != NULL) {
+ std::string msg = USER_DATA(ctx)->datamodel.evalAsString(expr);
+ printf("%s", msg.c_str());
+ }
+ if (label != NULL || expr != NULL) {
+ printf("\n");
+ }
} catch (Event e) {
exec_content_raise(ctx, e.name.c_str());
return SCXML_ERR_EXEC_CONTENT;
}
-
return SCXML_ERR_OK;
}
@@ -570,7 +574,7 @@ int main(int argc, char** argv) {
const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS");
if (envBenchmarkRuns != NULL) {
benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
- }
+ }
size_t remainingRuns = benchmarkRuns;
@@ -590,6 +594,8 @@ int main(int argc, char** argv) {
double avgDm = 0;
#endif
+ Timer tTotal;
+ tTotal.start();
while(remainingRuns-- > 0) {
memset(&ctx, 0, sizeof(scxml_ctx));
@@ -622,8 +628,15 @@ int main(int argc, char** argv) {
microSteps = 0;
while((err = scxml_step(&ctx)) == SCXML_ERR_OK) {
- microSteps++;
+ t.stop();
+ microSteps++;
+ if (ctx.event != NULL) {
+ delete ((Event*)(ctx.event));
+ }
+ t.start();
}
+ microSteps++;
+
assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL);
t.stop();
@@ -645,11 +658,12 @@ int main(int argc, char** argv) {
interpreterInfo.eq.clear();
interpreterInfo.iq.clear();
}
-
- // 14.25311111 us per microstep
- // 1.923466667 us
- std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms on average" << std::endl;
- std::cout << microSteps << " microsteps per iteration (" << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep)" << std::endl;
+ tTotal.stop();
+ std::cout << benchmarkRuns << " iterations" << std::endl;
+ std::cout << tTotal.elapsed * 1000.0 << " ms in total" << std::endl;
+ std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms per execution" << std::endl;
+ std::cout << microSteps << " microsteps per iteration" << std::endl;
+ std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl;
#ifdef BUILD_PROFILING
std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl;
diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c
index be14d3e..efc4c22 100644
--- a/test/src/test-c-machine.machine.c
+++ b/test/src/test-c-machine.machine.c
@@ -5,8 +5,13 @@
#define SET_BIT(idx, bitset) bitset[idx >> 3] |= (1 << (idx & 7));
#define CLEARBIT(idx, bitset) bitset[idx >> 3] &= (1 << (idx & 7)) ^ 0xFF;
-#define likely(x) (x)
-#define unlikely(x) (x)
+#ifdef __GNUC__
+#define likely(x) (__builtin_expect(!!(x), 1))
+#define unlikely(x) (__builtin_expect(!!(x), 0))
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
// error return codes
#define SCXML_ERR_OK 0
@@ -20,13 +25,14 @@
#define SCXML_ERR_UNSUPPORTED 8
#define SCXML_MACHINE_NAME ""
-#define SCXML_NUMBER_STATES 5
-#define SCXML_NUMBER_TRANSITIONS 4
+#define SCXML_NUMBER_STATES 11
+#define SCXML_NUMBER_TRANSITIONS 13
#define SCXML_TRANS_SPONTANEOUS 0x01
#define SCXML_TRANS_TARGETLESS 0x02
#define SCXML_TRANS_INTERNAL 0x04
#define SCXML_TRANS_HISTORY 0x08
+#define SCXML_TRANS_INITIAL 0x10
#define SCXML_STATE_ATOMIC 0x01
#define SCXML_STATE_PARALLEL 0x02
@@ -87,26 +93,26 @@ struct scxml_elem_data {
struct scxml_state {
const char* name; // eventual name
- uint16_t source; // parent
+ uint16_t parent; // parent
exec_content_t on_entry; // on entry handlers
exec_content_t on_exit; // on exit handlers
invoke_t invoke; // invocations
- char children[1]; // all children
- char completion[1]; // default completion
- char ancestors[1]; // all ancestors
+ char children[2]; // all children
+ char completion[2]; // default completion
+ char ancestors[2]; // all ancestors
const scxml_elem_data* data;
uint8_t type; // atomic, parallel, compound, final, history
};
struct scxml_transition {
uint16_t source;
- char target[1];
+ char target[2];
const char* event;
const char* condition;
exec_content_t on_transition;
uint8_t type;
- char conflicts[1];
- char exit_set[1];
+ char conflicts[2];
+ char exit_set[2];
};
struct scxml_elem_foreach {
@@ -165,12 +171,13 @@ struct scxml_elem_send {
struct scxml_ctx {
uint8_t flags;
- char config[1];
- char history[1];
- char pending_invokes[1];
- char initialized_data[1];
+ char config[2];
+ char history[2];
+ char pending_invokes[2];
+ char initialized_data[2];
void* user_data;
+ void* event;
dequeue_internal_cb_t dequeue_internal;
dequeue_external_cb_t dequeue_external;
@@ -191,15 +198,67 @@ struct scxml_ctx {
invoke_t invoke;
};
+static scxml_elem_data scxml_elem_datas[2] = {
+ { "Var1", NULL, "0", NULL },
+ { NULL, NULL, NULL, NULL }
+};
+
+static scxml_elem_send scxml_elem_sends[1] = {
+ { "timeout", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "'1s'", NULL, NULL, NULL, NULL, NULL }
+};
+
+static scxml_elem_donedata scxml_elem_donedatas[1] = {
+ { 0, NULL, NULL }
+};
+
+static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ return SCXML_ERR_OK;
+}
+
+static int s0_on_exit_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_assign != NULL) {
+ if ((ctx->exec_content_assign(ctx, "Var1", "Var1 + 1")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "Var1 is", "Var1")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int s0_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ s0_on_exit_0(ctx, state, event);
+ return SCXML_ERR_OK;
+}
+
static int s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &scxml_elem_sends[0])) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
if likely(ctx->exec_content_raise != NULL) {
- if ((ctx->exec_content_raise(ctx, "foo")) != SCXML_ERR_OK) return err;
+ if unlikely((ctx->exec_content_raise(ctx, "event1")) != SCXML_ERR_OK) return err;
} else {
return SCXML_ERR_MISSING_CALLBACK;
}
+ return SCXML_ERR_OK;
+}
+
+static int s0_initial(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
if likely(ctx->exec_content_raise != NULL) {
- if ((ctx->exec_content_raise(ctx, "bar")) != SCXML_ERR_OK) return err;
+ if unlikely((ctx->exec_content_raise(ctx, "event2")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "initial transition in s0", NULL)) != SCXML_ERR_OK) return err;
} else {
return SCXML_ERR_MISSING_CALLBACK;
}
@@ -208,6 +267,22 @@ static int s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const v
static int s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
s0_on_entry_0(ctx, state, event);
+ s0_initial(ctx, state, event);
+ return SCXML_ERR_OK;
+}
+
+static int s03_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "Var1 when entering s03", "Var1")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int s03_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ s03_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
@@ -241,19 +316,49 @@ static int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const v
return SCXML_ERR_OK;
}
-static scxml_state scxml_states[5] = {
- { NULL, 0, NULL, NULL, NULL, { 0x1e /* 01111, 1 2 3 4 */ }, { 0x02 /* 01000, 1 */ }, { 0x00 /* 00000, */ }, NULL, SCXML_STATE_COMPOUND },
- { "s0", 0, s0_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
- { "s1", 0, NULL, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
- { "pass", 0, pass_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_FINAL },
- { "fail", 0, fail_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_FINAL }
+static int sh1_transition0_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_raise != NULL) {
+ if unlikely((ctx->exec_content_raise(ctx, "event3")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "history transition in sh1", NULL)) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static scxml_state scxml_states[11] = {
+ { NULL, 0, NULL, NULL, NULL, { 0x82, 0x07 /* 01000001111, 1 7 8 9 10 */ }, { 0x02, 0x00 /* 01000000000, 1 */ }, { 0x00, 0x00 /* 00000000000, */ }, (const scxml_elem_data*)&scxml_elem_datas[0], SCXML_STATE_COMPOUND },
+ { "s0", 0, s0_on_entry, s0_on_exit, NULL, { 0x7c, 0x00 /* 00111110000, 2 3 4 5 6 */ }, { 0x04, 0x00 /* 00100000000, 2 */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_COMPOUND },
+ { NULL, 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_INITIAL },
+ { "sh1", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x74, 0x00 /* 00101110000, 2 4 5 6 */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_HISTORY_SHALLOW },
+ { "s01", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s02", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s03", 1, s03_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s2", 0, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s3", 0, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "pass", 0, pass_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_FINAL },
+ { "fail", 0, fail_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_FINAL }
};
-static scxml_transition scxml_transitions[4] = {
- { 1, { 0x04 /* 00100 */ }, "foo", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } },
- { 1, { 0x10 /* 00001 */ }, "*", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } },
- { 2, { 0x08 /* 00010 */ }, "bar", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } },
- { 2, { 0x10 /* 00001 */ }, "*", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } }
+static scxml_transition scxml_transitions[13] = {
+ { 2, { 0x08, 0x00 /* 00010000000 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS | SCXML_TRANS_INITIAL, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 3, { 0x10, 0x00 /* 00001000000 */ }, NULL, NULL, sh1_transition0_on_trans, SCXML_TRANS_SPONTANEOUS | SCXML_TRANS_HISTORY, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 4, { 0x20, 0x00 /* 00000100000 */ }, "event1", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0x7c, 0x00 /* 00111110000 */ } },
+ { 4, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 5, { 0x40, 0x00 /* 00000010000 */ }, "event2", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0x7c, 0x00 /* 00111110000 */ } },
+ { 5, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 6, { 0x02, 0x00 /* 01000000000 */ }, "event3", "Var1==0", NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 6, { 0x80, 0x00 /* 00000001000 */ }, "event1", "Var1==1", NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 6, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 7, { 0x00, 0x01 /* 00000000100 */ }, "event2", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 7, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 8, { 0x00, 0x04 /* 00000000001 */ }, "event3", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 8, { 0x00, 0x02 /* 00000000010 */ }, "timeout", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } }
};
#ifdef SCXML_VERBOSE
@@ -320,7 +425,7 @@ static int bit_any_set(const char* a, size_t i) {
return false;
}
-static int scxml_step(scxml_ctx* ctx) {
+int scxml_step(scxml_ctx* ctx) {
#ifdef SCXML_VERBOSE
printf("Config: ");
@@ -334,34 +439,34 @@ MACRO_STEP:
return SCXML_ERR_DONE;
int err = SCXML_ERR_OK;
- char conflicts[1] = {0};
- char target_set[1] = {0};
- char exit_set[1] = {0};
- char trans_set[1] = {0};
- char entry_set[1] = {0};
+ char conflicts[2] = {0, 0};
+ char target_set[2] = {0, 0};
+ char exit_set[2] = {0, 0};
+ char trans_set[2] = {0, 0};
+ char entry_set[2] = {0, 0};
- void* event;
if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {
- bit_or(target_set, scxml_states[0].completion, 1);
+ global_script(ctx, &scxml_states[0], NULL);
+ bit_or(target_set, scxml_states[0].completion, 2);
ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;
- goto COMPLETE_CONFIG;
+ goto ESTABLISH_ENTRY_SET;
}
if (ctx->flags & SCXML_CTX_SPONTANEOUS) {
- event = NULL;
+ ctx->event = NULL;
goto SELECT_TRANSITIONS;
}
- if ((event = ctx->dequeue_internal(ctx)) != NULL) {
+ if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
- if ((event = ctx->dequeue_external(ctx)) != NULL) {
+ if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
SELECT_TRANSITIONS:
for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
// never select history or initial transitions automatically
- if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_HISTORY))
+ if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))
continue;
// is the transition active?
@@ -369,32 +474,30 @@ SELECT_TRANSITIONS:
// is it non-conflicting?
if (!IS_SET(i, conflicts)) {
// is it enabled?
- if (ctx->is_enabled(ctx, &scxml_transitions[i], event) > 0) {
+ if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {
// remember that we found a transition
ctx->flags |= SCXML_CTX_TRANSITION_FOUND;
// transitions that are pre-empted
- bit_or(conflicts, scxml_transitions[i].conflicts, 1);
+ bit_or(conflicts, scxml_transitions[i].conflicts, 2);
// states that are directly targeted (resolve as entry-set later)
- bit_or(target_set, scxml_transitions[i].target, 1);
+ bit_or(target_set, scxml_transitions[i].target, 2);
// states that will be left
- bit_or(exit_set, scxml_transitions[i].exit_set, 1);
+ bit_or(exit_set, scxml_transitions[i].exit_set, 2);
SET_BIT(i, trans_set);
}
}
}
}
- bit_and(exit_set, ctx->config, 1);
+ bit_and(exit_set, ctx->config, 2);
if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {
ctx->flags |= SCXML_CTX_SPONTANEOUS;
} else {
ctx->flags &= ~SCXML_CTX_SPONTANEOUS;
- // goto MACRO_STEP;
- return SCXML_ERR_OK;
}
#ifdef SCXML_VERBOSE
@@ -402,25 +505,6 @@ SELECT_TRANSITIONS:
printStateNames(target_set);
#endif
-REMEMBER_HISTORY:
- for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
- if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {
- // a history state whose parent is about to be exited
- if unlikely(IS_SET(scxml_states[i].source, exit_set)) {
- char history[1] = {0};
- bit_copy(history, scxml_states[i].completion, 1);
-
- // set those states who were enabled
- bit_and(history, ctx->config, 1);
-
- // clear current history with completion mask
- bit_and_not(ctx->history, scxml_states[i].completion, 1);
-
- // set history
- bit_or(ctx->history, history, 1);
- }
- }
- }
#ifdef SCXML_VERBOSE
printf("Exiting: ");
printStateNames(exit_set);
@@ -431,55 +515,68 @@ REMEMBER_HISTORY:
printStateNames(ctx->history);
#endif
-EXIT_STATES:
- for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {
- if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {
- // call all on exit handlers
- if (scxml_states[i].on_exit != NULL) {
- if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], event)) != SCXML_ERR_OK)
- return err;
+
+ // REMEMBER_HISTORY:
+ for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
+ if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {
+ // a history state whose parent is about to be exited
+ if unlikely(IS_SET(scxml_states[i].parent, exit_set)) {
+ char history[2] = {0, 0};
+ bit_copy(history, scxml_states[i].completion, 2);
+
+ // set those states who were enabled
+ bit_and(history, ctx->config, 2);
+
+ // clear current history with completion mask - TODO: errornously clears nested history
+ bit_and_not(ctx->history, scxml_states[i].completion, 2);
+
+ // set history
+ bit_or(ctx->history, history, 2);
}
- CLEARBIT(i, ctx->config);
}
}
+#ifdef SCXML_VERBOSE
+ printf("Transitions: ");
+ printBitsetIndices(trans_set, sizeof(char) * 8 * 2);
+#endif
-COMPLETE_CONFIG:
+ESTABLISH_ENTRY_SET:
// calculate new entry set
- bit_copy(entry_set, target_set, 1);
+ bit_copy(entry_set, target_set, 2);
// iterate for ancestors
for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
if (IS_SET(i, entry_set)) {
- bit_or(entry_set, scxml_states[i].ancestors, 1);
+ bit_or(entry_set, scxml_states[i].ancestors, 2);
}
}
-ADD_DESCENDANTS:
// iterate for descendants
for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
if (IS_SET(i, entry_set)) {
switch (scxml_states[i].type) {
case SCXML_STATE_PARALLEL: {
- bit_or(entry_set, scxml_states[i].completion, 1);
+ bit_or(entry_set, scxml_states[i].completion, 2);
break;
}
case SCXML_STATE_HISTORY_SHALLOW:
case SCXML_STATE_HISTORY_DEEP: {
- char history_targets[1] = {0};
- if (!bit_has_and(scxml_states[i].completion, ctx->history, 1)) {
+ char history_targets[2] = {0, 0};
+ if (!bit_has_and(scxml_states[i].completion, ctx->history, 2) &&
+ !IS_SET(scxml_states[i].parent, ctx->config)) {
// nothing set for history, look for a default transition or enter parents completion
for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
if unlikely(scxml_transitions[j].source == i) {
- bit_or(entry_set, scxml_transitions[j].target, 1);
+ bit_or(entry_set, scxml_transitions[j].target, 2);
SET_BIT(j, trans_set);
break;
}
}
// TODO: enter parents default completion here
} else {
- bit_copy(history_targets, scxml_states[i].completion, 1);
- bit_and(history_targets, ctx->history, 1);
- bit_or(entry_set, history_targets, 1);
+ bit_copy(history_targets, scxml_states[i].completion, 2);
+ bit_and(history_targets, ctx->history, 2);
+ bit_or(entry_set, history_targets, 2);
}
break;
}
@@ -488,7 +585,7 @@ ADD_DESCENDANTS:
if (scxml_transitions[j].source == i) {
SET_BIT(j, trans_set);
CLEARBIT(i, entry_set);
- bit_or(entry_set, scxml_transitions[j].target, 1);
+ bit_or(entry_set, scxml_transitions[j].target, 2);
// one target may have been above, reestablish completion
// goto ADD_DESCENDANTS; // initial will have to be first!
}
@@ -496,10 +593,11 @@ ADD_DESCENDANTS:
break;
}
case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set
- if (!bit_has_and(entry_set, scxml_states[i].children, 1) &&
- !bit_has_and(ctx->config, scxml_states[i].children, 1))
+ if (!bit_has_and(entry_set, scxml_states[i].children, 2) &&
+ (!bit_has_and(ctx->config, scxml_states[i].children, 2) ||
+ bit_has_and(exit_set, scxml_states[i].children, 2)))
{
- bit_or(entry_set, scxml_states[i].completion, 1);
+ bit_or(entry_set, scxml_states[i].completion, 2);
}
break;
}
@@ -507,19 +605,26 @@ ADD_DESCENDANTS:
}
}
-#ifdef SCXML_VERBOSE
- printf("Transitions: ");
- printBitsetIndices(trans_set, sizeof(char) * 8 * 1);
-#endif
+// EXIT_STATES:
+ for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {
+ if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {
+ // call all on exit handlers
+ if (scxml_states[i].on_exit != NULL) {
+ if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
+ return err;
+ }
+ CLEARBIT(i, ctx->config);
+ }
+ }
-TAKE_TRANSITIONS:
+// TAKE_TRANSITIONS:
for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
if (IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY) == 0) {
// call executable content in transition
if (scxml_transitions[i].on_transition != NULL) {
if unlikely((err = scxml_transitions[i].on_transition(ctx,
&scxml_states[scxml_transitions[i].source],
- event)) != SCXML_ERR_OK)
+ ctx->event)) != SCXML_ERR_OK)
return err;
}
}
@@ -530,7 +635,7 @@ TAKE_TRANSITIONS:
printStateNames(entry_set);
#endif
-ENTER_STATES:
+// ENTER_STATES:
for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
if (IS_SET(i, entry_set) && !IS_SET(i, ctx->config)) {
// these are no proper states
@@ -550,26 +655,38 @@ ENTER_STATES:
}
if (scxml_states[i].on_entry != NULL) {
- if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], event)) != SCXML_ERR_OK)
+ if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
return err;
}
+ // take history transitions
+ for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
+ if unlikely(IS_SET(j, trans_set) &&
+ (scxml_transitions[j].type & SCXML_TRANS_HISTORY) &&
+ scxml_states[scxml_transitions[j].source].parent == i) {
+ // call executable content in transition
+ if (scxml_transitions[j].on_transition != NULL) {
+ if unlikely((err = scxml_transitions[j].on_transition(ctx,
+ &scxml_states[i],
+ ctx->event)) != SCXML_ERR_OK)
+ return err;
+ }
+ }
+ }
+
// handle final states
if unlikely(scxml_states[i].type == SCXML_STATE_FINAL) {
if unlikely(scxml_states[i].ancestors[0] == 0x01) {
ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;
} else {
// raise done event
- size_t parent = 0;
- for (int j = SCXML_NUMBER_STATES - 1; j >= 0; j--) {
- // we could trade runtime for memory here by saving the parent index
- if unlikely(IS_SET(j, scxml_states[i].ancestors)) {
- parent = j;
- break;
- }
+ scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];
+ while(ELEM_DONEDATA_IS_SET(donedata)) {
+ if unlikely(donedata->source == i)
+ break;
+ donedata++;
}
- // is this raised for toplevel final as well?
- ctx->raise_done_event(ctx, &scxml_states[parent], NULL);
+ ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
}
/**
@@ -581,18 +698,18 @@ ENTER_STATES:
*/
for (int j = 0; j < SCXML_NUMBER_STATES; j++) {
if unlikely(scxml_states[j].type == SCXML_STATE_PARALLEL) {
- char parallel_children[1] = {0};
+ char parallel_children[2] = {0, 0};
size_t parallel = j;
for (int k = 0; k < SCXML_NUMBER_STATES; k++) {
if unlikely(IS_SET(parallel, scxml_states[k].ancestors) && IS_SET(k, ctx->config)) {
if (scxml_states[k].type == SCXML_STATE_FINAL) {
- bit_and_not(parallel_children, scxml_states[k].ancestors, 1);
+ bit_and_not(parallel_children, scxml_states[k].ancestors, 2);
} else {
SET_BIT(k, parallel_children);
}
}
}
- if unlikely(!bit_any_set(parallel_children, 1)) {
+ if unlikely(!bit_any_set(parallel_children, 2)) {
ctx->raise_done_event(ctx, &scxml_states[parallel], NULL);
}
}
@@ -603,19 +720,6 @@ ENTER_STATES:
}
}
-HISTORY_TRANSITIONS:
- for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
- if unlikely(IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY)) {
- // call executable content in transition
- if (scxml_transitions[i].on_transition != NULL) {
- if unlikely((err = scxml_transitions[i].on_transition(ctx,
- &scxml_states[scxml_transitions[i].source],
- event)) != SCXML_ERR_OK)
- return err;
- }
- }
- }
-
return SCXML_ERR_OK;
}
diff --git a/test/src/test-lifecycle.cpp b/test/src/test-lifecycle.cpp
index 84ffbb5..7ac40fa 100644
--- a/test/src/test-lifecycle.cpp
+++ b/test/src/test-lifecycle.cpp
@@ -275,7 +275,9 @@ int main(int argc, char** argv) {
Interpreter interpreter = Interpreter::fromXML(xml, "");
interpreter.addMonitor(mon);
- callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_AFTERENTERINGSTATE);
callBackSeq.push_back(USCXML_BEFOREMICROSTEP);
@@ -299,9 +301,10 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_BEFORECOMPLETION);
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
- assert(interpreter.getState() == USCXML_INSTANTIATED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.getState() == USCXML_INSTANTIATED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
assert(callBackSeq.empty());
}
@@ -319,6 +322,8 @@ int main(int argc, char** argv) {
Interpreter interpreter = Interpreter::fromXML(xml, "");
interpreter.addMonitor(mon);
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_AFTERENTERINGSTATE);
@@ -335,10 +340,13 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
assert(interpreter.getState() == USCXML_INSTANTIATED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
interpreter.reset();
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_AFTERENTERINGSTATE);
@@ -355,7 +363,8 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
assert(interpreter.getState() == USCXML_INSTANTIATED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
}
@@ -378,6 +387,8 @@ int main(int argc, char** argv) {
Interpreter interpreter = Interpreter::fromXML(xml, "");
interpreter.addMonitor(mon);
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_BEFOREEXECUTINGCONTENT);
callBackSeq.push_back(USCXML_AFTEREXECUTINGCONTENT);
@@ -406,10 +417,11 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_BEFORECOMPLETION);
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
- assert(interpreter.getState() == USCXML_INSTANTIATED);
+ assert(interpreter.getState() == USCXML_INSTANTIATED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
assert(interpreter.step() == USCXML_IDLE);
assert(interpreter.step(true) == USCXML_MACROSTEPPED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
}
}
diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp
index 3de8e4d..aa2bff5 100644
--- a/test/src/test-w3c.cpp
+++ b/test/src/test-w3c.cpp
@@ -2,10 +2,27 @@
// #define protected public
#include "uscxml/config.h"
+
+#ifdef APPLE
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <pthread.h>
+#endif
+
#include "uscxml/Common.h"
#include "uscxml/Convenience.h"
+
+#ifdef BUILD_PROFILING
+// get access to the datamodel - this causes strange issues with MSVC depending on include order
+// may be better to ifndef all protected: and private: stanzas for profiling?
+#define protected public
#include "uscxml/Interpreter.h"
+#undef protected
+# endif
+
+
#include "uscxml/DOMUtils.h"
+#include "uscxml/concurrency/Timer.h"
#include "uscxml/Factory.h"
#include "uscxml/server/HTTPServer.h"
@@ -29,7 +46,7 @@
static bool withFlattening = false;
static double delayFactor = 1;
-static size_t benchmarkRuns = 0;
+static size_t benchmarkRuns = 1;
static std::string documentURI;
int retCode = EXIT_FAILURE;
@@ -63,17 +80,45 @@ class W3CStatusMonitor : public uscxml::InterpreterMonitor {
void beforeCompletion(uscxml::Interpreter tmp) {
if (interpreter.getConfiguration().size() == 1 && interpreter.isInState("pass")) {
- std::cout << "TEST SUCCEEDED" << std::endl;
+#ifndef BUILD_PROFILING
+ std::cout << "TEST SUCCEEDED" << std::endl;
+#endif
retCode = EXIT_SUCCESS;
return;
}
+#ifndef BUILD_PROFILING
std::cout << "TEST FAILED" << std::endl;
- }
+#endif
+ retCode = EXIT_FAILURE;
+ }
};
int main(int argc, char** argv) {
using namespace uscxml;
+#ifdef APPLE
+ mach_timebase_info_data_t timebase_info;
+ mach_timebase_info(&timebase_info);
+
+ const uint64_t NANOS_PER_MSEC = 1000000ULL;
+ double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
+
+ thread_time_constraint_policy_data_t policy;
+ policy.period = 0;
+ policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
+ policy.constraint = (uint32_t)(10 * clock2abs);
+ policy.preemptible = FALSE;
+
+ int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
+ THREAD_TIME_CONSTRAINT_POLICY,
+ (thread_policy_t)&policy,
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+ if (kr != KERN_SUCCESS) {
+ mach_error("thread_policy_set:", kr);
+ exit(1);
+ }
+#endif
+
try {
#if defined(HAS_SIGNAL_H) && !defined(WIN32)
@@ -85,7 +130,6 @@ int main(int argc, char** argv) {
}
google::InitGoogleLogging(argv[0]);
- google::LogToStderr();
HTTPServer::getInstance(32954, 32955, NULL); // bind to some random tcp sockets for ioprocessor tests
@@ -94,6 +138,14 @@ int main(int argc, char** argv) {
delayFactor = strTo<double>(dfEnv);
}
+ const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS");
+ if (envBenchmarkRuns != NULL) {
+ benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
+ google::SetStderrLogging(3);
+ } else {
+ google::LogToStderr();
+ }
+
int option;
while ((option = getopt(argc, argv, "fd:b:")) != -1) {
switch(option) {
@@ -111,11 +163,6 @@ int main(int argc, char** argv) {
}
}
- const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS");
- if (envBenchmarkRuns != NULL) {
- benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
- }
-
documentURI = argv[optind];
LOG(INFO) << "Processing " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor)) << (benchmarkRuns > 0 ? " for " + toStr(benchmarkRuns) + " benchmarks" : "");
@@ -162,50 +209,59 @@ int main(int argc, char** argv) {
W3CStatusMonitor* vm = new W3CStatusMonitor();
interpreter.addMonitor(vm);
- if (benchmarkRuns > 0) {
- LOG(INFO) << "Benchmarking " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor));
+ LOG(INFO) << "Benchmarking " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor));
+
+ size_t remainingRuns = benchmarkRuns;
+ size_t microSteps = 0;
- InterpreterState state = interpreter.getState();
+ Timer tTotal;
+ tTotal.start();
- double avg = 0;
+ double avg = 0;
#ifdef BUILD_PROFILING
- double avgDm = 0;
- double avgStep = 0;
+ double avgDm = 0;
+ double avgStep = 0;
#endif
- size_t remainingRuns = benchmarkRuns;
- uint64_t start = tthread::chrono::system_clock::now();
-
- while(remainingRuns-- > 0) {
- Timer t;
- t.start();
- for(;;) {
- state = interpreter.step(true);
- if (state == USCXML_FINISHED) {
+
+ while(remainingRuns-- > 0) {
+ Timer t;
+ microSteps = 0;
+
+ InterpreterState state = interpreter.getState();
+
+ for(;;) {
+ state = interpreter.step(true);
+ microSteps++;
+ if (state == USCXML_INITIALIZED) {
+ t.start();
+ } else if (state == USCXML_FINISHED) {
#ifdef BUILD_PROFILING
- avgDm += interpreter.getDataModel().timer.elapsed;
- interpreter.getDataModel().timer.reset();
- avgStep += interpreter.timer.elapsed;
+ avgDm += interpreter._impl->_dataModel.timer.elapsed;
+ interpreter._impl->_dataModel.timer.reset();
+ avgStep += interpreter.timer.elapsed;
#endif
- }
- if (state < 0)
- break;
- }
- t.stop();
- avg += t.elapsed;
- interpreter.reset();
- }
- uint64_t totalDuration = tthread::chrono::system_clock::now() - start;
- std::cout << benchmarkRuns << " iterations in " << totalDuration << " ms" << std::endl;
- std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms on average" << std::endl;
+ }
+ if (state < 0)
+ break;
+ }
+ assert(retCode == EXIT_SUCCESS);
+ t.stop();
+ avg += t.elapsed;
+ interpreter.reset();
+ std::cout << "." << std::flush;
+ }
+
+ tTotal.stop();
+
+ std::cout << benchmarkRuns << " iterations" << std::endl;
+ std::cout << tTotal.elapsed * 1000.0 << " ms in total" << std::endl;
+ std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms per execution" << std::endl;
+ std::cout << microSteps << " microsteps per iteration" << std::endl;
+ std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl;
#ifdef BUILD_PROFILING
- std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
- std::cout << (avgStep * 1000.0) / (double)benchmarkRuns << " ms in microsteps" << std::endl;
+ std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
+ std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl;
#endif
-
- } else {
- interpreter.start();
- while(interpreter.runOnMainThread(25));
- }
}
} catch(Event e) {
std::cout << e << std::endl;