Optimised failed test

This commit is contained in:
Martino Ferrari
2026-02-25 21:07:27 +01:00
parent dfb399bbba
commit f8f04856ed
17 changed files with 1842 additions and 557 deletions

View File

@@ -0,0 +1,109 @@
#include "DebugService.h"
#include "DebugBrokerWrapper.h"
#include "MemoryMapInputBroker.h"
#include "ObjectRegistryDatabase.h"
#include "StandardParser.h"
#include <stdio.h>
#include <assert.h>
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;
}

View File

@@ -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})

View File

@@ -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 <stdio.h>
#include <assert.h>
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<RealTimeApplication*>(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<count; j++) {
if (offset + 16 > 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;
}

View File

@@ -0,0 +1,109 @@
#include "DebugService.h"
#include "DebugBrokerWrapper.h"
#include "MemoryMapInputBroker.h"
#include "HighResolutionTimer.h"
#include "ObjectRegistryDatabase.h"
#include "StandardParser.h"
#include <stdio.h>
#include <assert.h>
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; i<NUM_SIGNALS; i++) srcMem[i] = i;
printf("1. Baseline (Pure Copy): ");
uint64 start = HighResolutionTimer::Counter();
for(uint32 c=0; c<NUM_CYCLES; c++) {
for(uint32 i=0; i<NUM_SIGNALS; i++) {
dstMem[i] = srcMem[i];
}
}
uint64 end = HighResolutionTimer::Counter();
float64 baselineTime = (float64)(end - start) * HighResolutionTimer::Period();
float64 baselineNs = (baselineTime / NUM_CYCLES) * 1e9;
printf("%.3f ms (avg: %.3f ns)\n", baselineTime * 1000.0, baselineNs);
DebugMemoryMapInputBroker debugBroker;
debugBroker.service = service;
DebugSignalInfo** ptrs = new DebugSignalInfo*[NUM_SIGNALS];
for(uint32 i=0; i<NUM_SIGNALS; i++) {
StreamString name;
name = "Sig";
// Convert i to string without Printf
if (i < 10) { name += (char)('0' + i); }
else { name += (char)('0' + (i/10)); name += (char)('0' + (i%10)); }
ptrs[i] = service->RegisterSignal((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; c<NUM_CYCLES; c++) {
for(uint32 i=0; i<NUM_SIGNALS; i++) dstMem[i] = srcMem[i];
if (anyActiveFlag || service->IsPaused()) {
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; i<NUM_SIGNALS; i++) {
service->signals[i].isTracing = true;
}
service->UpdateBrokersActiveStatus();
assert(anyActiveFlag == true);
printf("3. Debug Load (100 signals branchless): ");
start = HighResolutionTimer::Counter();
for(uint32 c=0; c<NUM_CYCLES; c++) {
for(uint32 i=0; i<NUM_SIGNALS; i++) dstMem[i] = srcMem[i];
if (anyActiveFlag || service->IsPaused()) {
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;
}