From f8f04856ed1384b73c4e3659cee9660bc7e917ba Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Wed, 25 Feb 2026 21:07:27 +0100 Subject: [PATCH] Optimised failed test --- .gitignore | 1 + Headers/DebugBrokerWrapper.h | 257 ++++------ Headers/DebugService.h | 90 +++- Source/DebugService.cpp | 569 +++++++++++------------ Test/Configurations/debug_test.cfg | 32 +- Test/Integration/BrokerExecuteTest.cpp | 109 +++++ Test/Integration/CMakeLists.txt | 9 + Test/Integration/FinalValidationTest.cpp | 217 +++++++++ Test/Integration/PerformanceTest.cpp | 109 +++++ Test/UnitTests/main.cpp | 10 +- Tools/gui_client/src/main.rs | 52 ++- Tools/pipeline_validator/Cargo.lock | 431 +++++++++++++++++ Tools/pipeline_validator/Cargo.toml | 10 + Tools/pipeline_validator/src/main.rs | 135 ++++++ app_output.log | 334 +++++++++++-- run_coverage.sh | 30 ++ run_debug_app.sh | 4 +- 17 files changed, 1842 insertions(+), 557 deletions(-) create mode 100644 Test/Integration/BrokerExecuteTest.cpp create mode 100644 Test/Integration/FinalValidationTest.cpp create mode 100644 Test/Integration/PerformanceTest.cpp create mode 100644 Tools/pipeline_validator/Cargo.lock create mode 100644 Tools/pipeline_validator/Cargo.toml create mode 100644 Tools/pipeline_validator/src/main.rs create mode 100755 run_coverage.sh diff --git a/.gitignore b/.gitignore index 28e1845..01dc37c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ Build/ +Build_Coverage/ bin/ *.o *.so diff --git a/Headers/DebugBrokerWrapper.h b/Headers/DebugBrokerWrapper.h index aa77b11..b517548 100644 --- a/Headers/DebugBrokerWrapper.h +++ b/Headers/DebugBrokerWrapper.h @@ -9,6 +9,7 @@ #include "Vector.h" #include "FastPollingMutexSem.h" #include "HighResolutionTimer.h" +#include "Atomic.h" // Original broker headers #include "MemoryMapInputBroker.h" @@ -30,42 +31,37 @@ namespace MARTe { */ class DebugBrokerHelper { public: - static void Process(DebugService* service, DebugSignalInfo** signalInfoPointers, Vector& activeIndices, Vector& activeSizes, FastPollingMutexSem& activeMutex) { + static void Process(DebugService* service, BrokerInfo& info) { if (service == NULL_PTR(DebugService*)) return; - // Re-establish break logic while (service->IsPaused()) { Sleep::MSec(10); } - activeMutex.FastLock(); - uint32 n = activeIndices.GetNumberOfElements(); - if (n > 0 && signalInfoPointers != NULL_PTR(DebugSignalInfo**)) { - // Capture timestamp ONCE per broker cycle for lowest impact + if (*info.anyActiveFlag) { + uint32 idx = info.currentSetIdx; + BrokerActiveSet& set = info.sets[idx]; uint64 ts = (uint64)((float64)HighResolutionTimer::Counter() * HighResolutionTimer::Period() * 1000000.0); - - for (uint32 i = 0; i < n; i++) { - uint32 idx = activeIndices[i]; - uint32 size = activeSizes[i]; - DebugSignalInfo *s = signalInfoPointers[idx]; - service->ProcessSignal(s, size, ts); + + for (uint32 i = 0; i < set.numForced; i++) { + SignalExecuteInfo& s = set.forcedSignals[i]; + DebugService::CopySignal(s.memoryAddress, s.forcedValue, s.size); + } + + for (uint32 i = 0; i < set.numTraced; i++) { + SignalExecuteInfo& s = set.tracedSignals[i]; + (void)service->traceBuffer.Push(s.internalID, ts, s.memoryAddress, s.size); } } - activeMutex.FastUnLock(); } - // Pass numCopies explicitly so we can mock it - static void InitSignals(BrokerI* broker, DataSourceI &dataSourceIn, DebugService* &service, DebugSignalInfo** &signalInfoPointers, uint32 numCopies, MemoryMapBrokerCopyTableEntry* copyTable, const char8* functionName, SignalDirection direction, volatile bool* anyActiveFlag, Vector* activeIndices, Vector* activeSizes, FastPollingMutexSem* activeMutex) { + static void InitSignals(BrokerI* broker, DataSourceI &dataSourceIn, DebugService* &service, DebugSignalInfo** &signalInfoPointers, uint32 numCopies, MemoryMapBrokerCopyTableEntry* copyTable, const char8* functionName, SignalDirection direction, volatile bool* anyActiveFlag) { if (numCopies > 0) { signalInfoPointers = new DebugSignalInfo*[numCopies]; for (uint32 i=0; iFind("DebugService"); - if (serviceRef.IsValid()) { - service = dynamic_cast(serviceRef.operator->()); - } + if (service == NULL_PTR(DebugService*)) service = DebugService::Instance(); if (service && (copyTable != NULL_PTR(MemoryMapBrokerCopyTableEntry*))) { StreamString dsPath; @@ -75,21 +71,19 @@ public: for (uint32 i = 0; i < numCopies; i++) { void *addr = copyTable[i].dataSourcePointer; TypeDescriptor type = copyTable[i].type; - uint32 dsIdx = i; - if (mmb != NULL_PTR(MemoryMapBroker*)) { - dsIdx = mmb->GetDSCopySignalIndex(i); - } + if (mmb != NULL_PTR(MemoryMapBroker*)) dsIdx = mmb->GetDSCopySignalIndex(i); StreamString signalName; - if (!dataSourceIn.GetSignalName(dsIdx, signalName)) signalName = "Unknown"; + if (!dataSourceIn.GetSignalName(dsIdx, signalName)) { + signalName.Printf("Signal_%u", dsIdx); + } - // Register canonical name - StreamString dsFullName; - dsFullName.Printf("%s.%s", dsPath.Buffer(), signalName.Buffer()); + StreamString dsFullName = dsPath; + if (dsFullName.Size() > 0) dsFullName += "."; + dsFullName += signalName; service->RegisterSignal(addr, type, dsFullName.Buffer()); - // Register alias if (functionName != NULL_PTR(const char8*)) { StreamString gamFullName; const char8* dirStr = (direction == InputSignals) ? "In" : "Out"; @@ -97,207 +91,147 @@ public: if (gamRef.IsValid()) { StreamString absGamPath; DebugService::GetFullObjectName(*(gamRef.operator->()), absGamPath); - gamFullName.Printf("%s.%s.%s", absGamPath.Buffer(), dirStr, signalName.Buffer()); + gamFullName = absGamPath; } else { - gamFullName.Printf("%s.%s.%s", functionName, dirStr, signalName.Buffer()); + gamFullName = functionName; } + gamFullName += "."; + gamFullName += dirStr; + gamFullName += "."; + gamFullName += signalName; signalInfoPointers[i] = service->RegisterSignal(addr, type, gamFullName.Buffer()); } else { signalInfoPointers[i] = service->RegisterSignal(addr, type, dsFullName.Buffer()); } } - - // Register broker in DebugService for optimized control - service->RegisterBroker(signalInfoPointers, numCopies, mmb, anyActiveFlag, activeIndices, activeSizes, activeMutex); + service->RegisterBroker(signalInfoPointers, numCopies, mmb, anyActiveFlag); } } }; -/** - * @brief Template class to instrument any MARTe2 Broker. - */ -template -class DebugBrokerWrapper : public BaseClass { +class DebugMemoryMapInputBroker : public MemoryMapInputBroker, public DebugBrokerI { public: - DebugBrokerWrapper() : BaseClass() { - service = NULL_PTR(DebugService*); - signalInfoPointers = NULL_PTR(DebugSignalInfo**); - numSignals = 0; - anyActive = false; + DebugMemoryMapInputBroker() : MemoryMapInputBroker(), service(NULL), infoPtr(NULL), anyActive(false) { + (void)ObjectRegistryDatabase::Instance()->Insert(Reference(this)); } - - virtual ~DebugBrokerWrapper() { - if (signalInfoPointers) delete[] signalInfoPointers; - } - + virtual void SetService(DebugService* s) { service = s; } + virtual bool IsLinked() const { return infoPtr != NULL; } virtual bool Execute() { - bool ret = BaseClass::Execute(); - if (ret && (anyActive || (service && service->IsPaused()))) { - DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, activeSizes, activeMutex); - } + bool ret = MemoryMapInputBroker::Execute(); + if (ret && infoPtr) DebugBrokerHelper::Process(service, *infoPtr); return ret; } - virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem) { - bool ret = BaseClass::Init(direction, ds, name, gamMem); + bool ret = MemoryMapInputBroker::Init(direction, ds, name, gamMem); if (ret) { - numSignals = this->GetNumberOfCopies(); - DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction, &anyActive, &activeIndices, &activeSizes, &activeMutex); + DebugSignalInfo** sigPtrs = NULL; + DebugBrokerHelper::InitSignals(this, ds, service, sigPtrs, GetNumberOfCopies(), this->copyTable, name, direction, &anyActive); + if (service) infoPtr = service->GetBrokerInfo(service->numberOfBrokers - 1); } return ret; } - - virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem, const bool optim) { - bool ret = BaseClass::Init(direction, ds, name, gamMem, optim); - if (ret) { - numSignals = this->GetNumberOfCopies(); - DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction, &anyActive, &activeIndices, &activeSizes, &activeMutex); - } - return ret; - } - - DebugService *service; - DebugSignalInfo **signalInfoPointers; - uint32 numSignals; + DebugService* service; + BrokerInfo* infoPtr; volatile bool anyActive; - Vector activeIndices; - Vector activeSizes; - FastPollingMutexSem activeMutex; }; -template -class DebugBrokerWrapperNoOptim : public BaseClass { +template +class DebugGenericBroker : public T, public DebugBrokerI { public: - DebugBrokerWrapperNoOptim() : BaseClass() { - service = NULL_PTR(DebugService*); - signalInfoPointers = NULL_PTR(DebugSignalInfo**); - numSignals = 0; - anyActive = false; + DebugGenericBroker() : T(), service(NULL), infoPtr(NULL), anyActive(false) { + (void)ObjectRegistryDatabase::Instance()->Insert(Reference(this)); } - - virtual ~DebugBrokerWrapperNoOptim() { - if (signalInfoPointers) delete[] signalInfoPointers; - } - + virtual void SetService(DebugService* s) { service = s; } + virtual bool IsLinked() const { return infoPtr != NULL; } virtual bool Execute() { - bool ret = BaseClass::Execute(); - if (ret && (anyActive || (service && service->IsPaused()))) { - DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, activeSizes, activeMutex); - } + bool ret = T::Execute(); + if (ret && infoPtr) DebugBrokerHelper::Process(service, *infoPtr); return ret; } - virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem) { - bool ret = BaseClass::Init(direction, ds, name, gamMem); + bool ret = T::Init(direction, ds, name, gamMem); if (ret) { - numSignals = this->GetNumberOfCopies(); - DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction, &anyActive, &activeIndices, &activeSizes, &activeMutex); + DebugSignalInfo** sigPtrs = NULL; + DebugBrokerHelper::InitSignals(this, ds, service, sigPtrs, this->GetNumberOfCopies(), this->copyTable, name, direction, &anyActive); + if (service) infoPtr = service->GetBrokerInfo(service->numberOfBrokers - 1); } return ret; } - - DebugService *service; - DebugSignalInfo **signalInfoPointers; - uint32 numSignals; + DebugService* service; + BrokerInfo* infoPtr; volatile bool anyActive; - Vector activeIndices; - Vector activeSizes; - FastPollingMutexSem activeMutex; }; -class DebugMemoryMapAsyncOutputBroker : public MemoryMapAsyncOutputBroker { +class DebugMemoryMapAsyncOutputBroker : public MemoryMapAsyncOutputBroker, public DebugBrokerI { public: - DebugMemoryMapAsyncOutputBroker() : MemoryMapAsyncOutputBroker() { - service = NULL_PTR(DebugService*); - signalInfoPointers = NULL_PTR(DebugSignalInfo**); - numSignals = 0; - anyActive = false; - } - virtual ~DebugMemoryMapAsyncOutputBroker() { - if (signalInfoPointers) delete[] signalInfoPointers; + DebugMemoryMapAsyncOutputBroker() : MemoryMapAsyncOutputBroker(), service(NULL), infoPtr(NULL), anyActive(false) { + (void)ObjectRegistryDatabase::Instance()->Insert(Reference(this)); } + virtual void SetService(DebugService* s) { service = s; } + virtual bool IsLinked() const { return infoPtr != NULL; } virtual bool Execute() { bool ret = MemoryMapAsyncOutputBroker::Execute(); - if (ret && (anyActive || (service && service->IsPaused()))) { - DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, activeSizes, activeMutex); - } + if (ret && infoPtr) DebugBrokerHelper::Process(service, *infoPtr); return ret; } - virtual bool InitWithBufferParameters(const SignalDirection direction, DataSourceI &dataSourceIn, const char8 * const functionName, - void * const gamMemoryAddress, const uint32 numberOfBuffersIn, const ProcessorType& cpuMaskIn, const uint32 stackSizeIn) { - bool ret = MemoryMapAsyncOutputBroker::InitWithBufferParameters(direction, dataSourceIn, functionName, gamMemoryAddress, numberOfBuffersIn, cpuMaskIn, stackSizeIn); + virtual bool InitWithBufferParameters(const SignalDirection d, DataSourceI &ds, const char8* n, void* m, const uint32 nb, const ProcessorType& c, const uint32 s) { + bool ret = MemoryMapAsyncOutputBroker::InitWithBufferParameters(d, ds, n, m, nb, c, s); if (ret) { - numSignals = this->GetNumberOfCopies(); - DebugBrokerHelper::InitSignals(this, dataSourceIn, service, signalInfoPointers, numSignals, this->copyTable, functionName, direction, &anyActive, &activeIndices, &activeSizes, &activeMutex); + DebugSignalInfo** sigPtrs = NULL; + DebugBrokerHelper::InitSignals(this, ds, service, sigPtrs, this->GetNumberOfCopies(), this->copyTable, n, d, &anyActive); + if (service) infoPtr = service->GetBrokerInfo(service->numberOfBrokers - 1); } return ret; } - DebugService *service; - DebugSignalInfo **signalInfoPointers; - uint32 numSignals; + DebugService* service; + BrokerInfo* infoPtr; volatile bool anyActive; - Vector activeIndices; - Vector activeSizes; - FastPollingMutexSem activeMutex; }; -class DebugMemoryMapAsyncTriggerOutputBroker : public MemoryMapAsyncTriggerOutputBroker { +class DebugMemoryMapAsyncTriggerOutputBroker : public MemoryMapAsyncTriggerOutputBroker, public DebugBrokerI { public: - DebugMemoryMapAsyncTriggerOutputBroker() : MemoryMapAsyncTriggerOutputBroker() { - service = NULL_PTR(DebugService*); - signalInfoPointers = NULL_PTR(DebugSignalInfo**); - numSignals = 0; - anyActive = false; - } - virtual ~DebugMemoryMapAsyncTriggerOutputBroker() { - if (signalInfoPointers) delete[] signalInfoPointers; + DebugMemoryMapAsyncTriggerOutputBroker() : MemoryMapAsyncTriggerOutputBroker(), service(NULL), infoPtr(NULL), anyActive(false) { + (void)ObjectRegistryDatabase::Instance()->Insert(Reference(this)); } + virtual void SetService(DebugService* s) { service = s; } + virtual bool IsLinked() const { return infoPtr != NULL; } virtual bool Execute() { bool ret = MemoryMapAsyncTriggerOutputBroker::Execute(); - if (ret && (anyActive || (service && service->IsPaused()))) { - DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices, activeSizes, activeMutex); - } + if (ret && infoPtr) DebugBrokerHelper::Process(service, *infoPtr); return ret; } - virtual bool InitWithTriggerParameters(const SignalDirection direction, DataSourceI &dataSourceIn, const char8 * const functionName, - void * const gamMemoryAddress, const uint32 numberOfBuffersIn, const uint32 preTriggerBuffersIn, - const uint32 postTriggerBuffersIn, const ProcessorType& cpuMaskIn, const uint32 stackSizeIn) { - bool ret = MemoryMapAsyncTriggerOutputBroker::InitWithTriggerParameters(direction, dataSourceIn, functionName, gamMemoryAddress, numberOfBuffersIn, preTriggerBuffersIn, postTriggerBuffersIn, cpuMaskIn, stackSizeIn); + virtual bool InitWithTriggerParameters(const SignalDirection d, DataSourceI &ds, const char8* n, void* m, const uint32 nb, const uint32 pre, const uint32 post, const ProcessorType& c, const uint32 s) { + bool ret = MemoryMapAsyncTriggerOutputBroker::InitWithTriggerParameters(d, ds, n, m, nb, pre, post, c, s); if (ret) { - numSignals = this->GetNumberOfCopies(); - DebugBrokerHelper::InitSignals(this, dataSourceIn, service, signalInfoPointers, numSignals, this->copyTable, functionName, direction, &anyActive, &activeIndices, &activeSizes, &activeMutex); + DebugSignalInfo** sigPtrs = NULL; + DebugBrokerHelper::InitSignals(this, ds, service, sigPtrs, this->GetNumberOfCopies(), this->copyTable, n, d, &anyActive); + if (service) infoPtr = service->GetBrokerInfo(service->numberOfBrokers - 1); } return ret; } - DebugService *service; - DebugSignalInfo **signalInfoPointers; - uint32 numSignals; + DebugService* service; + BrokerInfo* infoPtr; volatile bool anyActive; - Vector activeIndices; - Vector activeSizes; - FastPollingMutexSem activeMutex; }; +typedef DebugGenericBroker DebugMemoryMapOutputBroker; +typedef DebugGenericBroker DebugMemoryMapSynchronisedInputBroker; +typedef DebugGenericBroker DebugMemoryMapSynchronisedOutputBroker; +typedef DebugGenericBroker DebugMemoryMapInterpolatedInputBroker; +typedef DebugGenericBroker DebugMemoryMapMultiBufferInputBroker; +typedef DebugGenericBroker DebugMemoryMapMultiBufferOutputBroker; +typedef DebugGenericBroker DebugMemoryMapSynchronisedMultiBufferInputBroker; +typedef DebugGenericBroker DebugMemoryMapSynchronisedMultiBufferOutputBroker; + template class DebugBrokerBuilder : public ObjectBuilder { public: - virtual Object *Build(HeapI* const heap) const { return new (heap) T(); } + virtual Object *Build(HeapI* const heap) const { + return new (heap) T(); + } }; -typedef DebugBrokerWrapper DebugMemoryMapInputBroker; -// LCOV_EXCL_START -typedef DebugBrokerWrapper DebugMemoryMapOutputBroker; -typedef DebugBrokerWrapper DebugMemoryMapSynchronisedInputBroker; -typedef DebugBrokerWrapper DebugMemoryMapSynchronisedOutputBroker; -typedef DebugBrokerWrapperNoOptim DebugMemoryMapInterpolatedInputBroker; -typedef DebugBrokerWrapper DebugMemoryMapMultiBufferInputBroker; -typedef DebugBrokerWrapper DebugMemoryMapMultiBufferOutputBroker; -typedef DebugBrokerWrapper DebugMemoryMapSynchronisedMultiBufferInputBroker; -typedef DebugBrokerWrapper DebugMemoryMapSynchronisedMultiBufferOutputBroker; -// LCOV_EXCL_STOP - typedef DebugBrokerBuilder DebugMemoryMapInputBrokerBuilder; -// LCOV_EXCL_START typedef DebugBrokerBuilder DebugMemoryMapOutputBrokerBuilder; typedef DebugBrokerBuilder DebugMemoryMapSynchronisedInputBrokerBuilder; typedef DebugBrokerBuilder DebugMemoryMapSynchronisedOutputBrokerBuilder; @@ -308,7 +242,6 @@ typedef DebugBrokerBuilder Deb typedef DebugBrokerBuilder DebugMemoryMapSynchronisedMultiBufferOutputBrokerBuilder; typedef DebugBrokerBuilder DebugMemoryMapAsyncOutputBrokerBuilder; typedef DebugBrokerBuilder DebugMemoryMapAsyncTriggerOutputBrokerBuilder; -// LCOV_EXCL_STOP } diff --git a/Headers/DebugService.h b/Headers/DebugService.h index d6300df..ac87d35 100644 --- a/Headers/DebugService.h +++ b/Headers/DebugService.h @@ -14,20 +14,44 @@ namespace MARTe { class MemoryMapBroker; +class DebugService; -struct SignalAlias { - StreamString name; - uint32 signalIndex; +/** + * @brief Interface for instrumented brokers to allow service adoption. + */ +class DebugBrokerI { +public: + virtual ~DebugBrokerI() {} + virtual void SetService(DebugService* service) = 0; + virtual bool IsLinked() const = 0; +}; + +struct SignalExecuteInfo { + void* memoryAddress; + void* forcedValue; + uint32 internalID; + uint32 size; +}; + +struct BrokerActiveSet { + SignalExecuteInfo* forcedSignals; + uint32 numForced; + SignalExecuteInfo* tracedSignals; + uint32 numTraced; }; struct BrokerInfo { DebugSignalInfo** signalPointers; uint32 numSignals; MemoryMapBroker* broker; + BrokerActiveSet sets[2]; + volatile uint32 currentSetIdx; volatile bool* anyActiveFlag; - Vector* activeIndices; - Vector* activeSizes; - FastPollingMutexSem* activeMutex; +}; + +struct SignalAlias { + StreamString name; + uint32 signalIndex; }; class DebugService : public ReferenceContainer, public MessageI, public EmbeddedServiceMethodBinderI { @@ -41,12 +65,23 @@ public: virtual bool Initialise(StructuredDataI & data); DebugSignalInfo* RegisterSignal(void* memoryAddress, TypeDescriptor type, const char8* name); + + static inline void CopySignal(void* dst, const void* src, const uint32 size) { + if (size == 4u) *static_cast(dst) = *static_cast(src); + else if (size == 8u) *static_cast(dst) = *static_cast(src); + else if (size == 1u) *static_cast(dst) = *static_cast(src); + else if (size == 2u) *static_cast(dst) = *static_cast(src); + else MemoryOperationsHelper::Copy(dst, src, size); + } + void ProcessSignal(DebugSignalInfo* signalInfo, uint32 size, uint64 timestamp); - void RegisterBroker(DebugSignalInfo** signalPointers, uint32 numSignals, MemoryMapBroker* broker, volatile bool* anyActiveFlag, Vector* activeIndices, Vector* activeSizes, FastPollingMutexSem* activeMutex); + void RegisterBroker(DebugSignalInfo** signalPointers, uint32 numSignals, MemoryMapBroker* broker, volatile bool* anyActiveFlag); virtual ErrorManagement::ErrorType Execute(ExecutionInfo & info); + static DebugService* Instance(); + bool IsPaused() const { return isPaused; } void SetPaused(bool paused) { isPaused = paused; } @@ -56,12 +91,32 @@ public: uint32 UnforceSignal(const char8* name); uint32 TraceSignal(const char8* name, bool enable, uint32 decimation = 1); void Discover(BasicTCPSocket *client); + void ListNodes(const char8* path, BasicTCPSocket *client); void InfoNode(const char8* path, BasicTCPSocket *client); + void UpdateBrokersActiveStatus(); + + BrokerInfo* GetBrokerInfo(uint32 index) { + if (index < numberOfBrokers) return &brokers[index]; + return NULL_PTR(BrokerInfo*); + } + + // PERFORMANCE-CRITICAL MEMBERS + static const uint32 MAX_BROKERS = 256; + BrokerInfo brokers[MAX_BROKERS]; + uint32 numberOfBrokers; + TraceRingBuffer traceBuffer; + + static const uint32 MAX_SIGNALS = 512; + DebugSignalInfo signals[MAX_SIGNALS]; + uint32 numberOfSignals; + + static const uint32 MAX_ALIASES = 1024; + SignalAlias aliases[MAX_ALIASES]; + uint32 numberOfAliases; + private: void HandleCommand(StreamString cmd, BasicTCPSocket *client); - void UpdateBrokersActiveStatus(); - uint32 ExportTree(ReferenceContainer *container, StreamString &json); void PatchRegistry(); @@ -100,28 +155,15 @@ private: ThreadIdentifier serverThreadId; ThreadIdentifier streamerThreadId; - static const uint32 MAX_SIGNALS = 4096; - DebugSignalInfo signals[MAX_SIGNALS]; - uint32 numberOfSignals; - - static const uint32 MAX_ALIASES = 8192; - SignalAlias aliases[MAX_ALIASES]; - uint32 numberOfAliases; - - static const uint32 MAX_BROKERS = 1024; - BrokerInfo brokers[MAX_BROKERS]; - uint32 numberOfBrokers; - FastPollingMutexSem mutex; - TraceRingBuffer traceBuffer; static const uint32 MAX_CLIENTS = 16; BasicTCPSocket* activeClients[MAX_CLIENTS]; FastPollingMutexSem clientsMutex; - - static DebugService* instance; }; +extern DebugService* GlobalDebugServiceInstance; + } #endif diff --git a/Source/DebugService.cpp b/Source/DebugService.cpp index 2024950..7b91ed1 100644 --- a/Source/DebugService.cpp +++ b/Source/DebugService.cpp @@ -10,23 +10,11 @@ #include "HighResolutionTimer.h" #include "ConfigurationDatabase.h" #include "GAM.h" - -// Explicitly include target brokers for templating -#include "MemoryMapInputBroker.h" -#include "MemoryMapOutputBroker.h" -#include "MemoryMapSynchronisedInputBroker.h" -#include "MemoryMapSynchronisedOutputBroker.h" -#include "MemoryMapInterpolatedInputBroker.h" -#include "MemoryMapMultiBufferInputBroker.h" -#include "MemoryMapMultiBufferOutputBroker.h" -#include "MemoryMapSynchronisedMultiBufferInputBroker.h" -#include "MemoryMapSynchronisedMultiBufferOutputBroker.h" -#include "MemoryMapAsyncOutputBroker.h" -#include "MemoryMapAsyncTriggerOutputBroker.h" +#include "Atomic.h" namespace MARTe { -DebugService* DebugService::instance = NULL_PTR(DebugService*); +DebugService* GlobalDebugServiceInstance = NULL_PTR(DebugService*); static void EscapeJson(const char8* src, StreamString &dst) { if (src == NULL_PTR(const char8*)) return; @@ -41,215 +29,12 @@ static void EscapeJson(const char8* src, StreamString &dst) { } } -CLASS_REGISTER(DebugService, "1.0") - -DebugService::DebugService() : - ReferenceContainer(), EmbeddedServiceMethodBinderI(), - binderServer(this, ServiceBinder::ServerType), - binderStreamer(this, ServiceBinder::StreamerType), - threadService(binderServer), - streamerService(binderStreamer) -{ - controlPort = 0; - streamPort = 8081; - streamIP = "127.0.0.1"; - numberOfSignals = 0; - numberOfAliases = 0; - numberOfBrokers = 0; - isServer = false; - suppressTimeoutLogs = true; - isPaused = false; - for (uint32 i=0; iClose(); - delete activeClients[i]; - } - } -} - -bool DebugService::Initialise(StructuredDataI & data) { - if (!ReferenceContainer::Initialise(data)) return false; - if (!data.Read("ControlPort", controlPort)) { - (void)data.Read("TcpPort", controlPort); - } - if (controlPort > 0) { - isServer = true; - instance = this; - } - if (!data.Read("StreamPort", streamPort)) { - (void)data.Read("UdpPort", streamPort); - } - StreamString tempIP; - if (data.Read("StreamIP", tempIP)) { - streamIP = tempIP; - } else { - streamIP = "127.0.0.1"; - } - uint32 suppress = 1; - if (data.Read("SuppressTimeoutLogs", suppress)) { - suppressTimeoutLogs = (suppress == 1); - } - if (isServer) { - if (!traceBuffer.Init(8 * 1024 * 1024)) return false; - PatchRegistry(); - ConfigurationDatabase threadData; - threadData.Write("Timeout", (uint32)1000); - threadService.Initialise(threadData); - streamerService.Initialise(threadData); - if (!tcpServer.Open()) return false; - if (!tcpServer.Listen(controlPort)) return false; - printf("[DebugService] TCP Server listening on port %u\n", controlPort); - if (!udpSocket.Open()) return false; - printf("[DebugService] UDP Streamer socket opened\n"); - if (threadService.Start() != ErrorManagement::NoError) return false; - if (streamerService.Start() != ErrorManagement::NoError) return false; - printf("[DebugService] Worker threads started.\n"); - } - return true; -} - -void PatchItemInternal(const char8* className, ObjectBuilder* builder) { - ClassRegistryDatabase *db = ClassRegistryDatabase::Instance(); - ClassRegistryItem *item = (ClassRegistryItem*)db->Find(className); - if (item != NULL_PTR(ClassRegistryItem*)) { - item->SetObjectBuilder(builder); - } -} - -void DebugService::PatchRegistry() { - DebugMemoryMapInputBrokerBuilder* b1 = new DebugMemoryMapInputBrokerBuilder(); PatchItemInternal("MemoryMapInputBroker", b1); - DebugMemoryMapOutputBrokerBuilder* b2 = new DebugMemoryMapOutputBrokerBuilder(); PatchItemInternal("MemoryMapOutputBroker", b2); - DebugMemoryMapSynchronisedInputBrokerBuilder* b3 = new DebugMemoryMapSynchronisedInputBrokerBuilder(); PatchItemInternal("MemoryMapSynchronisedInputBroker", b3); - DebugMemoryMapSynchronisedOutputBrokerBuilder* b4 = new DebugMemoryMapSynchronisedOutputBrokerBuilder(); PatchItemInternal("MemoryMapSynchronisedOutputBroker", b4); - DebugMemoryMapInterpolatedInputBrokerBuilder* b5 = new DebugMemoryMapInterpolatedInputBrokerBuilder(); PatchItemInternal("MemoryMapInterpolatedInputBroker", b5); - DebugMemoryMapMultiBufferInputBrokerBuilder* b6 = new DebugMemoryMapMultiBufferInputBrokerBuilder(); PatchItemInternal("MemoryMapMultiBufferInputBroker", b6); - DebugMemoryMapMultiBufferOutputBrokerBuilder* b7 = new DebugMemoryMapMultiBufferOutputBrokerBuilder(); PatchItemInternal("MemoryMapMultiBufferOutputBroker", b7); - DebugMemoryMapSynchronisedMultiBufferInputBrokerBuilder* b8 = new DebugMemoryMapSynchronisedMultiBufferInputBrokerBuilder(); PatchItemInternal("MemoryMapSynchronisedMultiBufferInputBroker", b8); - DebugMemoryMapSynchronisedMultiBufferOutputBrokerBuilder* b9 = new DebugMemoryMapSynchronisedMultiBufferOutputBrokerBuilder(); PatchItemInternal("MemoryMapSynchronisedMultiBufferOutputBroker", b9); - DebugMemoryMapAsyncOutputBrokerBuilder* b10 = new DebugMemoryMapAsyncOutputBrokerBuilder(); PatchItemInternal("MemoryMapAsyncOutputBroker", b10); - DebugMemoryMapAsyncTriggerOutputBrokerBuilder* b11 = new DebugMemoryMapAsyncTriggerOutputBrokerBuilder(); PatchItemInternal("MemoryMapAsyncTriggerOutputBroker", b11); -} - -void DebugService::ProcessSignal(DebugSignalInfo* s, uint32 size, uint64 timestamp) { - if (s != NULL_PTR(DebugSignalInfo*)) { - if (s->isForcing) { - MemoryOperationsHelper::Copy(s->memoryAddress, s->forcedValue, size); - } - if (s->isTracing) { - if (s->decimationFactor <= 1) { - (void)traceBuffer.Push(s->internalID, timestamp, s->memoryAddress, size); - } - else { - if (s->decimationCounter == 0) { - (void)traceBuffer.Push(s->internalID, timestamp, s->memoryAddress, size); - s->decimationCounter = s->decimationFactor - 1; - } - else { - s->decimationCounter--; - } - } - } - } -} - -void DebugService::RegisterBroker(DebugSignalInfo** signalPointers, uint32 numSignals, MemoryMapBroker* broker, volatile bool* anyActiveFlag, Vector* activeIndices, Vector* activeSizes, FastPollingMutexSem* activeMutex) { - mutex.FastLock(); - if (numberOfBrokers < MAX_BROKERS) { - brokers[numberOfBrokers].signalPointers = signalPointers; - brokers[numberOfBrokers].numSignals = numSignals; - brokers[numberOfBrokers].broker = broker; - brokers[numberOfBrokers].anyActiveFlag = anyActiveFlag; - brokers[numberOfBrokers].activeIndices = activeIndices; - brokers[numberOfBrokers].activeSizes = activeSizes; - brokers[numberOfBrokers].activeMutex = activeMutex; - numberOfBrokers++; - } - mutex.FastUnLock(); -} - -void DebugService::UpdateBrokersActiveStatus() { - // Already locked by caller (TraceSignal, ForceSignal, etc.) - for (uint32 i = 0; i < numberOfBrokers; i++) { - uint32 count = 0; - for (uint32 j = 0; j < brokers[i].numSignals; j++) { - DebugSignalInfo *s = brokers[i].signalPointers[j]; - if (s != NULL_PTR(DebugSignalInfo*) && (s->isTracing || s->isForcing)) { - count++; - } - } - - Vector tempInd(count); - Vector tempSizes(count); - uint32 idx = 0; - for (uint32 j = 0; j < brokers[i].numSignals; j++) { - DebugSignalInfo *s = brokers[i].signalPointers[j]; - if (s != NULL_PTR(DebugSignalInfo*) && (s->isTracing || s->isForcing)) { - tempInd[idx] = j; - tempSizes[idx] = (brokers[i].broker != NULL_PTR(MemoryMapBroker*)) ? brokers[i].broker->GetCopyByteSize(j) : 4; - idx++; - } - } - - if (brokers[i].activeMutex) brokers[i].activeMutex->FastLock(); - - if (brokers[i].activeIndices) *(brokers[i].activeIndices) = tempInd; - if (brokers[i].activeSizes) *(brokers[i].activeSizes) = tempSizes; - if (brokers[i].anyActiveFlag) *(brokers[i].anyActiveFlag) = (count > 0); - - if (brokers[i].activeMutex) brokers[i].activeMutex->FastUnLock(); - } -} - -DebugSignalInfo* DebugService::RegisterSignal(void* memoryAddress, TypeDescriptor type, const char8* name) { - mutex.FastLock(); - DebugSignalInfo* res = NULL_PTR(DebugSignalInfo*); - uint32 sigIdx = 0xFFFFFFFF; - for(uint32 i=0; imemoryAddress = memoryAddress; - res->type = type; - res->name = name; - res->isTracing = false; - res->isForcing = false; - res->internalID = numberOfSignals; - res->decimationFactor = 1; - res->decimationCounter = 0; - numberOfSignals++; - } - if (sigIdx != 0xFFFFFFFF && numberOfAliases < MAX_ALIASES) { - bool foundAlias = false; - for (uint32 i=0; i tLen) return false; + const char8* suffix = target + (tLen - pLen); + if (StringHelper::Compare(suffix, pattern) == 0) { if (tLen == pLen || *(suffix - 1) == '.') return true; } + return false; } static bool RecursiveGetFullObjectName(ReferenceContainer *container, const Object &obj, StreamString &path) { @@ -276,6 +61,55 @@ bool DebugService::GetFullObjectName(const Object &obj, StreamString &fullPath) return false; } +CLASS_REGISTER(DebugService, "1.0") + +DebugService* DebugService::Instance() { + return GlobalDebugServiceInstance; +} + +void PatchItemInternal(const char8* className, ObjectBuilder* builder) { + ClassRegistryDatabase *db = ClassRegistryDatabase::Instance(); + ClassRegistryItem *item = (ClassRegistryItem*)db->Find(className); + if (item != NULL_PTR(ClassRegistryItem*)) { + item->SetObjectBuilder(builder); + } +} + +uint32 DebugService::ForceSignal(const char8* name, const char8* valueStr) { + mutex.FastLock(); uint32 count = 0; + for (uint32 i = 0; i < numberOfAliases; i++) { + if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { + DebugSignalInfo &s = signals[aliases[i].signalIndex]; s.isForcing = true; + AnyType dest(s.type, 0u, s.forcedValue); AnyType source(CharString, 0u, valueStr); (void)TypeConvert(dest, source); + count++; + } + } + mutex.FastUnLock(); return count; +} + +uint32 DebugService::UnforceSignal(const char8* name) { + mutex.FastLock(); uint32 count = 0; + for (uint32 i = 0; i < numberOfAliases; i++) { + if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { signals[aliases[i].signalIndex].isForcing = false; count++; } + } + mutex.FastUnLock(); return count; +} + +uint32 DebugService::TraceSignal(const char8* name, bool enable, uint32 decimation) { + mutex.FastLock(); uint32 count = 0; + for (uint32 i = 0; i < numberOfAliases; i++) { + if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { + uint32 sigIdx = aliases[i].signalIndex; + DebugSignalInfo &s = signals[sigIdx]; + s.isTracing = enable; + s.decimationFactor = decimation; + s.decimationCounter = 0; + count++; + } + } + mutex.FastUnLock(); return count; +} + ErrorManagement::ErrorType DebugService::Execute(ExecutionInfo & info) { return ErrorManagement::FatalError; } @@ -284,10 +118,9 @@ ErrorManagement::ErrorType DebugService::Server(ExecutionInfo & info) { if (info.GetStage() == ExecutionInfo::TerminationStage) return ErrorManagement::NoError; if (info.GetStage() == ExecutionInfo::StartupStage) { serverThreadId = Threads::Id(); return ErrorManagement::NoError; } while (info.GetStage() == ExecutionInfo::MainStage) { - BasicTCPSocket *newClient = tcpServer.WaitConnection(1); + BasicTCPSocket *newClient = tcpServer.WaitConnection(10); if (newClient != NULL_PTR(BasicTCPSocket *)) { - clientsMutex.FastLock(); - bool added = false; + clientsMutex.FastLock(); bool added = false; for (uint32 i=0; iClose(); delete newClient; } @@ -341,12 +174,222 @@ ErrorManagement::ErrorType DebugService::Streamer(ExecutionInfo & info) { return ErrorManagement::NoError; } -static bool SuffixMatch(const char8* target, const char8* pattern) { - uint32 tLen = StringHelper::Length(target); uint32 pLen = StringHelper::Length(pattern); - if (pLen > tLen) return false; - const char8* suffix = target + (tLen - pLen); - if (StringHelper::Compare(suffix, pattern) == 0) { if (tLen == pLen || *(suffix - 1) == '.') return true; } - return false; +DebugService::DebugService() : + ReferenceContainer(), EmbeddedServiceMethodBinderI(), + binderServer(this, ServiceBinder::ServerType), + binderStreamer(this, ServiceBinder::StreamerType), + threadService(binderServer), + streamerService(binderStreamer) +{ + GlobalDebugServiceInstance = this; + controlPort = 0; + streamPort = 8081; + streamIP = "127.0.0.1"; + numberOfSignals = 0; + numberOfAliases = 0; + numberOfBrokers = 0; + isServer = false; + suppressTimeoutLogs = true; + isPaused = false; + for (uint32 i=0; i B1; PatchItemInternal("MemoryMapInputBroker", new B1()); + typedef DebugBrokerBuilder B2; PatchItemInternal("MemoryMapOutputBroker", new B2()); + + typedef DebugBrokerBuilder B3; PatchItemInternal("MemoryMapSynchronisedInputBroker", new B3()); + typedef DebugBrokerBuilder B4; PatchItemInternal("MemoryMapSynchronisedOutputBroker", new B4()); + + typedef DebugBrokerBuilder B5; PatchItemInternal("MemoryMapInterpolatedInputBroker", new B5()); +} + +DebugService::~DebugService() { + if (GlobalDebugServiceInstance == this) GlobalDebugServiceInstance = NULL_PTR(DebugService*); + threadService.Stop(); streamerService.Stop(); + tcpServer.Close(); udpSocket.Close(); + for (uint32 i=0; iClose(); delete activeClients[i]; } + } + for (uint32 i=0; i 0) { isServer = true; GlobalDebugServiceInstance = this; } + if (!data.Read("StreamPort", streamPort)) (void)data.Read("UdpPort", streamPort); + StreamString tempIP; if (data.Read("StreamIP", tempIP)) streamIP = tempIP; else streamIP = "127.0.0.1"; + uint32 suppress = 1; if (data.Read("SuppressTimeoutLogs", suppress)) suppressTimeoutLogs = (suppress == 1); + + if (isServer) { + if (!traceBuffer.Init(8 * 1024 * 1024)) return false; + ConfigurationDatabase threadData; threadData.Write("Timeout", (uint32)1000); + threadService.Initialise(threadData); streamerService.Initialise(threadData); + if (!tcpServer.Open()) return false; + if (!tcpServer.Listen(controlPort)) return false; + printf("[DebugService] TCP Server listening on port %u\n", controlPort); + if (!udpSocket.Open()) return false; + printf("[DebugService] UDP Streamer socket opened\n"); + if (threadService.Start() != ErrorManagement::NoError) return false; + if (streamerService.Start() != ErrorManagement::NoError) return false; + printf("[DebugService] Worker threads started.\n"); + } + return true; +} + +void DebugService::PatchRegistry() { +} + +void DebugService::ProcessSignal(DebugSignalInfo* s, uint32 size, uint64 timestamp) { + if (s == NULL_PTR(DebugSignalInfo*)) return; + if (s->isForcing) CopySignal(s->memoryAddress, s->forcedValue, size); + if (s->isTracing) { + if (s->decimationFactor <= 1) (void)traceBuffer.Push(s->internalID, timestamp, s->memoryAddress, size); + else { + if (s->decimationCounter == 0) { (void)traceBuffer.Push(s->internalID, timestamp, s->memoryAddress, size); s->decimationCounter = s->decimationFactor - 1; } + else s->decimationCounter--; + } + } +} + +void DebugService::RegisterBroker(DebugSignalInfo** signalPointers, uint32 numSignals, MemoryMapBroker* broker, volatile bool* anyActiveFlag) { + mutex.FastLock(); + for (uint32 i=0; iSize(); i++) { + Reference child = container->Get(i); + if (child.IsValid()) { + DebugBrokerI* b = dynamic_cast(child.operator->()); + if (b && !b->IsLinked()) { + b->SetService(service); + } + ReferenceContainer *inner = dynamic_cast(child.operator->()); + if (inner) AdoptOrphans(inner, service); + } + } +} + +void DebugService::UpdateBrokersActiveStatus() { + AdoptOrphans(ObjectRegistryDatabase::Instance(), this); + for (uint32 i = 0; i < numberOfBrokers; i++) { + uint32 nextIdx = (brokers[i].currentSetIdx + 1) % 2; + BrokerActiveSet& nextSet = brokers[i].sets[nextIdx]; + uint32 forcedCount = 0; uint32 tracedCount = 0; + for (uint32 j = 0; j < brokers[i].numSignals; j++) { + DebugSignalInfo *s = brokers[i].signalPointers[j]; + if (s != NULL_PTR(DebugSignalInfo*)) { + if (s->isForcing) forcedCount++; + if (s->isTracing) tracedCount++; + } + } + SignalExecuteInfo* newForced = (forcedCount > 0) ? new SignalExecuteInfo[forcedCount] : NULL_PTR(SignalExecuteInfo*); + SignalExecuteInfo* newTraced = (tracedCount > 0) ? new SignalExecuteInfo[tracedCount] : NULL_PTR(SignalExecuteInfo*); + uint32 fIdx = 0; uint32 tIdx = 0; + for (uint32 j = 0; j < brokers[i].numSignals; j++) { + DebugSignalInfo *s = brokers[i].signalPointers[j]; + if (s != NULL_PTR(DebugSignalInfo*)) { + uint32 size = (brokers[i].broker != NULL_PTR(MemoryMapBroker*)) ? brokers[i].broker->GetCopyByteSize(j) : 4; + if (s->isForcing) { newForced[fIdx].memoryAddress = s->memoryAddress; newForced[fIdx].forcedValue = s->forcedValue; newForced[fIdx].size = size; fIdx++; } + if (s->isTracing) { newTraced[tIdx].memoryAddress = s->memoryAddress; newTraced[tIdx].internalID = s->internalID; newTraced[tIdx].size = size; tIdx++; } + } + } + SignalExecuteInfo* oldForced = nextSet.forcedSignals; SignalExecuteInfo* oldTraced = nextSet.tracedSignals; + nextSet.forcedSignals = newForced; nextSet.tracedSignals = newTraced; nextSet.numForced = forcedCount; nextSet.numTraced = tracedCount; + Atomic::Exchange((int32*)&brokers[i].currentSetIdx, (int32)nextIdx); + if (brokers[i].anyActiveFlag) *(brokers[i].anyActiveFlag) = (forcedCount > 0 || tracedCount > 0); + if (oldForced) delete[] oldForced; if (oldTraced) delete[] oldTraced; + } +} + +DebugSignalInfo* DebugService::RegisterSignal(void* memoryAddress, TypeDescriptor type, const char8* name) { + mutex.FastLock(); + DebugSignalInfo* res = NULL_PTR(DebugSignalInfo*); uint32 sigIdx = 0xFFFFFFFF; + for (uint32 i=0; imemoryAddress == NULL && memoryAddress != NULL) res->memoryAddress = memoryAddress; + break; + } + } + if (res == NULL_PTR(DebugSignalInfo*) && numberOfSignals < MAX_SIGNALS) { + sigIdx = numberOfSignals; res = &signals[numberOfSignals]; + res->memoryAddress = memoryAddress; res->type = type; res->name = name; + res->isTracing = false; res->isForcing = false; res->internalID = numberOfSignals; + res->decimationFactor = 1; res->decimationCounter = 0; numberOfSignals++; + } + if (sigIdx != 0xFFFFFFFF && numberOfAliases < MAX_ALIASES) { + bool foundAlias = false; + for (uint32 i=0; iSize(); i++) { + Reference child = container->Get(i); + if (child.IsValid()) { + DataSourceI *ds = dynamic_cast(child.operator->()); + if (ds) { + StreamString dsPath; + if (DebugService::GetFullObjectName(*ds, dsPath)) { + for (uint32 j=0; jGetNumberOfSignals(); j++) { + StreamString sname; (void)ds->GetSignalName(j, sname); + StreamString fullName = dsPath; fullName += "."; fullName += sname; + service->RegisterSignal(NULL, ds->GetSignalType(j), fullName.Buffer()); + } + } + } + ReferenceContainer *inner = dynamic_cast(child.operator->()); + if (inner) RecursivePopulate(inner, service); + } + } +} + +void DebugService::Discover(BasicTCPSocket *client) { + if (client) { + RecursivePopulate(ObjectRegistryDatabase::Instance(), this); + StreamString json; json = "{\n \"Signals\": [\n"; + mutex.FastLock(); + for (uint32 i = 0; i < numberOfAliases; i++) { + DebugSignalInfo &sig = signals[aliases[i].signalIndex]; + const char8* typeName = TypeDescriptor::GetTypeNameFromTypeDescriptor(sig.type); + StreamString line; + line.Printf(" {\"name\": \"%s\", \"id\": %u, \"type\": \"%s\", \"ready\": %s}", + aliases[i].name.Buffer(), sig.internalID, typeName ? typeName : "Unknown", (sig.memoryAddress != NULL) ? "true" : "false"); + json += line; if (i < numberOfAliases - 1) json += ","; json += "\n"; + } + mutex.FastUnLock(); + json += " ]\n}\nOK DISCOVER\n"; uint32 s = json.Size(); (void)client->Write(json.Buffer(), s); + } } void DebugService::HandleCommand(StreamString cmd, BasicTCPSocket *client) { @@ -388,6 +431,7 @@ void DebugService::HandleCommand(StreamString cmd, BasicTCPSocket *client) { else if (token == "LS") { StreamString path; if (cmd.GetToken(path, delims, term)) ListNodes(path.Buffer(), client); else ListNodes(NULL_PTR(const char8*), client); } + UpdateBrokersActiveStatus(); } } @@ -471,65 +515,4 @@ uint32 DebugService::ExportTree(ReferenceContainer *container, StreamString &jso return validCount; } -uint32 DebugService::ForceSignal(const char8* name, const char8* valueStr) { - mutex.FastLock(); uint32 count = 0; - for (uint32 i = 0; i < numberOfAliases; i++) { - if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { - DebugSignalInfo &s = signals[aliases[i].signalIndex]; s.isForcing = true; - AnyType dest(s.type, 0u, s.forcedValue); AnyType source(CharString, 0u, valueStr); (void)TypeConvert(dest, source); - count++; - } - } - UpdateBrokersActiveStatus(); - mutex.FastUnLock(); return count; -} - -uint32 DebugService::UnforceSignal(const char8* name) { - mutex.FastLock(); uint32 count = 0; - for (uint32 i = 0; i < numberOfAliases; i++) { - if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { signals[aliases[i].signalIndex].isForcing = false; count++; } - } - UpdateBrokersActiveStatus(); - mutex.FastUnLock(); return count; -} - -uint32 DebugService::TraceSignal(const char8* name, bool enable, uint32 decimation) { - mutex.FastLock(); uint32 count = 0; - for (uint32 i = 0; i < numberOfAliases; i++) { - if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { - DebugSignalInfo &s = signals[aliases[i].signalIndex]; s.isTracing = enable; s.decimationFactor = decimation; s.decimationCounter = 0; count++; - printf("[Debug] Tracing state for %s (ID: %u) set to %d\n", aliases[i].name.Buffer(), s.internalID, enable); - } - } - UpdateBrokersActiveStatus(); - mutex.FastUnLock(); return count; -} - -void DebugService::Discover(BasicTCPSocket *client) { - if (client) { - StreamString header = "{\n \"Signals\": [\n"; uint32 s = header.Size(); (void)client->Write(header.Buffer(), s); - mutex.FastLock(); - for (uint32 i = 0; i < numberOfAliases; i++) { - StreamString line; DebugSignalInfo &sig = signals[aliases[i].signalIndex]; - const char8* typeName = TypeDescriptor::GetTypeNameFromTypeDescriptor(sig.type); - line.Printf(" {\"name\": \"%s\", \"id\": %d, \"type\": \"%s\"}", aliases[i].name.Buffer(), sig.internalID, typeName ? typeName : "Unknown"); - if (i < numberOfAliases - 1) line += ","; - line += "\n"; s = line.Size(); (void)client->Write(line.Buffer(), s); - } - mutex.FastUnLock(); - StreamString footer = " ]\n}\nOK DISCOVER\n"; s = footer.Size(); (void)client->Write(footer.Buffer(), s); - } -} - -void DebugService::ListNodes(const char8* path, BasicTCPSocket *client) { - if (!client) return; - Reference ref = (path == NULL_PTR(const char8*) || StringHelper::Length(path) == 0 || StringHelper::Compare(path, "/") == 0) ? ObjectRegistryDatabase::Instance() : ObjectRegistryDatabase::Instance()->Find(path); - if (ref.IsValid()) { - StreamString out; out.Printf("Nodes under %s:\n", path ? path : "/"); - ReferenceContainer *container = dynamic_cast(ref.operator->()); - if (container) { for (uint32 i=0; iSize(); i++) { Reference child = container->Get(i); if (child.IsValid()) out.Printf(" %s [%s]\n", child->GetName(), child->GetClassProperties()->GetName()); } } - const char* okMsg = "OK LS\n"; out += okMsg; uint32 s = out.Size(); (void)client->Write(out.Buffer(), s); - } else { const char* msg = "ERROR: Path not found\n"; uint32 s = StringHelper::Length(msg); (void)client->Write(msg, s); } -} - } diff --git a/Test/Configurations/debug_test.cfg b/Test/Configurations/debug_test.cfg index 037d627..7cf92db 100644 --- a/Test/Configurations/debug_test.cfg +++ b/Test/Configurations/debug_test.cfg @@ -1,3 +1,19 @@ ++DebugService = { + Class = DebugService + ControlPort = 8080 + UdpPort = 8081 + StreamIP = "127.0.0.1" +} + ++LoggerService = { + Class = LoggerService + CPUs = 0x1 + +DebugConsumer = { + Class = TcpLogger + Port = 8082 + } +} + +App = { Class = RealTimeApplication +Functions = { @@ -120,19 +136,3 @@ TimingDataSource = DAMS } } - -+DebugService = { - Class = DebugService - ControlPort = 8080 - UdpPort = 8081 - StreamIP = "127.0.0.1" -} - -+LoggerService = { - Class = LoggerService - CPUs = 0x1 - +DebugConsumer = { - Class = TcpLogger - Port = 8082 - } -} diff --git a/Test/Integration/BrokerExecuteTest.cpp b/Test/Integration/BrokerExecuteTest.cpp new file mode 100644 index 0000000..a0ed99d --- /dev/null +++ b/Test/Integration/BrokerExecuteTest.cpp @@ -0,0 +1,109 @@ +#include "DebugService.h" +#include "DebugBrokerWrapper.h" +#include "MemoryMapInputBroker.h" +#include "ObjectRegistryDatabase.h" +#include "StandardParser.h" +#include +#include + +using namespace MARTe; + +namespace MARTe { + +class ManualDebugMemoryMapInputBroker : public DebugMemoryMapInputBroker { +public: + virtual bool Execute() { + if (infoPtr) DebugBrokerHelper::Process(service, *infoPtr); + return true; + } + using MemoryMapBroker::copyTable; +}; + +class MockDS : public DataSourceI { +public: + CLASS_REGISTER_DECLARATION() + MockDS() { SetName("MockDS"); } + virtual bool AllocateMemory() { return true; } + virtual uint32 GetNumberOfMemoryBuffers() { return 1; } + virtual bool GetSignalMemoryBuffer(const uint32 signalIdx, const uint32 bufferIdx, void *&signalAddress) { + static uint32 val = 0; + signalAddress = &val; + return true; + } + virtual const char8 *GetBrokerName(StructuredDataI &data, const SignalDirection direction) { return "MemoryMapInputBroker"; } + virtual bool GetInputBrokers(ReferenceContainer &inputBrokers, const char8 *const functionName, void *const gamMem) { return true; } + virtual bool GetOutputBrokers(ReferenceContainer &outputBrokers, const char8 *const functionName, void *const gamMem) { return true; } + virtual bool PrepareNextState(const char8 *const currentStateName, const char8 *const nextStateName) { return true; } + virtual bool Synchronise() { return true; } +}; +CLASS_REGISTER(MockDS, "1.0") + +void RunTest() { + printf("--- Broker Execute Path Test (Isolated) ---\n"); + + DebugService* service = new DebugService(); + service->traceBuffer.Init(1024 * 1024); + ConfigurationDatabase cfg; + cfg.Write("ControlPort", (uint32)0); + cfg.Write("StreamPort", (uint32)0); + assert(service->Initialise(cfg)); + + ObjectRegistryDatabase::Instance()->Insert(Reference(service)); + + MockDS ds; + uint32 gamMem = 42; + + ManualDebugMemoryMapInputBroker* broker = new ManualDebugMemoryMapInputBroker(); + broker->service = service; + + printf("Manually bootstrapping Broker for testing...\n"); + broker->copyTable = new MemoryMapBrokerCopyTableEntry[1]; + broker->copyTable[0].copySize = 4; + broker->copyTable[0].dataSourcePointer = &gamMem; + broker->copyTable[0].gamPointer = &gamMem; + broker->copyTable[0].type = UnsignedInteger32Bit; + + DebugSignalInfo** sigPtrs = NULL; + DebugBrokerHelper::InitSignals(NULL_PTR(BrokerI*), ds, service, sigPtrs, 1, broker->copyTable, "TestGAM", InputSignals, &broker->anyActive); + broker->infoPtr = &service->brokers[service->numberOfBrokers - 1]; + + printf("Broker ready. Registered signals in service: %u\n", service->numberOfSignals); + + printf("Executing IDLE cycle...\n"); + broker->Execute(); + assert(service->traceBuffer.Count() == 0); + + printf("Manually enabling TRACE for first signal...\n"); + // Directly enable tracing on the signal info to bypass name matching + service->signals[0].isTracing = true; + service->signals[0].decimationFactor = 1; + service->signals[0].decimationCounter = 0; + + printf("Updating brokers active status...\n"); + service->UpdateBrokersActiveStatus(); + assert(broker->anyActive == true); + + printf("Executing TRACE cycle...\n"); + broker->Execute(); + + uint32 rbCount = service->traceBuffer.Count(); + printf("Trace Buffer Count: %u\n", rbCount); + + if (rbCount > 0) { + printf("SUCCESS: Data reached Trace Buffer via Broker!\n"); + uint32 rid, rsize; uint64 rts; uint32 rval; + assert(service->traceBuffer.Pop(rid, rts, &rval, rsize, 4)); + printf("Value popped: %u (ID=%u, TS=%lu)\n", rval, rid, rts); + assert(rval == 42); + } else { + printf("FAILURE: Trace Buffer is still empty.\n"); + } + + ObjectRegistryDatabase::Instance()->Purge(); +} +} + +int main() { + MARTe::RunTest(); + return 0; +} diff --git a/Test/Integration/CMakeLists.txt b/Test/Integration/CMakeLists.txt index a702770..efcf054 100644 --- a/Test/Integration/CMakeLists.txt +++ b/Test/Integration/CMakeLists.txt @@ -9,3 +9,12 @@ target_link_libraries(ValidationTest marte_dev ${MARTe2_LIB} ${IOGAM_LIB} ${Linu add_executable(SchedulerTest SchedulerTest.cpp) target_link_libraries(SchedulerTest marte_dev ${MARTe2_LIB} ${IOGAM_LIB} ${LinuxTimer_LIB}) + +add_executable(PerformanceTest PerformanceTest.cpp) +target_link_libraries(PerformanceTest marte_dev ${MARTe2_LIB}) + +add_executable(BrokerExecuteTest BrokerExecuteTest.cpp) +target_link_libraries(BrokerExecuteTest marte_dev ${MARTe2_LIB}) + +add_executable(FinalValidationTest FinalValidationTest.cpp) +target_link_libraries(FinalValidationTest marte_dev ${MARTe2_LIB} ${IOGAM_LIB} ${LinuxTimer_LIB} ${LoggerDataSource_LIB}) diff --git a/Test/Integration/FinalValidationTest.cpp b/Test/Integration/FinalValidationTest.cpp new file mode 100644 index 0000000..19087ea --- /dev/null +++ b/Test/Integration/FinalValidationTest.cpp @@ -0,0 +1,217 @@ +#include "DebugService.h" +#include "DebugCore.h" +#include "ObjectRegistryDatabase.h" +#include "StandardParser.h" +#include "RealTimeApplication.h" +#include "GlobalObjectsDatabase.h" +#include "BasicUDPSocket.h" +#include "BasicTCPSocket.h" +#include "HighResolutionTimer.h" +#include +#include + +using namespace MARTe; + +void RunFinalValidation() { + printf("--- MARTe2 Debug Final Validation (End-to-End) ---\n"); + + ObjectRegistryDatabase::Instance()->Purge(); + + // 1. Initialise DebugService FIRST + const char8 * const service_cfg = + "+DebugService = {" + " Class = DebugService " + " ControlPort = 8080 " + " UdpPort = 8081 " + " StreamIP = \"127.0.0.1\" " + "}"; + + StreamString ssSrv = service_cfg; + ssSrv.Seek(0); + ConfigurationDatabase cdbSrv; + StandardParser parserSrv(ssSrv, cdbSrv); + assert(parserSrv.Parse()); + + cdbSrv.MoveToRoot(); + if (cdbSrv.MoveRelative("+DebugService")) { + ConfigurationDatabase child; + cdbSrv.Copy(child); + cdbSrv.MoveToAncestor(1u); + Reference ref("DebugService", GlobalObjectsDatabase::Instance()->GetStandardHeap()); + ref->SetName("DebugService"); + if (!ref->Initialise(child)) { + printf("ERROR: Failed to initialise DebugService\n"); + return; + } + ObjectRegistryDatabase::Instance()->Insert(ref); + printf("[Init] DebugService started.\n"); + } + + // 2. Minimal App configuration + const char8 * const minimal_app_cfg = + "+App = {" + " Class = RealTimeApplication " + " +Functions = {" + " Class = ReferenceContainer " + " +GAM1 = {" + " Class = IOGAM " + " InputSignals = {" + " Counter = { DataSource = Timer Type = uint32 Frequency = 1000 }" + " }" + " OutputSignals = {" + " Counter = { DataSource = DDB Type = uint32 }" + " }" + " }" + " }" + " +Data = {" + " Class = ReferenceContainer " + " DefaultDataSource = DDB " + " +Timer = { Class = LinuxTimer SleepTime = 1000 Signals = { +Counter = { Type = uint32 } } }" + " +DDB = { Class = GAMDataSource Signals = { +Counter = { Type = uint32 } } }" + " +DAMS = { Class = TimingDataSource }" + " }" + " +States = {" + " Class = ReferenceContainer " + " +State1 = { Class = RealTimeState +Threads = { Class = ReferenceContainer +Thread1 = { Class = RealTimeThread Functions = {GAM1} } } }" + " }" + " +Scheduler = { Class = GAMScheduler TimingDataSource = DAMS }" + "}"; + + StreamString ssApp = minimal_app_cfg; + ssApp.Seek(0); + ConfigurationDatabase cdbApp; + StandardParser parserApp(ssApp, cdbApp); + assert(parserApp.Parse()); + + cdbApp.MoveToRoot(); + if (cdbApp.MoveRelative("+App")) { + ConfigurationDatabase child; + cdbApp.Copy(child); + cdbApp.MoveToAncestor(1u); + Reference ref("RealTimeApplication", GlobalObjectsDatabase::Instance()->GetStandardHeap()); + ref->SetName("App"); + if (ref->Initialise(child)) { + ObjectRegistryDatabase::Instance()->Insert(ref); + printf("[Init] App object created.\n"); + } else { + printf("ERROR: Failed to initialise App object.\n"); + return; + } + } + + Reference appRef = ObjectRegistryDatabase::Instance()->Find("App"); + RealTimeApplication* app = dynamic_cast(appRef.operator->()); + + // 3. Start Application + printf("Configuring Application...\n"); + if (!app->ConfigureApplication()) { + printf("ERROR: ConfigureApplication failed.\n"); + return; + } + printf("Preparing State1...\n"); + if (app->PrepareNextState("State1") != ErrorManagement::NoError) { + printf("ERROR: Failed to prepare State1.\n"); + return; + } + printf("Starting State1 Execution...\n"); + if (app->StartNextStateExecution() != ErrorManagement::NoError) { + printf("ERROR: Failed to start State1 execution.\n"); + return; + } + + printf("Application running. Starting client simulation...\n"); + Sleep::MSec(1000); + + // 4. Act as Client: Send Commands + BasicTCPSocket client; + if (client.Connect("127.0.0.1", 8080, TimeoutType(2000))) { + printf("[Client] Connected to DebugService.\n"); + + // Command 1: TREE + printf("[Client] Sending TREE...\n"); + uint32 cmdLen = 5; + client.Write("TREE\n", cmdLen); + char buf[4096]; uint32 rsize = 4096; + if (client.Read(buf, rsize, TimeoutType(1000))) { + printf("[Client] TREE response received (%u bytes).\n", rsize); + } + + // Command 2: DISCOVER + printf("[Client] Sending DISCOVER...\n"); + cmdLen = 9; + client.Write("DISCOVER\n", cmdLen); + rsize = 4096; + if (client.Read(buf, rsize, TimeoutType(1000))) { + buf[rsize] = '\0'; + printf("[Client] DISCOVER response:\n%s\n", buf); + } + + // Command 3: TRACE + const char* target = "App.Data.Timer.Counter"; + printf("[Client] Sending TRACE %s 1...\n", target); + StreamString traceCmd; + traceCmd.Printf("TRACE %s 1\n", target); + cmdLen = traceCmd.Size(); + client.Write(traceCmd.Buffer(), cmdLen); + + rsize = 1024; + if (client.Read(buf, rsize, TimeoutType(1000))) { + buf[rsize] = '\0'; + printf("[Client] TRACE response: %s", buf); + } + client.Close(); + } else { + printf("ERROR: Client failed to connect to 127.0.0.1:8080\n"); + } + + // 5. Verify Telemetry + BasicUDPSocket telemListener; + assert(telemListener.Open()); + assert(telemListener.Listen(8081)); + + printf("Listening for UDP Telemetry on 8081...\n"); + uint32 totalSamples = 0; + uint64 startBench = HighResolutionTimer::Counter(); + + while (totalSamples < 50 && (HighResolutionTimer::Counter() - startBench) * HighResolutionTimer::Period() < 10.0) { + char packet[4096]; + uint32 psize = 4096; + if (telemListener.Read(packet, psize, TimeoutType(100))) { + if (psize < 20) continue; + uint32 magic = *(uint32*)(&packet[0]); + if (magic != 0xDA7A57AD) continue; + + uint32 count = *(uint32*)(&packet[16]); + uint32 offset = 20; + for (uint32 j=0; j psize) break; + uint32 id = *(uint32*)(&packet[offset]); + uint64 ts = *(uint64*)(&packet[offset + 4]); + uint32 size = *(uint32*)(&packet[offset + 12]); + offset += 16; + if (offset + size > psize) break; + if (size == 4) { + uint32 val = *(uint32*)(&packet[offset]); + if (totalSamples % 10 == 0) printf("[Telemetry] Sample %u: ID=%u, TS=%lu, Val=%u\n", totalSamples, id, ts, val); + totalSamples++; + } + offset += size; + } + } + } + + if (totalSamples >= 50) { + printf("\nSUCCESS: End-to-End pipeline verified with real MARTe2 app!\n"); + } else { + printf("\nFAILURE: Received only %u samples in 10 seconds.\n", totalSamples); + } + + app->StopCurrentStateExecution(); + telemListener.Close(); + ObjectRegistryDatabase::Instance()->Purge(); +} + +int main() { + RunFinalValidation(); + return 0; +} diff --git a/Test/Integration/PerformanceTest.cpp b/Test/Integration/PerformanceTest.cpp new file mode 100644 index 0000000..92d7863 --- /dev/null +++ b/Test/Integration/PerformanceTest.cpp @@ -0,0 +1,109 @@ +#include "DebugService.h" +#include "DebugBrokerWrapper.h" +#include "MemoryMapInputBroker.h" +#include "HighResolutionTimer.h" +#include "ObjectRegistryDatabase.h" +#include "StandardParser.h" +#include +#include + +using namespace MARTe; + +namespace MARTe { +void RunBenchmark() { + printf("--- MARTe2 Debug Performance Benchmark V5 (Wait-Free/Branchless) ---\n"); + printf("Testing with 100 signals, 1,000,000 cycles per test.\n\n"); + + const uint32 NUM_SIGNALS = 100; + const uint32 NUM_CYCLES = 1000000; + + DebugService* service = new DebugService(); + service->traceBuffer.Init(128 * 1024 * 1024); + ConfigurationDatabase cfg; + cfg.Write("ControlPort", (uint32)0); + cfg.Write("StreamPort", (uint32)0); + assert(service->Initialise(cfg)); + + volatile uint32 srcMem[NUM_SIGNALS]; + volatile uint32 dstMem[NUM_SIGNALS]; + for(uint32 i=0; iRegisterSignal((void*)&srcMem[i], UnsignedInteger32Bit, name.Buffer()); + } + volatile bool anyActiveFlag = false; + service->RegisterBroker(ptrs, NUM_SIGNALS, NULL_PTR(MemoryMapBroker*), &anyActiveFlag); + debugBroker.infoPtr = &service->brokers[service->numberOfBrokers - 1]; + service->UpdateBrokersActiveStatus(); + assert(anyActiveFlag == false); + + printf("2. Debug Idle (Wait-Free Skip): "); + start = HighResolutionTimer::Counter(); + for(uint32 c=0; cIsPaused()) { + DebugBrokerHelper::Process(service, *debugBroker.infoPtr); + } + } + end = HighResolutionTimer::Counter(); + float64 idleTime = (float64)(end - start) * HighResolutionTimer::Period(); + float64 idleNs = (idleTime / NUM_CYCLES) * 1e9; + printf("%.3f ms (avg: %.3f ns) | Delta: +%.3f ns\n", + idleTime * 1000.0, idleNs, idleNs - baselineNs); + + for(uint32 i=0; isignals[i].isTracing = true; + } + service->UpdateBrokersActiveStatus(); + assert(anyActiveFlag == true); + + printf("3. Debug Load (100 signals branchless): "); + start = HighResolutionTimer::Counter(); + for(uint32 c=0; cIsPaused()) { + DebugBrokerHelper::Process(service, *debugBroker.infoPtr); + } + if ((c % 1000) == 0) { + uint32 tid, tsize; uint64 tts; uint8 tbuf[16]; + while(service->traceBuffer.Pop(tid, tts, tbuf, tsize, 16)); + } + } + end = HighResolutionTimer::Counter(); + float64 loadTime = (float64)(end - start) * HighResolutionTimer::Period(); + float64 loadNs = (loadTime / NUM_CYCLES) * 1e9; + printf("%.3f ms (avg: %.3f ns) | Delta: +%.3f ns (+%.3f ns/signal)\n", + loadTime * 1000.0, loadNs, loadNs - baselineNs, (loadNs - baselineNs)/NUM_SIGNALS); + + printf("\nBenchmark complete.\n"); + + delete[] ptrs; + delete service; +} +} + +int main() { + MARTe::RunBenchmark(); + return 0; +} diff --git a/Test/UnitTests/main.cpp b/Test/UnitTests/main.cpp index dcfec7e..857e3bd 100644 --- a/Test/UnitTests/main.cpp +++ b/Test/UnitTests/main.cpp @@ -51,18 +51,15 @@ public: service.HandleCommand("RESUME", NULL_PTR(BasicTCPSocket*)); service.HandleCommand("LS /", NULL_PTR(BasicTCPSocket*)); - // 3. Broker Active Status + // 3. Broker Active Status (Wait-Free) volatile bool active = false; - Vector indices; - Vector sizes; - FastPollingMutexSem mutex; DebugSignalInfo* ptrs[1] = { &service.signals[0] }; - service.RegisterBroker(ptrs, 1, NULL_PTR(MemoryMapBroker*), &active, &indices, &sizes, &mutex); + service.RegisterBroker(ptrs, 1, NULL_PTR(MemoryMapBroker*), &active); service.UpdateBrokersActiveStatus(); assert(active == true); // Helper Process - DebugBrokerHelper::Process(&service, ptrs, indices, sizes, mutex); + DebugBrokerHelper::Process(&service, service.brokers[0]); // 4. Object Hierarchy branches service.HandleCommand("INFO X.Y.Z", NULL_PTR(BasicTCPSocket*)); @@ -98,7 +95,6 @@ void TestRingBuffer() { int main(int argc, char **argv) { printf("--- MARTe2 Debug Suite COVERAGE V29 ---\n"); MARTe::TestTcpLogger(); - // MARTe::TestRingBuffer(); // Fixed previously, but let's keep it clean MARTe::DebugServiceTest::TestAll(); printf("\nCOVERAGE V29 PASSED!\n"); return 0; diff --git a/Tools/gui_client/src/main.rs b/Tools/gui_client/src/main.rs index 3bd1d3a..bf7c737 100644 --- a/Tools/gui_client/src/main.rs +++ b/Tools/gui_client/src/main.rs @@ -342,7 +342,7 @@ fn tcp_command_worker(shared_config: Arc>, rx_cmd: Recei let trimmed = line.trim(); if trimmed.is_empty() { line.clear(); continue; } - if !in_json && trimmed.starts_with("{") { in_json = true; json_acc.clear(); } + if !in_json && (trimmed.starts_with("{") || trimmed.starts_with("[")) { in_json = true; json_acc.clear(); } if in_json { json_acc.push_str(trimmed); @@ -439,6 +439,7 @@ fn udp_worker(shared_config: Arc>, id_to_meta: Arc = None; let mut last_seq: Option = None; let mut last_warning_time = std::time::Instant::now(); + let mut first_packet = true; loop { let (ver, port) = { let config = shared_config.lock().unwrap(); (config.version, config.udp_port.clone()) }; @@ -460,6 +461,7 @@ fn udp_worker(shared_config: Arc>, id_to_meta: Arc>, id_to_meta: Arc last { let _ = tx_events.send(InternalEvent::UdpDropped(seq - last - 1)); } } last_seq = Some(seq); @@ -482,7 +489,7 @@ fn udp_worker(shared_config: Arc>, id_to_meta: Arc 0 && last_warning_time.elapsed().as_secs() > 5 { - let _ = tx_events.send(InternalEvent::InternalLog("UDP received but Metadata empty. Still discovering?".to_string())); + let _ = tx_events.send(InternalEvent::InternalLog(format!("UDP received but Metadata empty ({} known). Still discovering?", metas.len()))); last_warning_time = std::time::Instant::now(); } @@ -497,24 +504,43 @@ fn udp_worker(shared_config: Arc>, id_to_meta: Arc base { ts_raw - base } else { base - ts_raw }; + if diff > 100_000_000 { + *base_ts_guard = Some(ts_raw); + let _ = tx_events.send(InternalEvent::InternalLog("Clock reset detected. Syncing base.".to_string())); + } + } + if base_ts_guard.is_none() { *base_ts_guard = Some(ts_raw); } let base = base_ts_guard.unwrap(); let ts_s = if ts_raw >= base { (ts_raw - base) as f64 / 1000000.0 } else { - 0.0 // Avoid huge jitter wrap-around + 0.0 }; drop(base_ts_guard); if let Some(meta) = metas.get(&id) { let _ = tx_events.send(InternalEvent::TelemMatched(id)); - let t = meta.sig_type.as_str(); + let t = meta.sig_type.to_lowercase(); let val = match size { 1 => { if t.contains('u') { data_slice[0] as f64 } else { (data_slice[0] as i8) as f64 } }, 2 => { let b = data_slice[0..2].try_into().unwrap(); if t.contains('u') { u16::from_le_bytes(b) as f64 } else { i16::from_le_bytes(b) as f64 } }, - 4 => { let b = data_slice[0..4].try_into().unwrap(); if t.contains("float") { f32::from_le_bytes(b) as f64 } else if t.contains('u') { u32::from_le_bytes(b) as f64 } else { i32::from_le_bytes(b) as f64 } }, - 8 => { let b = data_slice[0..8].try_into().unwrap(); if t.contains("float") { f64::from_le_bytes(b) } else if t.contains('u') { u64::from_le_bytes(b) as f64 } else { i64::from_le_bytes(b) as f64 } }, + 4 => { + let b = data_slice[0..4].try_into().unwrap(); + if t.contains("float") || (t.contains("32") && (t.contains('f') || t.contains("real"))) { f32::from_le_bytes(b) as f64 } + else if t.contains('u') { u32::from_le_bytes(b) as f64 } + else { i32::from_le_bytes(b) as f64 } + }, + 8 => { + let b = data_slice[0..8].try_into().unwrap(); + if t.contains("float") || t.contains("double") || (t.contains("64") && (t.contains('f') || t.contains("real"))) { f64::from_le_bytes(b) } + else if t.contains('u') { u64::from_le_bytes(b) as f64 } + else { i64::from_le_bytes(b) as f64 } + }, _ => 0.0, }; for name in &meta.names { @@ -702,6 +728,16 @@ impl eframe::App for MarteDebugApp { } }); ui.separator(); + ui.heading("Telemetry Stats"); + let mut ids: Vec<_> = self.telem_match_count.keys().cloned().collect(); + ids.sort(); + if ids.is_empty() { ui.label("No IDs matched yet."); } + for id in ids { + if let Some(count) = self.telem_match_count.get(&id) { + ui.label(format!("ID {}: {} samples", id, count)); + } + } + ui.separator(); ui.heading("Forced Signals"); for (path, val) in &self.forced_signals { ui.horizontal(|ui| { ui.label(format!("{}: {}", path, val)); if ui.button("❌").clicked() { let _ = self.tx_cmd.send(format!("UNFORCE {}", path)); } }); } }); diff --git a/Tools/pipeline_validator/Cargo.lock b/Tools/pipeline_validator/Cargo.lock new file mode 100644 index 0000000..52e612d --- /dev/null +++ b/Tools/pipeline_validator/Cargo.lock @@ -0,0 +1,431 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "pipeline_validator" +version = "0.1.0" +dependencies = [ + "chrono", + "serde", + "serde_json", + "socket2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wasm-bindgen" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Tools/pipeline_validator/Cargo.toml b/Tools/pipeline_validator/Cargo.toml new file mode 100644 index 0000000..a67fabf --- /dev/null +++ b/Tools/pipeline_validator/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "pipeline_validator" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +socket2 = "0.5" +chrono = "0.4" diff --git a/Tools/pipeline_validator/src/main.rs b/Tools/pipeline_validator/src/main.rs new file mode 100644 index 0000000..ac20ec0 --- /dev/null +++ b/Tools/pipeline_validator/src/main.rs @@ -0,0 +1,135 @@ +use std::io::{Read, Write}; +use std::net::{TcpStream, UdpSocket}; +use std::time::{Duration, Instant}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Signal { + name: String, + id: u32, + #[serde(rename = "type")] + sig_type: String, + ready: bool, +} + +#[derive(Deserialize, Debug)] +struct DiscoverResponse { + #[serde(rename = "Signals")] + signals: Vec, +} + +fn main() { + println!("--- MARTe2 Debug Pipeline Validator ---"); + + // 1. Connect to TCP Control Port + let mut stream = match TcpStream::connect("127.0.0.1:8080") { + Ok(s) => { + println!("[TCP] Connected to DebugService on 8080"); + s + } + Err(e) => { + println!("[TCP] FAILED to connect: {}", e); + println!("Check if 'run_debug_app.sh' is running."); + return; + } + }; + stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap(); + + // 2. DISCOVER signals + println!("[TCP] Sending DISCOVER..."); + stream.write_all(b"DISCOVER\n").unwrap(); + + let mut buf = [0u8; 8192]; + let n = stream.read(&mut buf).unwrap(); + let resp = String::from_utf8_lossy(&buf[..n]); + + // Split JSON from OK DISCOVER terminator + let json_part = resp.split("OK DISCOVER").next().unwrap_or("").trim(); + let discovery: DiscoverResponse = match serde_json::from_str(json_part) { + Ok(d) => d, + Err(e) => { + println!("[TCP] Discovery Parse Error: {}", e); + println!("Raw Response: {}", resp); + return; + } + }; + + println!("[TCP] Found {} signals.", discovery.signals.len()); + let mut counter_id = None; + for s in &discovery.signals { + println!("[TCP] Signal: {} (ID={}, Ready={})", s.name, s.id, s.ready); + if s.name.contains("Timer.Counter") { + println!("[TCP] Target found: {} (ID={})", s.name, s.id); + counter_id = Some(s.id); + + // 3. Enable TRACE + println!("[TCP] Enabling TRACE for {}...", s.name); + stream.write_all(format!("TRACE {} 1\n", s.name).as_bytes()).unwrap(); + let mut t_buf = [0u8; 1024]; + let tn = stream.read(&mut t_buf).unwrap(); + println!("[TCP] TRACE Response: {}", String::from_utf8_lossy(&t_buf[..tn]).trim()); + } + } + + if counter_id.is_none() { + println!("[TCP] ERROR: Counter signal not found in discovery."); + return; + } + + // 4. Listen for UDP Telemetry + let socket = UdpSocket::bind("0.0.0.0:8081").expect("Could not bind UDP socket"); + socket.set_read_timeout(Some(Duration::from_secs(5))).unwrap(); + println!("[UDP] Listening for telemetry on 8081..."); + + let mut samples_received = 0; + let mut last_val: Option = None; + let mut last_ts: Option = None; + let start_wait = Instant::now(); + + while samples_received < 20 && start_wait.elapsed().as_secs() < 10 { + let mut u_buf = [0u8; 4096]; + if let Ok(n) = socket.recv(&mut u_buf) { + if n < 20 { continue; } + + // Validate Header + let magic = u32::from_le_bytes(u_buf[0..4].try_into().unwrap()); + if magic != 0xDA7A57AD { continue; } + + let count = u32::from_le_bytes(u_buf[16..20].try_into().unwrap()); + let mut offset = 20; + + for _ in 0..count { + if offset + 16 > n { break; } + let id = u32::from_le_bytes(u_buf[offset..offset+4].try_into().unwrap()); + let ts = u64::from_le_bytes(u_buf[offset+4..offset+12].try_into().unwrap()); + let size = u32::from_le_bytes(u_buf[offset+12..offset+16].try_into().unwrap()); + offset += 16; + + if offset + size as usize > n { break; } + + if id == counter_id.unwrap() && size == 4 { + let val = u32::from_le_bytes(u_buf[offset..offset+4].try_into().unwrap()); + println!("[UDP] Match! ID={} TS={} VAL={}", id, ts, val); + + if let Some(lt) = last_ts { + if ts <= lt { println!("[UDP] WARNING: Non-monotonic timestamp!"); } + } + if let Some(lv) = last_val { + if val == lv { println!("[UDP] WARNING: Stale value detected."); } + } + + last_ts = Some(ts); + last_val = Some(val); + samples_received += 1; + } + offset += size as usize; + } + } + } + + if samples_received >= 20 { + println!("\n[RESULT] SUCCESS: Telemetry pipeline is fully functional!"); + } else { + println!("\n[RESULT] FAILURE: Received only {} samples.", samples_received); + } +} diff --git a/app_output.log b/app_output.log index d924cc4..cdff580 100644 --- a/app_output.log +++ b/app_output.log @@ -17,17 +17,6 @@ Filename = "Test/Configurations/debug_ [Information - Loader.cpp:74]: SchedulerGranularity is 10000 [Debug - Loader.cpp:189]: Purging ObjectRegistryDatabase with 0 objects [Debug - Loader.cpp:192]: Purge ObjectRegistryDatabase. Number of objects left: 0 -[Information - LinuxTimer.cpp:117]: SleepNature was not set. Using Default. -[Information - LinuxTimer.cpp:127]: Phase was not configured, using default 0 -[Warning - LinuxTimer.cpp:164]: ExecutionMode not specified using: IndependentThread -[Warning - LinuxTimer.cpp:185]: CPUMask not specified using: 255 -[Warning - LinuxTimer.cpp:191]: StackSize not specified using: 262144 -[Information - LinuxTimer.cpp:236]: No timer provider specified. Falling back to HighResolutionTimeProvider -[Information - HighResolutionTimeProvider.cpp:163]: Sleep nature was not specified, falling back to default (Sleep::NoMore mode) -[Information - HighResolutionTimeProvider.cpp:61]: Inner initialization succeeded -[Information - LinuxTimer.cpp:267]: Backward compatibility parameters injection unnecessary -[Information - RealTimeThread.cpp:190]: No CPUs defined for the RealTimeThread Thread1 -[Information - RealTimeThread.cpp:193]: No StackSize defined for the RealTimeThread Thread1 [DebugService] TCP Server listening on port 8080 [DebugService] UDP Streamer socket opened [ParametersError - StringHelper.cpp:60]: Error: invalid input arguments @@ -43,53 +32,90 @@ Filename = "Test/Configurations/debug_ [Warning - Threads.cpp:173]: Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. [Warning] Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. [Warning] Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. +[Information] SleepNature was not set. Using Default. +[Information] Phase was not configured, using default 0 +[Warning] ExecutionMode not specified using: IndependentThread +[Warning] CPUMask not specified using: 255 +[Warning] StackSize not specified using: 262144 +[Information] No timer provider specified. Falling back to HighResolutionTimeProvider +[Information] Sleep nature was not specified, falling back to default (Sleep::NoMore mode) +[Information] Inner initialization succeeded +[Information] Backward compatibility parameters injection unnecessary +[Information] SleepNature was not set. Using Default. +[Information] Phase was not configured, using default 0 +[Warning] ExecutionMode not specified using: IndependentThread +[Warning] CPUMask not specified using: 255 +[Warning] StackSize not specified using: 262144 +[Information] No timer provider specified. Falling back to HighResolutionTimeProvider +[Information] Sleep nature was not specified, falling back to default (Sleep::NoMore mode) +[Information] Inner initialization succeeded +[Information] Backward compatibility parameters injection unnecessary +[Information] No CPUs defined for the RealTimeThread Thread1 +[Information] No StackSize defined for the RealTimeThread Thread1 +[Information] No CPUs defined for the RealTimeThread Thread2 +[Information] No StackSize defined for the RealTimeThread Thread2 [Information] LoaderPostInit not set +[Debug] Finished updating the signal database [Information] Going to rtAppBuilder.ConfigureAfterInitialisation() [Information] Going to InitialiseSignalsDatabase +[Debug] Updating the signal database +[Debug] Finished updating the signal database [Information] Going to FlattenSignalsDatabases [Information] Caching introspection signals [Information] Flattening functions input signals [Debug] Updating the signal database [Debug] Finished updating the signal database +[Debug] Updating the signal database +[Debug] Updating the signal database +[Debug] Finished updating the signal database +[Debug] Finished updating the signal database [Information] Flattening functions output signals [Debug] Updating the signal database [Debug] Finished updating the signal database +[Debug] Updating the signal database +[Debug] Finished updating the signal database +[Debug] Updating the signal database +[Debug] Finished updating the signal database [Information] Flattening data sources signals [Debug] Updating the signal database [Debug] Finished updating the signal database [Debug] Updating the signal database -[Debug] Finished updating the signal database -[Debug] Updating the signal database -[Debug] Finished updating the signal database -[Information] Going to VerifyDataSourcesSignals -[Debug] Updating the signal database -[Information] Verifying signals for Timer -[Debug] Finished updating the signal database [Information] Going to ResolveStates [Information] Resolving state State1 [Information] Resolving thread container Threads [Information] Resolving thread State1.Thread1 [Information] Resolving GAM1 +[Information] Resolving thread State1.Thread2 +[Information] Resolving GAM2 [Information] Going to ResolveDataSources -[Information] Verifying signals for Logger [Information] Resolving for function GAM1 [idx: 0] [Information] Resolving 2 signals [Information] Resolving 2 signals +[Information] Resolving for function GAM2 [idx: 1] +[Information] Resolving 2 signals +[Information] Resolving 2 signals +[DebugBrokerBuilder] Built MemoryMapSynchronisedInputBroker +[DebugBrokerBuilder] Built MemoryMapInputBroker +[Information] Going to VerifyDataSourcesSignals +[Information] Verifying signals for Timer +[Information] Verifying signals for TimerSlow +[Information] Verifying signals for Logger [Information] Verifying signals for DDB [Information] Verifying signals for DAMS [Information] Going to VerifyConsumersAndProducers -[Information] Started application in state State1 -[Information] Application starting [Information] Verifying consumers and producers for Timer +[Information] Verifying consumers and producers for TimerSlow [Information] Verifying consumers and producers for Logger [Information] Verifying consumers and producers for DDB [Information] Verifying consumers and producers for DAMS [Information] Going to CleanCaches -[Debug] Purging dataSourcesIndexesCache. Number of children:3 -[Debug] Purging functionsIndexesCache. Number of children:1 -[Debug] Purging dataSourcesSignalIndexCache. Number of children:3 +[Information] Creating broker MemoryMapSynchronisedInputBroker for GAM2 and signal Counter(0) +[DebugBrokerBuilder] Built MemoryMapSynchronisedInputBroker +[Debug] Purging dataSourcesIndexesCache. Number of children:4 +[Debug] Purging functionsIndexesCache. Number of children:2 +[Debug] Purging dataSourcesSignalIndexCache. Number of children:4 [Debug] Purging dataSourcesFunctionIndexesCache. Number of children:1 -[Debug] Purging functionsMemoryIndexesCache. Number of children:2 +[Debug] Purging functionsMemoryIndexesCache. Number of children:1 [Debug] Purged functionsMemoryIndexesCache. Number of children:0 [Debug] Purged cachedIntrospections. Number of children:0 [Information] Going to rtAppBuilder.PostConfigureDataSources() @@ -102,6 +128,11 @@ Filename = "Test/Configurations/debug_ [Information] Creating broker MemoryMapInputBroker for GAM1 and signal Time(1) [Information] Getting input brokers for Timer [Information] Getting output brokers for Timer +[DebugBrokerBuilder] Built MemoryMapInputBroker +[DebugBrokerBuilder] Built MemoryMapOutputBroker +[Information] Creating broker MemoryMapInputBroker for GAM2 and signal Time(1) +[Information] Getting input brokers for TimerSlow +[Information] Getting output brokers for TimerSlow [Information] Getting input brokers for Logger [Information] Getting output brokers for Logger [Information] Getting input brokers for DDB @@ -111,40 +142,253 @@ Filename = "Test/Configurations/debug_ [Information] Going to FindStatefulDataSources [Information] Going to configure scheduler [Information] Preparing state State1 -[Information] Frequency found = 1.000000 -[Information] Frequency found = 1.000000 -[Information] The timer will be set using a frequency of 1.000000 Hz +[Information] Frequency found = 1000.000000 +[Information] Frequency found = 1000.000000 +[Information] The timer will be set using a frequency of 1000.000000 Hz +[ParametersError] Error: invalid input arguments +[Warning] Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. +[Warning] Failed to change the thread priority (likely due to insufficient permissions) +[Information] LinuxTimer::Prepared = true +[Information] Frequency found = 10.000000 +[Information] Frequency found = 10.000000 +[Information] The timer will be set using a frequency of 10.000000 Hz [ParametersError] Error: invalid input arguments [Warning] Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. [Warning] Failed to change the thread priority (likely due to insufficient permissions) [Information] LinuxTimer::Prepared = true [Warning] Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. [Warning] Failed to change the thread priority (likely due to insufficient permissions) +[Warning] Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy. +[Warning] Failed to change the thread priority (likely due to insufficient permissions) +[Information] Started application in state State1 +[Information] Application starting +[Information] Counter [0:0]:1 [Information] Time [0:0]:0 +[Information] Counter [0:0]:2 +[Information] Time [0:0]:200000 +[Information] Counter [0:0]:3 +[Information] Time [0:0]:300000 +[Information] Counter [0:0]:4 +[Information] Time [0:0]:400000 +[DebugService] Discover called. Instance: 0x7fd54d967010 +[DebugService] Found existing broker: GAM1.InputBroker.MemoryMapSynchronisedInputBroker (MemoryMapSynchronisedInputBroker) +[DebugService] Found existing broker: GAM1.InputBroker.MemoryMapInputBroker (MemoryMapInputBroker) +[DebugService] Found existing broker: GAM2.InputBroker.MemoryMapSynchronisedInputBroker (MemoryMapSynchronisedInputBroker) +[DebugService] Found existing broker: GAM2.InputBroker.MemoryMapInputBroker (MemoryMapInputBroker) +[DebugService] Found existing broker: (null) (MemoryMapOutputBroker) +[DebugService] Registry Scan: Current Signals=19, Brokers=0 +[Debug] Tracing state for App.Data.Timer.Counter (ID: 0, Mem: (nil)) set to 1 +[Debug] WARNING: Signal App.Data.Timer.Counter is NOT associated with any active broker! +[Information] Counter [0:0]:5 +[Information] Time [0:0]:500000 +[Information] Counter [0:0]:6 +[Information] Time [0:0]:600000 +[Information] Counter [0:0]:7 +[Information] Time [0:0]:700000 +[Information] Counter [0:0]:8 +[Information] Time [0:0]:800000 +[Information] Counter [0:0]:9 +[Information] Time [0:0]:900000 +[Information] Counter [0:0]:10 +[Information] Time [0:0]:1000000 +[Information] Counter [0:0]:11 +[Information] Time [0:0]:1100000 +[Information] Counter [0:0]:12 +[Information] Time [0:0]:1200000 +[Information] Counter [0:0]:13 +[Information] Time [0:0]:1300000 +[Information] Counter [0:0]:14 +[Information] Time [0:0]:1400000 +[Information] Counter [0:0]:15 +[Information] Time [0:0]:1500000 +[Information] Counter [0:0]:16 +[Information] Time [0:0]:1600000 +[Information] Counter [0:0]:17 +[Information] Time [0:0]:1700000 +[Information] Counter [0:0]:18 +[Information] Time [0:0]:1800000 +[Information] Counter [0:0]:19 +[Information] Time [0:0]:1900000 +[Information] Counter [0:0]:20 [Information] Time [0:0]:2000000 +[Information] Counter [0:0]:21 +[Information] Time [0:0]:2100000 +[Information] Counter [0:0]:22 +[Information] Time [0:0]:2200000 +[Information] Counter [0:0]:23 +[Information] Time [0:0]:2300000 +[Information] Counter [0:0]:24 +[Information] Time [0:0]:2400000 +[Information] Counter [0:0]:25 +[Information] Time [0:0]:2500000 +[Information] Counter [0:0]:26 +[Information] Time [0:0]:2600000 +[Information] Counter [0:0]:27 +[Information] Time [0:0]:2700000 +[Information] Counter [0:0]:28 +[Information] Time [0:0]:2800000 +[Information] Counter [0:0]:29 +[Information] Time [0:0]:2900000 +[Information] Counter [0:0]:30 [Information] Time [0:0]:3000000 +[Information] Counter [0:0]:31 +[Information] Time [0:0]:3100000 +[Information] Counter [0:0]:32 +[Information] Time [0:0]:3200000 +[Information] Counter [0:0]:33 +[Information] Time [0:0]:3300000 +[Information] Counter [0:0]:34 +[Information] Time [0:0]:3400000 +[Information] Counter [0:0]:35 +[Information] Time [0:0]:3500000 +[Information] Counter [0:0]:36 +[Information] Time [0:0]:3600000 +[Information] Counter [0:0]:37 +[Information] Time [0:0]:3700000 +[Information] Counter [0:0]:38 +[Information] Time [0:0]:3800000 +[Information] Counter [0:0]:39 +[Information] Time [0:0]:3900000 +[Information] Counter [0:0]:40 [Information] Time [0:0]:4000000 +[Information] Counter [0:0]:41 +[Information] Time [0:0]:4100000 +[Information] Counter [0:0]:42 +[Information] Time [0:0]:4200000 +[Information] Counter [0:0]:43 +[Information] Time [0:0]:4300000 +[Information] Counter [0:0]:44 +[Information] Time [0:0]:4400000 +[Information] Counter [0:0]:45 +[Information] Time [0:0]:4500000 +[Information] Counter [0:0]:46 +[Information] Time [0:0]:4600000 +[Information] Counter [0:0]:47 +[Information] Time [0:0]:4700000 +[Information] Counter [0:0]:48 +[Information] Time [0:0]:4800000 +[Information] Counter [0:0]:49 +[Information] Time [0:0]:4900000 +[Information] Counter [0:0]:50 [Information] Time [0:0]:5000000 +[Information] Counter [0:0]:51 +[Information] Time [0:0]:5100000 +[Information] Counter [0:0]:52 +[Information] Time [0:0]:5200000 +[Information] Counter [0:0]:53 +[Information] Time [0:0]:5300000 +[Information] Counter [0:0]:54 +[Information] Time [0:0]:5400000 +[Information] Counter [0:0]:55 +[Information] Time [0:0]:5500000 +[Information] Counter [0:0]:56 +[Information] Time [0:0]:5600000 +[Information] Counter [0:0]:57 +[Information] Time [0:0]:5700000 +[Information] Counter [0:0]:58 +[Information] Time [0:0]:5800000 +[Information] Counter [0:0]:59 +[Information] Time [0:0]:5900000 +[Information] Counter [0:0]:60 [Information] Time [0:0]:6000000 +[Information] Counter [0:0]:61 +[Information] Time [0:0]:6100000 +[Information] Counter [0:0]:62 +[Information] Time [0:0]:6200000 +[Information] Counter [0:0]:63 +[Information] Time [0:0]:6300000 +[Information] Counter [0:0]:64 +[Information] Time [0:0]:6400000 +[Information] Counter [0:0]:65 +[Information] Time [0:0]:6500000 +[Information] Counter [0:0]:66 +[Information] Time [0:0]:6600000 +[Information] Counter [0:0]:67 +[Information] Time [0:0]:6700000 +[Information] Counter [0:0]:68 +[Information] Time [0:0]:6800000 +[Information] Counter [0:0]:69 +[Information] Time [0:0]:6900000 +[Information] Counter [0:0]:70 [Information] Time [0:0]:7000000 +[Information] Counter [0:0]:71 +[Information] Time [0:0]:7100000 +[Information] Counter [0:0]:72 +[Information] Time [0:0]:7200000 +[Information] Counter [0:0]:73 +[Information] Time [0:0]:7300000 +[Information] Counter [0:0]:74 +[Information] Time [0:0]:7400000 +[Information] Counter [0:0]:75 +[Information] Time [0:0]:7500000 +[Information] Counter [0:0]:76 +[Information] Time [0:0]:7600000 +[Information] Counter [0:0]:77 +[Information] Time [0:0]:7700000 +[Information] Counter [0:0]:78 +[Information] Time [0:0]:7800000 +[Information] Counter [0:0]:79 +[Information] Time [0:0]:7900000 +[Information] Counter [0:0]:80 [Information] Time [0:0]:8000000 +[Information] Counter [0:0]:81 +[Information] Time [0:0]:8100000 +[Information] Counter [0:0]:82 +[Information] Time [0:0]:8200000 +[Information] Counter [0:0]:83 +[Information] Time [0:0]:8300000 +[Information] Counter [0:0]:84 +[Information] Time [0:0]:8400000 +[Information] Counter [0:0]:85 +[Information] Time [0:0]:8500000 +[Information] Counter [0:0]:86 +[Information] Time [0:0]:8600000 +[Information] Counter [0:0]:87 +[Information] Time [0:0]:8700000 +[Information] Counter [0:0]:88 +[Information] Time [0:0]:8800000 +[Information] Counter [0:0]:89 +[Information] Time [0:0]:8900000 +[Information] Counter [0:0]:90 [Information] Time [0:0]:9000000 +[Information] Counter [0:0]:91 +[Information] Time [0:0]:9100000 +[Information] Counter [0:0]:92 +[Information] Time [0:0]:9200000 +[Information] Counter [0:0]:93 +[Information] Time [0:0]:9300000 +[Information] Counter [0:0]:94 +[Information] Time [0:0]:9400000 +[Information] Counter [0:0]:95 +[Information] Time [0:0]:9500000 +[Information] Counter [0:0]:96 +[Information] Time [0:0]:9600000 +[Information] Counter [0:0]:97 +[Information] Time [0:0]:9700000 +[Information] Counter [0:0]:98 +[Information] Time [0:0]:9800000 +[Information] Counter [0:0]:99 +[Information] Time [0:0]:9900000 +[Information] Counter [0:0]:100 [Information] Time [0:0]:10000000 +[Information] Counter [0:0]:101 +[Information] Time [0:0]:10100000 +[Information] Counter [0:0]:102 +[Information] Time [0:0]:10200000 +[Information] Counter [0:0]:103 +[Information] Time [0:0]:10300000 +[Information] Counter [0:0]:104 +[Information] Time [0:0]:10400000 +[Information] Counter [0:0]:105 +[Information] Time [0:0]:10500000 +[Information] Counter [0:0]:106 +[Information] Time [0:0]:10600000 +[Information] Counter [0:0]:107 +[Information] Time [0:0]:10700000 +[Information] Counter [0:0]:108 +[Information] Time [0:0]:10800000 +[Information] Counter [0:0]:109 +[Information] Time [0:0]:10900000 +[Information] Counter [0:0]:110 [Information] Time [0:0]:11000000 -[Information] Time [0:0]:12000000 -[Information] Time [0:0]:13000000 -[Information] Time [0:0]:14000000 -[Information] Time [0:0]:15000000 -[Information] Time [0:0]:16000000 -[Information] Time [0:0]:17000000 -[Information] Time [0:0]:18000000 -[Information] Time [0:0]:19000000 -[Information] Time [0:0]:20000000 -[Information] Time [0:0]:21000000 -[Information] Time [0:0]:22000000 -[Information] Time [0:0]:23000000 -[Information] Time [0:0]:24000000 -[Information] Time [0:0]:25000000 -[Information] Time [0:0]:26000000 -[Information] Time [0:0]:27000000 -[Information] Time [0:0]:28000000 +./run_debug_app.sh: line 40: 325075 Killed "$MARTE_EX" -f Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1 diff --git a/run_coverage.sh b/run_coverage.sh new file mode 100755 index 0000000..2c18922 --- /dev/null +++ b/run_coverage.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Load environment +. ./env.sh + +# Clean build directory +rm -rf Build_Coverage + +# Build with coverage +mkdir -p Build_Coverage +cd Build_Coverage +cmake .. -DENABLE_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug +make -j$(nproc) + +# Reset coverage data +lcov --directory . --zerocounters + +# Run unit tests +./Test/UnitTests/UnitTests + +# Capture coverage data +lcov --directory . --capture --output-file coverage.info --ignore-errors inconsistent + +# Filter out system and MARTe2 internal headers +lcov --remove coverage.info '/usr/*' '*/dependency/*' '*/Test/*' --output-file coverage_filtered.info --ignore-errors inconsistent + +# Generate report +genhtml coverage_filtered.info --output-directory out --ignore-errors inconsistent + +# Display summary +lcov --list coverage_filtered.info --ignore-errors inconsistent diff --git a/run_debug_app.sh b/run_debug_app.sh index 03657ec..145c2aa 100755 --- a/run_debug_app.sh +++ b/run_debug_app.sh @@ -26,7 +26,7 @@ for dir in $ALL_COMPONENT_DIRS; do done # Ensure our build dir and core dir are included -export LD_LIBRARY_PATH="$(pwd)/Build:${MARTe2_DIR}/Build/${TARGET}/Core:${LD_LIBRARY_PATH}" +export LD_LIBRARY_PATH="$(pwd)/Build:${LD_LIBRARY_PATH}" # 3. Cleanup echo "Cleaning up lingering processes..." @@ -36,5 +36,5 @@ sleep 1 # 4. Launch Application echo "Launching standard MARTeApp.ex with debug_test.cfg..." # PRELOAD ensures our DebugService class is available to the registry early -export LD_PRELOAD="${DEBUG_LIB}" +export LD_PRELOAD="$(pwd)/Build/libmarte_dev.so" "$MARTE_EX" -f Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1