diff options
author | Stefan Radomski <sradomski@mintwerk.de> | 2016-01-08 22:15:37 (GMT) |
---|---|---|
committer | Stefan Radomski <sradomski@mintwerk.de> | 2016-01-08 22:15:37 (GMT) |
commit | 9f4d810400550d1b98ab944cd96f937720eb6b0d (patch) | |
tree | a30226ae642e54e217c9b89523d75f1346d5f7cb /test/src/test-c-machine.cpp | |
parent | f9eb54fc9c17116954846133b33f7a241e662cbc (diff) | |
download | uscxml-9f4d810400550d1b98ab944cd96f937720eb6b0d.zip uscxml-9f4d810400550d1b98ab944cd96f937720eb6b0d.tar.gz uscxml-9f4d810400550d1b98ab944cd96f937720eb6b0d.tar.bz2 |
Fixed compilation for gcc on Linux again
Diffstat (limited to 'test/src/test-c-machine.cpp')
-rw-r--r-- | test/src/test-c-machine.cpp | 375 |
1 files changed, 302 insertions, 73 deletions
diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp index a9e5ecb..4bbc653 100644 --- a/test/src/test-c-machine.cpp +++ b/test/src/test-c-machine.cpp @@ -6,13 +6,22 @@ #include <deque> // deque #include <boost/algorithm/string.hpp> // trim -#define SCXML_VERBOSE 1 +//#define SCXML_VERBOSE + +#include "uscxml/config.h" + +#ifdef APPLE +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <pthread.h> +#endif #ifndef AUTOINCLUDE_TEST #include "test-c-machine.machine.c" #endif #include "uscxml/Convenience.h" +#include "uscxml/concurrency/Timer.h" //#include "uscxml/DOMUtils.h" #include "uscxml/Factory.h" #include "uscxml/InterpreterInfo.h" @@ -21,6 +30,10 @@ #include "uscxml/concurrency/DelayedEventQueue.h" #include "uscxml/concurrency/tinythread.h" +#ifdef BUILD_PROFILING +# include "uscxml/plugins/DataModel.h" +# endif + #define USER_DATA(ctx) ((GenCInterpreterInfo*)(((scxml_ctx*)ctx)->user_data)) using namespace uscxml; @@ -82,33 +95,49 @@ public: int matches(const char* desc, const char* event) { const char* dPtr = desc; const char* ePtr = event; - while(true) { + while(*dPtr != 0) { - // next event descriptor - if (*dPtr == ' ') { + if (*dPtr == '*' && *ePtr != 0) // something following + return true; + + // descriptor differs from event name + if (*dPtr != *ePtr) { + // move to next descriptor + while(*dPtr != ' ' && *dPtr != 0) { + dPtr++; + } + if (*dPtr == 0) + return false; dPtr++; ePtr = event; - continue; + } else { + // move both pointers one character + dPtr++; + ePtr++; + } // descriptor is done, return match - if (*dPtr == 0 || *dPtr == '*') + if (((*dPtr == 0 || *dPtr == ' ') && (*ePtr == 0 || *ePtr == ' ')) || // exact match, end of string + (*dPtr == ' ' && *ePtr == '.') || (*dPtr == 0 && *ePtr == '.')) // prefix match return true; - - // descriptor differs from event name - if (*dPtr != *ePtr) - return false; - - // move both pointers one character - dPtr++; - ePtr++; } + return false; } int exec_content_raise(const scxml_ctx* ctx, const char* event) { Event* e = new Event(); e->name = strdup(event); + + if (boost::starts_with(e->name, "error.")) { + e->eventType = Event::PLATFORM; + } else { + e->eventType = Event::INTERNAL; + } + +#ifdef SCXML_VERBOSE printf("Raising Internal Event: %s\n", e->name.c_str()); +#endif USER_DATA(ctx)->iq.push_back(e); return SCXML_ERR_OK; } @@ -145,9 +174,42 @@ int is_enabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) { return false; } -int raise_done_event(const scxml_ctx* ctx, const scxml_state* state) { - std::string doneName = "done.state."; - exec_content_raise(ctx, (doneName + state->name).c_str()); +int raise_done_event(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) { + Event* e = new Event(); + e->name = std::string("done.state.") + state->name; + + if (donedata) { + if (donedata->content != NULL) { + e->data = Data(donedata->content, Data::VERBATIM); + } else if (donedata->contentexpr != NULL) { + try { + e->data = USER_DATA(ctx)->datamodel->getStringAsData(donedata->contentexpr); + } catch (Event e) { + exec_content_raise(ctx, e.name.c_str()); + } + } else { + try { + const scxml_elem_param* param = donedata->params; + while (param && ELEM_PARAM_IS_SET(param)) { + Data paramValue; + if (param->expr != NULL) { + paramValue = USER_DATA(ctx)->datamodel->getStringAsData(param->expr); + } else if(param->location) { + paramValue = USER_DATA(ctx)->datamodel->getStringAsData(param->location); + } + e->params.insert(std::make_pair(param->name, paramValue)); + param++; + } + } catch (Event e) { + exec_content_raise(ctx, e.name.c_str()); + } + } + } + +#ifdef SCXML_VERBOSE + printf("Raising Done Event: %s\n", e->name.c_str()); +#endif + USER_DATA(ctx)->iq.push_back(e); return SCXML_ERR_OK; } @@ -156,10 +218,16 @@ void delayedSend(void* ctx, std::string eventName) { SendRequest* e = USER_DATA(ctx)->sendIds[eventName]; if (e->target == "#_internal") { + e->eventType = Event::INTERNAL; +#ifdef SCXML_VERBOSE printf("Pushing Internal Event: %s\n", e->name.c_str()); +#endif USER_DATA(ctx)->iq.push_back(e); } else { + e->eventType = Event::EXTERNAL; +#ifdef SCXML_VERBOSE printf("Pushing External Event: %s\n", e->name.c_str()); +#endif USER_DATA(ctx)->eq.push_back(e); } USER_DATA(ctx)->monitor.notify_all(); @@ -182,6 +250,27 @@ int exec_content_cancel(const scxml_ctx* ctx, const char* sendid, const char* se return SCXML_ERR_OK; } +std::string spaceNormalize(const std::string& text) { + std::stringstream content; + std::string seperator; + + size_t start = 0; + for (int i = 0; i < text.size(); i++) { + if (isspace(text[i])) { + if (i > 0 && start < i) { + content << seperator << text.substr(start, i - start); + seperator = " "; + } + while(isspace(text[++i])); // skip whitespaces + start = i; + } else if (i + 1 == text.size()) { + content << seperator << text.substr(start, i + 1 - start); + } + } + return content.str(); +} + + int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { SendRequest* e = new SendRequest(); @@ -190,6 +279,8 @@ int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { e->target = send->target; } else if (send->targetexpr != NULL) { e->target = USER_DATA(ctx)->datamodel->evalAsString(send->targetexpr); + } else { + e->target = "#_external"; } if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) { @@ -198,12 +289,20 @@ int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { return SCXML_ERR_INVALID_TARGET; } - if (send->type != NULL) { - e->type = send->type; - } else if (send->typeexpr != NULL) { - e->type = USER_DATA(ctx)->datamodel->evalAsString(send->typeexpr); - } else { - e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + e->origin = e->target; + + try { + if (send->type != NULL) { + e->type = send->type; + } else if (send->typeexpr != NULL) { + e->type = USER_DATA(ctx)->datamodel->evalAsString(send->typeexpr); + } else { + e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + } + } catch (Event e) { + exec_content_raise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; } // only one somewhat supported @@ -221,31 +320,67 @@ int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { e->name = strdup(send->event); } - const scxml_elem_param* param = send->params; - while (param && ELEM_PARAM_IS_SET(param)) { - Data paramValue; - if (param->expr != NULL) { - paramValue = USER_DATA(ctx)->datamodel->getStringAsData(param->expr); - } else if(param->location) { - paramValue = USER_DATA(ctx)->datamodel->getStringAsData(param->location); + try { + const scxml_elem_param* param = send->params; + while (param && ELEM_PARAM_IS_SET(param)) { + Data paramValue; + if (param->expr != NULL) { + paramValue = USER_DATA(ctx)->datamodel->getStringAsData(param->expr); + } else if(param->location) { + paramValue = USER_DATA(ctx)->datamodel->getStringAsData(param->location); + } + e->params.insert(std::make_pair(param->name, paramValue)); + param++; } - e->params.insert(std::make_pair(param->name, paramValue)); - param++; + } catch (Event e) { + exec_content_raise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; } - + + try { + if (send->namelist != NULL) { + const char* bPtr = &send->namelist[0]; + const char* ePtr = bPtr; + while(*ePtr != '\0') { + ePtr++; + if (*ePtr == ' ' || *ePtr == '\0') { + std::string key(bPtr, ePtr - bPtr); + e->params.insert(std::make_pair(key, USER_DATA(ctx)->datamodel->getStringAsData(key))); + if (*ePtr == '\0') + break; + bPtr = ++ePtr; + } + } + } + } catch (Event e) { + exec_content_raise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; + } + if (send->content != NULL) { - e->data = Data(send->content, Data::VERBATIM); + // will it parse as json? + Data d = Data::fromJSON(send->content); + if (!d.empty()) { + e->data = d; + } else { + e->data = Data(spaceNormalize(send->content), Data::VERBATIM); + } } const char* sendid = NULL; if (send->id != NULL) { sendid = send->id; + e->sendid = sendid; } else { sendid = strdup(UUID::getUUID().c_str()); - if (send->idlocation != NULL) + if (send->idlocation != NULL) { USER_DATA(ctx)->datamodel->assign(send->idlocation, Data(sendid, Data::VERBATIM)); + } else { + e->hideSendId = true; + } } + size_t delayMs = 0; std::string delay; if (send->delayexpr != NULL) { @@ -299,9 +434,15 @@ int exec_content_init(const scxml_ctx* ctx, const scxml_elem_data* data) { } int exec_content_assign(const scxml_ctx* ctx, const char* location, const char* expr) { + std::string key = location; + if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") { + exec_content_raise(ctx, "error.execution"); + return SCXML_ERR_EXEC_CONTENT; + } + try { Data d(expr, Data::INTERPRETED); - USER_DATA(ctx)->datamodel->assign(location, d); + USER_DATA(ctx)->datamodel->assign(key, d); } catch (Event e) { exec_content_raise(ctx, e.name.c_str()); return SCXML_ERR_EXEC_CONTENT; @@ -350,10 +491,25 @@ 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) { - if (label != 0) { - printf("%s: %s\n", label, expr); - } else { - printf("%s\n", USER_DATA(ctx)->datamodel->evalAsString(expr).c_str()); + 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()); + } + } catch (Event e) { + exec_content_raise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; + } + + return SCXML_ERR_OK; +} + +int exec_content_script(const scxml_ctx* ctx, const char* src, const char* content) { + if (content != NULL) { + USER_DATA(ctx)->datamodel->eval(Arabica::DOM::Element<std::string>(), content); + } else if (src != NULL) { + return SCXML_ERR_UNSUPPORTED; } return SCXML_ERR_OK; } @@ -366,7 +522,9 @@ void* dequeue_external(const scxml_ctx* ctx) { Event* e = USER_DATA(ctx)->eq.front(); USER_DATA(ctx)->eq.pop_front(); USER_DATA(ctx)->datamodel->setEvent(*e); +#ifdef SCXML_VERBOSE printf("Popping External Event: %s\n", e->name.c_str()); +#endif return e; } @@ -376,54 +534,125 @@ void* dequeue_internal(const scxml_ctx* ctx) { Event* e = USER_DATA(ctx)->iq.front(); USER_DATA(ctx)->iq.pop_front(); USER_DATA(ctx)->datamodel->setEvent(*e); +#ifdef SCXML_VERBOSE printf("Popping Internal Event: %s\n", e->name.c_str()); +#endif return e; } int main(int argc, char** argv) { + +#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 + int err; + size_t benchmarkRuns = 1; + const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS"); + if (envBenchmarkRuns != NULL) { + benchmarkRuns = strTo<size_t>(envBenchmarkRuns); + } + + size_t remainingRuns = benchmarkRuns; + // setup info object required for datamodel GenCInterpreterInfo interpreterInfo; - interpreterInfo.name = "adsf"; + interpreterInfo.name = SCXML_MACHINE_NAME; interpreterInfo.sessionId = "rfwef"; - interpreterInfo.datamodel = Factory::getInstance()->createDataModel("ecmascript", &interpreterInfo); interpreterInfo.delayQueue.start(); scxml_ctx ctx; - memset(&ctx, 0, sizeof(scxml_ctx)); interpreterInfo.ctx = &ctx; - - // set info object as user data - ctx.user_data = (void*)&interpreterInfo; - - // register callbacks with scxml context - ctx.is_enabled = &is_enabled; - ctx.is_true = &is_true; - ctx.raise_done_event = &raise_done_event; - - ctx.exec_content_send = &exec_content_send; - ctx.exec_content_raise = &exec_content_raise; - ctx.exec_content_cancel = &exec_content_cancel; - ctx.exec_content_log = &exec_content_log; - ctx.exec_content_assign = &exec_content_assign; - ctx.exec_content_foreach_init = &exec_content_foreach_init; - ctx.exec_content_foreach_next = &exec_content_foreach_next; - ctx.exec_content_foreach_done = &exec_content_foreach_done; - ctx.dequeue_external = &dequeue_external; - ctx.dequeue_internal = &dequeue_internal; - ctx.exec_content_init = &exec_content_init; - - while((err = scxml_step(&ctx)) == SCXML_ERR_OK); - assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL); - - size_t passIdx = 0; - for (int i = 0; i < SCXML_NUMBER_STATES; i++) { - if (scxml_states[i].name && strcmp(scxml_states[i].name, "pass") == 0) { - passIdx = i; - break; + + double avg = 0; + size_t microSteps = 0; +#ifdef BUILD_PROFILING + double avgDm = 0; +#endif + + while(remainingRuns-- > 0) { + memset(&ctx, 0, sizeof(scxml_ctx)); + + // fresh dm (expensive :( ) + interpreterInfo.datamodel = Factory::getInstance()->createDataModel("ecmascript", &interpreterInfo); + + // set info object as user data + ctx.user_data = (void*)&interpreterInfo; + + // register callbacks with scxml context + ctx.is_enabled = &is_enabled; + ctx.is_true = &is_true; + ctx.raise_done_event = &raise_done_event; + + ctx.exec_content_send = &exec_content_send; + ctx.exec_content_raise = &exec_content_raise; + ctx.exec_content_cancel = &exec_content_cancel; + ctx.exec_content_log = &exec_content_log; + ctx.exec_content_assign = &exec_content_assign; + ctx.exec_content_foreach_init = &exec_content_foreach_init; + ctx.exec_content_foreach_next = &exec_content_foreach_next; + ctx.exec_content_foreach_done = &exec_content_foreach_done; + ctx.dequeue_external = &dequeue_external; + ctx.dequeue_internal = &dequeue_internal; + ctx.exec_content_init = &exec_content_init; + ctx.exec_content_script = &exec_content_script; + + Timer t; + t.start(); + + microSteps = 0; + while((err = scxml_step(&ctx)) == SCXML_ERR_OK) { microSteps++; } + assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL); + + t.stop(); + avg += t.elapsed; +#ifdef BUILD_PROFILING + avgDm += interpreterInfo.datamodel.get()->timer.elapsed; + interpreterInfo.datamodel.get()->timer.elapsed = 0; +#endif + size_t passIdx = 0; + for (int i = 0; i < SCXML_NUMBER_STATES; i++) { + if (scxml_states[i].name && strcmp(scxml_states[i].name, "pass") == 0) { + passIdx = i; + break; + } } + + assert(IS_SET(passIdx, ctx.config)); + interpreterInfo.delayQueue.cancelAllEvents(); + interpreterInfo.eq.clear(); + interpreterInfo.iq.clear(); } - assert(IS_SET(passIdx, ctx.config)); + + // 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; +#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; +#endif + interpreterInfo.delayQueue.stop(); + tthread::this_thread::sleep_for(tthread::chrono::milliseconds(100)); return EXIT_SUCCESS; }
\ No newline at end of file |