Implemented qt port + e2e
This commit is contained in:
@@ -1,3 +1,138 @@
|
||||
../../../Build/x86-linux/Applications/StreamHub/BinaryRecorderGTest.o: BinaryRecorderGTest.cpp \
|
||||
../../../Source/Applications/StreamHub/BinaryRecorder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
../../../Common/UDP/UDPSProtocol.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-internal.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-port.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-message.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-string.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-filepath.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-death-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-param-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-param-util.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-printers.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest_prod.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-test-part.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-typed-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h
|
||||
../../../Build/x86-linux/Applications/StreamHub/BinaryRecorderSrc.o: BinaryRecorderSrc.cpp \
|
||||
../../../Source/Applications/StreamHub/BinaryRecorder.cpp \
|
||||
../../../Source/Applications/StreamHub/BinaryRecorder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
../../../Common/UDP/UDPSProtocol.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h
|
||||
../../../Build/x86-linux/Applications/StreamHub/LTTBGTest.o: LTTBGTest.cpp ../../../Source/Applications/StreamHub/LTTB.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
|
||||
@@ -1,3 +1,138 @@
|
||||
BinaryRecorderGTest.o: BinaryRecorderGTest.cpp \
|
||||
../../../Source/Applications/StreamHub/BinaryRecorder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
../../../Common/UDP/UDPSProtocol.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-internal.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-port.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-message.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-string.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-filepath.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-death-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-param-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-param-util.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-printers.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest_prod.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-test-part.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-typed-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h
|
||||
BinaryRecorderSrc.o: BinaryRecorderSrc.cpp \
|
||||
../../../Source/Applications/StreamHub/BinaryRecorder.cpp \
|
||||
../../../Source/Applications/StreamHub/BinaryRecorder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
../../../Common/UDP/UDPSProtocol.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h
|
||||
LTTBGTest.o: LTTBGTest.cpp ../../../Source/Applications/StreamHub/LTTB.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
|
||||
@@ -18,3 +18,182 @@
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-typed-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h \
|
||||
UDPStreamerTest.h
|
||||
../../../../Build/x86-linux/Components/DataSources/UDPStreamer/UDPStreamerTest.o: UDPStreamerTest.cpp \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicTCPSocket.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicSocket.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetHostCore.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetMulticastCore.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HandleI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/SocketCore.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyObject.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabaseNode.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Fnv1aHashFunction.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/HashFunction.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/UnorderedMap.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilterObjectName.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TypeConversion.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAM.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/DataSourceI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/StatefulI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/ExecutableI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs/GAMScheduler.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/EventSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAMSchedulerI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAM.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/TimingDataSource.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAMDataSource.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryArea.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/Message.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/MultiThreadService.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/RealTimeApplication.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSMETHODREGISTER.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassMethodInterfaceMapper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassMethodCaller.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassMethodCallerT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAMSchedulerI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/MessageI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/Message.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/MessageFilterPool.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/MessageFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/RealTimeApplicationConfigurationBuilder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/RealTimeApplication.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/RegisteredMethodsMessageFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectRegistryDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/StandardParser.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationParserI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyTypeCreator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/LexicalAnalyzer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/GrammarInfo.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/Token.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TokenInfo.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ParserI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/RuntimeEvaluator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticStack.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/VariableInformation.h \
|
||||
../../../../Source/Components/DataSources/UDPStreamer/UDPStreamer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/MemoryDataSourceI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
|
||||
../../../../Source/Components/Interfaces/UDPStream/UDPSServer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
|
||||
../../../../Common/UDP/UDPSProtocol.h UDPStreamerTest.h
|
||||
|
||||
@@ -18,3 +18,182 @@ UDPStreamerGTest.o: UDPStreamerGTest.cpp \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest-typed-test.h \
|
||||
/home/martino/workspace/MARTe2/Lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h \
|
||||
UDPStreamerTest.h
|
||||
UDPStreamerTest.o: UDPStreamerTest.cpp \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicTCPSocket.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicSocket.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetHostCore.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetMulticastCore.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HandleI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/SocketCore.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyObject.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabaseNode.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Fnv1aHashFunction.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/HashFunction.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/UnorderedMap.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilterObjectName.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TypeConversion.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAM.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/DataSourceI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/StatefulI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/ExecutableI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L5GAMs/GAMScheduler.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/EventSem.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAMSchedulerI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAM.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/TimingDataSource.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAMDataSource.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryArea.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/Message.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/MultiThreadService.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/RealTimeApplication.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSMETHODREGISTER.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassMethodInterfaceMapper.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassMethodCaller.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassMethodCallerT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/GAMSchedulerI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/MessageI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/Message.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/MessageFilterPool.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/MessageFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/RealTimeApplicationConfigurationBuilder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/RealTimeApplication.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Messages/RegisteredMethodsMessageFilter.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectRegistryDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/StandardParser.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationParserI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyTypeCreator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/LexicalAnalyzer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/GrammarInfo.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/Token.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TokenInfo.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ParserI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/RuntimeEvaluator.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticStack.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/VariableInformation.h \
|
||||
../../../../Source/Components/DataSources/UDPStreamer/UDPStreamer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/MemoryDataSourceI.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
|
||||
../../../../Source/Components/Interfaces/UDPStream/UDPSServer.h \
|
||||
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
|
||||
../../../../Common/UDP/UDPSProtocol.h UDPStreamerTest.h
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
* Sine1 (1 Hz, 5 V, phase 0)
|
||||
* Sine2 (0.3 Hz, 3 V, phase 60 deg)
|
||||
*
|
||||
* Thread2 1 kHz — 2 array sines @ 1 Msps (1000 elem × 1 kHz)
|
||||
* Thread2 1 kHz — 2 array sines @ 1 Msps (1000 elem × 1 kHz, Strict)
|
||||
* Ch1 (1 kHz, 1 V, phase 0)
|
||||
* Ch2 (5 kHz, 0.5 V, phase 90 deg)
|
||||
* Strict publishing: every cycle's 1 ms array is sent so the
|
||||
* reconstructed waveform is contiguous (Decimate would drop
|
||||
* whole cycles, leaving periodic gaps in the array trace).
|
||||
*
|
||||
* Thread3 5 kHz — 2 array sines @ 5 Msps (1000 elem × 5 kHz, Ratio=5 → 1 kHz pub)
|
||||
* Thread3 5 kHz — 2 array sines @ 5 Msps (1000 elem × 5 kHz, Strict)
|
||||
* Ch3 (10 kHz, 2 V, phase 0)
|
||||
* Ch4 (50 kHz, 1.5 V, phase 45 deg)
|
||||
*/
|
||||
@@ -437,9 +440,13 @@ $App = {
|
||||
+Streamer2 = {
|
||||
Class = UDPStreamer
|
||||
Port = 44501
|
||||
MaxPayloadSize = 1400
|
||||
PublishingMode = "Decimate"
|
||||
Ratio = 10
|
||||
// One full cycle = TimeArray1(8000) + Ch1(4000) + Ch2(4000) = 16000 B.
|
||||
// Sizing the payload above a whole cycle sends each cycle as a single
|
||||
// datagram (totalFragments = 1): at Strict 1 kHz / 5 kHz this avoids
|
||||
// saturating the receiver's fragment-reassembly pool, which otherwise
|
||||
// evicts in-flight cycles and reintroduces gaps in the array traces.
|
||||
MaxPayloadSize = 18000
|
||||
PublishingMode = "Strict"
|
||||
Signals = {
|
||||
TimeArray1 = {
|
||||
Type = uint64
|
||||
@@ -469,9 +476,12 @@ $App = {
|
||||
+Streamer3 = {
|
||||
Class = UDPStreamer
|
||||
Port = 44502
|
||||
MaxPayloadSize = 1400
|
||||
PublishingMode = "Decimate"
|
||||
Ratio = 5
|
||||
// One full cycle = TimeArray2(8000) + Ch3(4000) + Ch4(4000) = 16000 B.
|
||||
// Single-datagram cycles (see Streamer2) — essential here because this
|
||||
// source runs Strict at 5 kHz, where per-cycle fragmentation would flood
|
||||
// the reassembly pool.
|
||||
MaxPayloadSize = 18000
|
||||
PublishingMode = "Strict"
|
||||
Signals = {
|
||||
TimeArray2 = {
|
||||
Type = uint64
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
// E2E_Report.typ — Streaming-chain E2E report.
|
||||
//
|
||||
// Renders report_data.json (produced by report_build.py) into a single PDF:
|
||||
// headline KPIs, per-field progression/regression vs the previous run, unit-test
|
||||
// suites, code coverage, performance (CPU/peak-RSS/throughput), per-scenario
|
||||
// waveform fidelity, trend plots, and embedded per-scenario waveform images.
|
||||
//
|
||||
// Compile from the directory holding report_data.json + the *.png artifacts:
|
||||
// typst compile E2E_Report.typ E2E_Report.pdf
|
||||
// Missing inputs degrade to "n/a" / skipped sections so a partial run still
|
||||
// renders.
|
||||
|
||||
#let data = json("report_data.json")
|
||||
#let meta = data.meta
|
||||
#let e2e = data.e2e
|
||||
#let ut = data.unit_tests
|
||||
#let cov = data.coverage
|
||||
#let reg = data.regression
|
||||
#let hl = data.headline
|
||||
|
||||
// ── helpers ──────────────────────────────────────────────────────────────────
|
||||
#let fmt(v, suffix: "") = if v == none { "n/a" } else { str(v) + suffix }
|
||||
#let fnum(v, digits: 3, suffix: "") = {
|
||||
if v == none { "n/a" } else {
|
||||
[#calc.round(v, digits: digits)] + suffix
|
||||
}
|
||||
}
|
||||
#let ok_color = rgb("#1a7f37")
|
||||
#let bad_color = rgb("#cf222e")
|
||||
#let neutral = rgb("#57606a")
|
||||
|
||||
#let warn_color = rgb("#9a6700") // XFAIL — expected/known failure
|
||||
#let xpass_color = rgb("#8250df") // XPASS — stale marker, needs attention
|
||||
#let status_badge(s) = {
|
||||
let c = if s == "PASS" { ok_color }
|
||||
else if s == "FAIL" { bad_color }
|
||||
else if s == "XFAIL" { warn_color }
|
||||
else if s == "XPASS" { xpass_color }
|
||||
else { neutral }
|
||||
box(fill: c, inset: (x: 6pt, y: 2pt), radius: 3pt, text(fill: white, weight: "bold", size: 8pt)[#s])
|
||||
}
|
||||
|
||||
#let yesno(b) = {
|
||||
if b == true { text(fill: ok_color)[✓] }
|
||||
else if b == false { text(fill: bad_color)[✗] }
|
||||
else { text(fill: neutral)[—] }
|
||||
}
|
||||
|
||||
// progression arrow for a regression row
|
||||
#let trend_arrow(r) = {
|
||||
if r.delta == none or r.delta == 0 { text(fill: neutral)[—] }
|
||||
else {
|
||||
let up = r.delta > 0
|
||||
let good = r.better == true
|
||||
let c = if good { ok_color } else { bad_color }
|
||||
let arrow = if up { "▲" } else { "▼" }
|
||||
text(fill: c)[#arrow #calc.round(r.delta, digits: 4)]
|
||||
}
|
||||
}
|
||||
|
||||
// ── page setup ───────────────────────────────────────────────────────────────
|
||||
#set page(
|
||||
paper: "a4", margin: (x: 1.8cm, y: 1.8cm),
|
||||
header: align(right, text(size: 8pt, fill: neutral)[Streaming-chain E2E · #meta.git_sha]),
|
||||
footer: context align(center, text(size: 8pt, fill: neutral)[#counter(page).display("1 / 1", both: true)]),
|
||||
)
|
||||
#set text(font: "DejaVu Sans", size: 9.5pt)
|
||||
#set heading(numbering: "1.1")
|
||||
#show heading.where(level: 1): it => block(above: 14pt, below: 8pt, text(size: 14pt, weight: "bold", it))
|
||||
#show heading.where(level: 2): it => block(above: 10pt, below: 6pt, text(size: 11pt, weight: "bold", it))
|
||||
|
||||
// ── title ────────────────────────────────────────────────────────────────────
|
||||
#align(center)[
|
||||
#text(size: 20pt, weight: "bold")[MARTe2 Streaming-Chain E2E Report] \
|
||||
#v(2pt)
|
||||
#text(size: 10pt, fill: neutral)[
|
||||
#meta.timestamp · commit #raw(meta.git_sha) · target #meta.target ·
|
||||
run \##data.history_len
|
||||
]
|
||||
]
|
||||
|
||||
#v(6pt)
|
||||
#align(center, status_badge(e2e.overall) + h(8pt) + text(size: 11pt)[
|
||||
E2E #hl.e2e_pass/#hl.e2e_total · Units #hl.unit_pass/#hl.unit_total
|
||||
#if hl.at("e2e_xfail", default: 0) > 0 [ · #hl.e2e_xfail xfail]
|
||||
#if hl.at("e2e_xpass", default: 0) > 0 [ · #text(fill: xpass_color)[#hl.e2e_xpass xpass!]]
|
||||
])
|
||||
|
||||
// ── headline KPIs ────────────────────────────────────────────────────────────
|
||||
#v(10pt)
|
||||
#let kpi(label, value) = box(width: 100%, inset: 8pt, radius: 4pt, fill: rgb("#f6f8fa"))[
|
||||
#align(center)[
|
||||
#text(size: 14pt, weight: "bold")[#value] \
|
||||
#text(size: 8pt, fill: neutral)[#label]
|
||||
]
|
||||
]
|
||||
#grid(columns: 4, gutter: 6pt,
|
||||
kpi("E2E passed", [#hl.e2e_pass/#hl.e2e_total]),
|
||||
kpi("Unit passed", [#hl.unit_pass/#hl.unit_total]),
|
||||
kpi("Mean sine corr", fnum(hl.mean_corr, digits: 4)),
|
||||
kpi("Throughput", fnum(hl.mean_throughput_sps, digits: 0, suffix: " sp/s")),
|
||||
kpi("Python cov", fmt(hl.cov_python, suffix: "%")),
|
||||
kpi("Go cov", fmt(hl.cov_go, suffix: "%")),
|
||||
kpi("Mean peak RSS", fnum(hl.mean_peak_rss_mb, digits: 1, suffix: " MB")),
|
||||
kpi("Mean CPU", fnum(hl.mean_cpu_s, digits: 2, suffix: " s")),
|
||||
)
|
||||
|
||||
// ── progression / regression ─────────────────────────────────────────────────
|
||||
= Progression / regression
|
||||
#if data.is_first_run [
|
||||
_First recorded run — baseline established; no previous run to compare against._
|
||||
] else [
|
||||
Comparison against the previous run (#text(fill: ok_color)[▲] better,
|
||||
#text(fill: bad_color)[▼] worse, — unchanged/unavailable).
|
||||
#v(4pt)
|
||||
#table(
|
||||
columns: (1.6fr, 1fr, 1fr, 1.2fr),
|
||||
align: (left, right, right, right),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 5pt,
|
||||
table.header([*Metric*], [*Current*], [*Previous*], [*Δ (trend)*]),
|
||||
..reg.map(r => (
|
||||
[#r.name],
|
||||
fnum(r.current, digits: 4),
|
||||
fnum(r.previous, digits: 4),
|
||||
trend_arrow(r),
|
||||
)).flatten()
|
||||
)
|
||||
]
|
||||
|
||||
// ── unit tests ───────────────────────────────────────────────────────────────
|
||||
= Unit tests
|
||||
#table(
|
||||
columns: (2fr, 0.8fr, 0.8fr, 0.8fr, 0.8fr, 0.8fr, 0.8fr),
|
||||
align: (left, center, right, right, right, right, right),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 5pt,
|
||||
table.header([*Suite*], [*Status*], [*Total*], [*Pass*], [*Fail*], [*Skip*], [*Time (s)*]),
|
||||
..ut.suites.map(s => (
|
||||
[#s.name],
|
||||
if not s.avail { status_badge("SKIP") } else if s.ok { status_badge("PASS") } else { status_badge("FAIL") },
|
||||
[#s.total], [#s.passed], [#s.failed], [#s.skipped], fnum(s.time_s, digits: 2),
|
||||
)).flatten(),
|
||||
table.cell(colspan: 2)[*Totals*],
|
||||
[#ut.totals.total], [#ut.totals.passed], [#ut.totals.failed], [#ut.totals.skipped], [],
|
||||
)
|
||||
|
||||
// ── coverage ─────────────────────────────────────────────────────────────────
|
||||
= Code coverage
|
||||
#table(
|
||||
columns: (1fr, 1fr, 2fr),
|
||||
align: (left, right, left),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 5pt,
|
||||
table.header([*Language*], [*Coverage*], [*Source*]),
|
||||
..cov.languages.map(l => (
|
||||
[#l.name],
|
||||
if l.pct == none { text(fill: neutral)[n/a] } else { [#l.pct%] },
|
||||
text(size: 8pt, fill: neutral)[#l.note],
|
||||
)).flatten()
|
||||
)
|
||||
|
||||
// per-file C++ detail — the streaming chain's most critical code, so the report
|
||||
// shows line coverage for every project C++ source (worst-covered first).
|
||||
#let cpp = cov.languages.find(l => l.name == "C++")
|
||||
#if cpp != none and cpp.at("files", default: ()).len() > 0 [
|
||||
== C++ source detail
|
||||
#let cf = cpp.files
|
||||
#text(size: 8pt, fill: neutral)[
|
||||
#cpp.at("lines_hit", default: 0) of #cpp.at("lines_found", default: 0)
|
||||
lines covered across #cf.len() project files (worst-covered first;
|
||||
green ≥75%, amber 50–75%, red under 50%).
|
||||
]
|
||||
#v(4pt)
|
||||
#let covcell(p) = {
|
||||
let c = if p == none { neutral }
|
||||
else if p >= 75 { ok_color }
|
||||
else if p >= 50 { warn_color }
|
||||
else { bad_color }
|
||||
text(fill: c, weight: "bold")[#if p == none { "n/a" } else [#p%]]
|
||||
}
|
||||
#table(
|
||||
columns: (3.2fr, 1fr, 1fr, 1.1fr),
|
||||
align: (left, right, right, right),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 4pt,
|
||||
table.header([*Source file*], [*Lines*], [*Hit*], [*Coverage*]),
|
||||
..cf.map(f => (
|
||||
text(size: 8pt)[#f.path],
|
||||
[#f.lines_found],
|
||||
[#f.lines_hit],
|
||||
covcell(f.pct),
|
||||
)).flatten()
|
||||
)
|
||||
]
|
||||
|
||||
// ── performance ──────────────────────────────────────────────────────────────
|
||||
= Performance
|
||||
Per-scenario CPU time and peak resident memory (VmHWM) of the StreamHub and
|
||||
MARTe2 processes, plus sustained client throughput (recorded samples ÷ duration).
|
||||
#v(4pt)
|
||||
#table(
|
||||
columns: (1.8fr, 1fr, 1fr, 1fr, 1fr, 1.1fr),
|
||||
align: (left, right, right, right, right, right),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 5pt,
|
||||
table.header([*Scenario*], [*Hub CPU (s)*], [*Hub RSS (MB)*],
|
||||
[*MARTe CPU (s)*], [*MARTe RSS (MB)*], [*Throughput (sp/s)*]),
|
||||
..e2e.scenarios.map(sc => {
|
||||
let h = sc.perf.at("hub", default: (:))
|
||||
let m = sc.perf.at("marte", default: (:))
|
||||
(
|
||||
[#sc.id],
|
||||
fnum(h.at("cpu_s", default: none), digits: 2),
|
||||
fnum(h.at("peak_rss_mb", default: none), digits: 1),
|
||||
fnum(m.at("cpu_s", default: none), digits: 2),
|
||||
fnum(m.at("peak_rss_mb", default: none), digits: 1),
|
||||
fnum(sc.throughput_sps, digits: 0),
|
||||
)
|
||||
}).flatten()
|
||||
)
|
||||
|
||||
// ── per-scenario waveform fidelity ───────────────────────────────────────────
|
||||
= Scenarios
|
||||
#for sc in e2e.scenarios [
|
||||
== #sc.id #h(6pt) #status_badge(sc.status)
|
||||
#if sc.at("desc", default: none) != none [
|
||||
#v(1pt)
|
||||
#text(size: 9pt, fill: neutral, style: "italic")[#sc.desc]
|
||||
#v(2pt)
|
||||
]
|
||||
#if sc.at("known_issue", default: none) != none [
|
||||
#v(2pt)
|
||||
#box(fill: rgb("#fff8c5"), inset: 5pt, radius: 3pt, width: 100%,
|
||||
text(size: 8pt, fill: rgb("#7d4e00"))[*Known issue:* #sc.known_issue])
|
||||
]
|
||||
#let rb = sc.rollup
|
||||
Client checks:
|
||||
live #yesno(rb.at("live_ok", default: none)) ·
|
||||
zoom #yesno(rb.at("zoom_ok", default: none)) ·
|
||||
window #yesno(rb.at("window_ok", default: none)) ·
|
||||
trigger #yesno(rb.at("trigger_ok", default: none))
|
||||
#if sc.live_frames != none [ · #sc.live_frames live frames]
|
||||
#v(3pt)
|
||||
#table(
|
||||
columns: (1.6fr, 0.6fr, 0.8fr, 0.8fr, 1fr, 0.9fr, 0.9fr, 0.8fr, 0.8fr),
|
||||
align: (left, center, left, left, right, right, right, center, center),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 4pt,
|
||||
table.header([*Signal*], [*Pass*], [*Type*], [*Quant*], [*Max abs err*],
|
||||
[*Corr*], [*nRMSE*], [*Fidelity*], [*Shape*]),
|
||||
..sc.signals.map(g => (
|
||||
raw(g.key),
|
||||
yesno(g.pass),
|
||||
text(size: 8pt)[#g.type],
|
||||
text(size: 8pt)[#g.quant],
|
||||
fnum(g.max_abs_err, digits: 6),
|
||||
fnum(g.corr, digits: 4),
|
||||
fnum(g.nrmse, digits: 4),
|
||||
yesno(g.fidelity_ok),
|
||||
yesno(g.shape_ok),
|
||||
)).flatten()
|
||||
)
|
||||
// zoom / window / trigger behavioural detail (real WS-driven results)
|
||||
#let zooms = sc.at("zoom", default: ())
|
||||
#let win = sc.at("window", default: (:))
|
||||
#let trigs = sc.at("trigger", default: ())
|
||||
#if zooms.len() > 0 or win.len() > 0 [
|
||||
#v(3pt)
|
||||
#text(size: 8.5pt, weight: "bold")[Zoom / window queries]
|
||||
#table(
|
||||
columns: (1fr, 1.2fr, 1fr, 0.8fr, 0.8fr),
|
||||
align: (left, left, right, right, center),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 4pt,
|
||||
table.header([*Query*], [*Signal*], [*Span (s)*], [*Pts*], [*OK*]),
|
||||
..zooms.enumerate().map(((i, z)) => {
|
||||
let r = z.at("range", default: (0, 0))
|
||||
(
|
||||
[zoom #str(i + 1)],
|
||||
raw(z.at("key", default: "")),
|
||||
fnum(r.at(1) - r.at(0), digits: 4),
|
||||
[#z.at("returned", default: 0)],
|
||||
yesno(z.at("inrange", default: none)),
|
||||
)
|
||||
}).flatten(),
|
||||
..(if win.len() > 0 and win.at("returned", default: 0) > 0 {(
|
||||
[window #fnum(win.at("windowSec", default: 0), digits: 2)],
|
||||
raw(win.at("key", default: "")),
|
||||
fnum(win.at("span", default: 0), digits: 4),
|
||||
[#win.at("returned", default: 0)],
|
||||
yesno(win.at("ok", default: none)),
|
||||
)} else {()}),
|
||||
)
|
||||
]
|
||||
#if trigs.len() > 0 [
|
||||
#v(3pt)
|
||||
#text(size: 8.5pt, weight: "bold")[Trigger captures] #h(4pt)
|
||||
#text(size: 8pt, fill: neutral)[(signal #raw(trigs.at(0).at("key", default: "")))]
|
||||
#table(
|
||||
columns: (1fr, 1fr, 0.8fr, 1fr, 1fr, 0.8fr, 0.8fr),
|
||||
align: (left, left, center, right, right, center, center),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 4pt,
|
||||
table.header([*Edge*], [*Mode*], [*Fired*], [*Pre/Post (s)*],
|
||||
[*Capture pts*], [*Win OK*], [*Edge OK*]),
|
||||
..trigs.map(t => (
|
||||
text(size: 8pt)[#t.at("edge", default: "")],
|
||||
text(size: 8pt)[#t.at("mode", default: "")],
|
||||
yesno(t.at("fired", default: none)),
|
||||
text(size: 8pt)[#fnum(t.at("preSec", default: 0), digits: 3) / #fnum(t.at("postSec", default: 0), digits: 3)],
|
||||
[#t.at("capturePts", default: 0)],
|
||||
yesno(t.at("windowOk", default: none)),
|
||||
yesno(t.at("edgeOk", default: none)),
|
||||
)).flatten()
|
||||
)
|
||||
]
|
||||
// embed the waveform overview if report_build.py found one in the artifacts
|
||||
#if sc.at("wave_img", default: none) != none [
|
||||
#v(3pt)
|
||||
#align(center, image(sc.wave_img, width: 92%))
|
||||
]
|
||||
#v(6pt)
|
||||
]
|
||||
|
||||
// ── trend plots ──────────────────────────────────────────────────────────────
|
||||
#if data.trend_plots.len() > 0 [
|
||||
= Trends over runs
|
||||
#grid(columns: 2, gutter: 8pt,
|
||||
..data.trend_plots.map(p => image(p, width: 100%))
|
||||
)
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+177
-10
@@ -44,6 +44,9 @@ var (
|
||||
durSec = flag.Float64("dur", 4.0, "live recording duration (s)")
|
||||
timeout = flag.Duration("timeout", 90*time.Second, "overall timeout")
|
||||
verbose = flag.Bool("v", false, "log every event")
|
||||
mode = flag.String("mode", "checks", "checks | stress")
|
||||
reqrate = flag.Float64("reqrate", 0, "stress: sustained zoom requests/sec (0 = liveness only)")
|
||||
clientID = flag.Int("clientid", 0, "stress: parallel client index (output suffix)")
|
||||
)
|
||||
|
||||
// ── wire types ────────────────────────────────────────────────────────────
|
||||
@@ -173,13 +176,14 @@ type client struct {
|
||||
ws *websocket.Conn
|
||||
deadline time.Time
|
||||
|
||||
mu sync.Mutex
|
||||
sources []sourceInfo
|
||||
configs map[string][]signalInfo
|
||||
pushes []*pushFrame
|
||||
zooms map[uint32]map[string]points
|
||||
trigSt []string
|
||||
captures []*captureFrame
|
||||
mu sync.Mutex
|
||||
sources []sourceInfo
|
||||
configs map[string][]signalInfo
|
||||
pushes []*pushFrame
|
||||
zooms map[uint32]map[string]points
|
||||
zoomArrival map[uint32]time.Time
|
||||
trigSt []string
|
||||
captures []*captureFrame
|
||||
|
||||
readErr error
|
||||
done chan struct{}
|
||||
@@ -266,6 +270,7 @@ func (c *client) handle(mt int, data []byte) {
|
||||
if json.Unmarshal(data, &body) == nil {
|
||||
c.mu.Lock()
|
||||
c.zooms[ev.ReqID] = body.Signals
|
||||
c.zoomArrival[ev.ReqID] = time.Now()
|
||||
c.mu.Unlock()
|
||||
}
|
||||
case "triggerState":
|
||||
@@ -491,9 +496,10 @@ func main() {
|
||||
|
||||
c := &client{
|
||||
ws: ws, deadline: time.Now().Add(*timeout),
|
||||
configs: map[string][]signalInfo{},
|
||||
zooms: map[uint32]map[string]points{},
|
||||
done: make(chan struct{}),
|
||||
configs: map[string][]signalInfo{},
|
||||
zooms: map[uint32]map[string]points{},
|
||||
zoomArrival: map[uint32]time.Time{},
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
go c.reader()
|
||||
out := checksOut{Scenario: *scenario}
|
||||
@@ -522,6 +528,13 @@ func main() {
|
||||
return true
|
||||
})
|
||||
|
||||
// stress mode: record liveness + sustained zoom latency, then exit. The
|
||||
// correctness checks below are skipped (a separate gate framework).
|
||||
if *mode == "stress" {
|
||||
c.runStress(*scenario, *clientID, *durSec, *reqrate, *outDir)
|
||||
return
|
||||
}
|
||||
|
||||
// 2. live recording — the reader goroutine accumulates pushes in the
|
||||
// background, so we simply wait out the recording window (or an early
|
||||
// reader death).
|
||||
@@ -647,6 +660,160 @@ func main() {
|
||||
fmt.Printf("OK chain-client %s: %s + %s\n", *scenario, filepath.Base(recvPath), filepath.Base(cj))
|
||||
}
|
||||
|
||||
// ── stress mode ──────────────────────────────────────────────────────────────
|
||||
|
||||
type stressOut struct {
|
||||
Scenario string `json:"scenario"`
|
||||
ClientID int `json:"clientId"`
|
||||
Frames int `json:"frames"`
|
||||
Signals int `json:"signals"`
|
||||
Monotonic bool `json:"monotonic"`
|
||||
WallClock bool `json:"wallclock"`
|
||||
DurationS float64 `json:"duration"`
|
||||
ReqRate float64 `json:"reqRate"`
|
||||
ZoomCount int `json:"zoomCount"`
|
||||
ZoomFail int `json:"zoomFail"`
|
||||
ZoomP50ms float64 `json:"zoomP50ms"`
|
||||
ZoomP95ms float64 `json:"zoomP95ms"`
|
||||
ZoomMaxms float64 `json:"zoomMaxms"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// busiestKey returns the full "src:sig" key carrying the most samples so far.
|
||||
func (c *client) busiestKey() string {
|
||||
m := c.merged()
|
||||
var busy string
|
||||
bn := 0
|
||||
for k, p := range m {
|
||||
if len(p.T) > bn {
|
||||
bn, busy = len(p.T), k
|
||||
}
|
||||
}
|
||||
return busy
|
||||
}
|
||||
|
||||
// maxTimeFull returns the latest timestamp seen for a full "src:sig" key.
|
||||
func (c *client) maxTimeFull(full string) (float64, bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
var mx float64
|
||||
found := false
|
||||
for _, f := range c.pushes {
|
||||
if !strings.HasPrefix(full, f.sourceID+":") {
|
||||
continue
|
||||
}
|
||||
name := full[len(f.sourceID)+1:]
|
||||
p, ok := f.signals[name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, t := range p.T {
|
||||
if !found || t > mx {
|
||||
mx, found = t, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return mx, found
|
||||
}
|
||||
|
||||
// runStress records liveness for the duration while (optionally) issuing zoom
|
||||
// queries at a sustained rate, measuring round-trip latency. One request is in
|
||||
// flight at a time, so latency reflects the hub's serialised zoom service time
|
||||
// under whatever concurrent live/zoom load the matrix imposes.
|
||||
func (c *client) runStress(scenario string, clientID int, dur, reqrate float64, outDir string) {
|
||||
if !c.waitFor(20*time.Second, func() bool { return len(c.pushes) > 0 }) {
|
||||
fatal("stress: no live push within timeout")
|
||||
}
|
||||
// brief warmup so the busiest signal and a usable time window exist.
|
||||
c.waitFor(500*time.Millisecond, func() bool { return false })
|
||||
key := c.busiestKey()
|
||||
|
||||
start := time.Now()
|
||||
end := start.Add(time.Duration(dur * float64(time.Second)))
|
||||
var lat []float64
|
||||
zoomFail := 0
|
||||
var reqID uint32 = 5000
|
||||
var interval time.Duration
|
||||
if reqrate > 0 {
|
||||
interval = time.Duration(float64(time.Second) / reqrate)
|
||||
}
|
||||
|
||||
for reqrate > 0 && key != "" && time.Now().Before(end) {
|
||||
tick := time.Now()
|
||||
t1, ok := c.maxTimeFull(key)
|
||||
if !ok {
|
||||
c.waitFor(50*time.Millisecond, func() bool { return false })
|
||||
continue
|
||||
}
|
||||
reqID++
|
||||
c.send(map[string]interface{}{
|
||||
"type": "zoom", "reqId": reqID, "t0": t1 - 0.5, "t1": t1,
|
||||
"n": 300, "signals": key,
|
||||
})
|
||||
sendT := time.Now()
|
||||
got := c.waitFor(3*time.Second, func() bool {
|
||||
_, ok := c.zoomArrival[reqID]
|
||||
return ok
|
||||
})
|
||||
if got {
|
||||
c.mu.Lock()
|
||||
at := c.zoomArrival[reqID]
|
||||
c.mu.Unlock()
|
||||
lat = append(lat, at.Sub(sendT).Seconds()*1000.0)
|
||||
} else {
|
||||
zoomFail++
|
||||
}
|
||||
if rem := interval - time.Since(tick); rem > 0 {
|
||||
c.waitFor(rem, func() bool { return false })
|
||||
}
|
||||
}
|
||||
// if no reqrate, simply wait out the remaining liveness window.
|
||||
if reqrate <= 0 {
|
||||
c.waitFor(time.Until(end), func() bool { return false })
|
||||
}
|
||||
|
||||
m := c.merged()
|
||||
now := float64(time.Now().UnixNano()) / 1e9
|
||||
mono, wall := true, true
|
||||
for _, p := range m {
|
||||
for i, t := range p.T {
|
||||
if math.Abs(t-now) > 60.0 {
|
||||
wall = false
|
||||
}
|
||||
if i > 0 && t < p.T[i-1]-1e-9 {
|
||||
mono = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Float64s(lat)
|
||||
pct := func(q float64) float64 {
|
||||
if len(lat) == 0 {
|
||||
return 0
|
||||
}
|
||||
idx := int(q * float64(len(lat)-1))
|
||||
return lat[idx]
|
||||
}
|
||||
so := stressOut{
|
||||
Scenario: scenario, ClientID: clientID,
|
||||
Frames: c.nPushes(), Signals: len(m), Monotonic: mono,
|
||||
WallClock: wall, DurationS: dur, ReqRate: reqrate, Key: key,
|
||||
ZoomCount: len(lat), ZoomFail: zoomFail,
|
||||
ZoomP50ms: pct(0.50), ZoomP95ms: pct(0.95),
|
||||
}
|
||||
if len(lat) > 0 {
|
||||
so.ZoomMaxms = lat[len(lat)-1]
|
||||
}
|
||||
path := filepath.Join(outDir,
|
||||
fmt.Sprintf("stress_%s_c%d.json", scenario, clientID))
|
||||
b, _ := json.MarshalIndent(so, "", " ")
|
||||
if err := os.WriteFile(path, b, 0o644); err != nil {
|
||||
fatal("write stress: %v", err)
|
||||
}
|
||||
log.Printf("stress: frames=%d signals=%d zoom n=%d fail=%d p50=%.1fms p95=%.1fms max=%.1fms",
|
||||
so.Frames, so.Signals, so.ZoomCount, so.ZoomFail, so.ZoomP50ms, so.ZoomP95ms, so.ZoomMaxms)
|
||||
fmt.Printf("OK stress %s c%d: %s\n", scenario, clientID, filepath.Base(path))
|
||||
}
|
||||
|
||||
// runTrigger configures one edge/mode trigger, arms it, and records the result.
|
||||
func (c *client) runTrigger(key, edge, mode string, thr float64) trigCheck {
|
||||
tc := trigCheck{Edge: edge, Mode: mode, Key: key}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ── frame builders (mirror the StreamHub wire format) ───────────────────────
|
||||
|
||||
func putf(b []byte, v float64) []byte {
|
||||
var t [8]byte
|
||||
binary.LittleEndian.PutUint64(t[:], math.Float64bits(v))
|
||||
return append(b, t[:]...)
|
||||
}
|
||||
|
||||
func putSignals(b []byte, sigs map[string]points) []byte {
|
||||
var n [4]byte
|
||||
binary.LittleEndian.PutUint32(n[:], uint32(len(sigs)))
|
||||
b = append(b, n[:]...)
|
||||
for k, p := range sigs {
|
||||
var kl [2]byte
|
||||
binary.LittleEndian.PutUint16(kl[:], uint16(len(k)))
|
||||
b = append(b, kl[:]...)
|
||||
b = append(b, []byte(k)...)
|
||||
var cnt [4]byte
|
||||
binary.LittleEndian.PutUint32(cnt[:], uint32(len(p.T)))
|
||||
b = append(b, cnt[:]...)
|
||||
for _, t := range p.T {
|
||||
b = putf(b, t)
|
||||
}
|
||||
for _, v := range p.V {
|
||||
b = putf(b, v)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func buildPush(srcID string, sigs map[string]points) []byte {
|
||||
b := []byte{1, byte(len(srcID))}
|
||||
b = append(b, []byte(srcID)...)
|
||||
return putSignals(b, sigs)
|
||||
}
|
||||
|
||||
func buildCapture(trigTime, preSec, postSec float64, sigs map[string]points) []byte {
|
||||
b := []byte{2}
|
||||
b = putf(b, trigTime)
|
||||
b = putf(b, preSec)
|
||||
b = putf(b, postSec)
|
||||
return putSignals(b, sigs)
|
||||
}
|
||||
|
||||
// ── tests ───────────────────────────────────────────────────────────────────
|
||||
|
||||
func TestParsePushRoundTrip(t *testing.T) {
|
||||
in := map[string]points{"Sine": {T: []float64{0, 0.1, 0.2}, V: []float64{1, 2, 3}}}
|
||||
f, err := parsePush(buildPush("src", in))
|
||||
if err != nil {
|
||||
t.Fatalf("parsePush: %v", err)
|
||||
}
|
||||
if f.sourceID != "src" {
|
||||
t.Errorf("sourceID = %q, want src", f.sourceID)
|
||||
}
|
||||
got := f.signals["Sine"]
|
||||
if len(got.T) != 3 || got.T[2] != 0.2 || got.V[1] != 2 {
|
||||
t.Errorf("bad payload: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePushRejectsWrongVersion(t *testing.T) {
|
||||
if _, err := parsePush([]byte{2, 0, 0}); err == nil {
|
||||
t.Error("expected error on non-v1 frame")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePushTruncated(t *testing.T) {
|
||||
full := buildPush("src", map[string]points{"A": {T: []float64{0}, V: []float64{1}}})
|
||||
if _, err := parsePush(full[:len(full)-4]); err == nil {
|
||||
t.Error("expected truncation error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCaptureRoundTrip(t *testing.T) {
|
||||
in := map[string]points{"Sig": {T: []float64{1, 2}, V: []float64{9, 8}}}
|
||||
f, err := parseCapture(buildCapture(100.5, 0.02, 0.08, in))
|
||||
if err != nil {
|
||||
t.Fatalf("parseCapture: %v", err)
|
||||
}
|
||||
if f.trigTime != 100.5 || f.preSec != 0.02 || f.postSec != 0.08 {
|
||||
t.Errorf("header = %v/%v/%v", f.trigTime, f.preSec, f.postSec)
|
||||
}
|
||||
if g := f.signals["Sig"]; len(g.T) != 2 || g.V[0] != 9 {
|
||||
t.Errorf("bad capture payload: %+v", g)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCaptureRejectsWrongVersion(t *testing.T) {
|
||||
if _, err := parseCapture([]byte{1, 0, 0, 0}); err == nil {
|
||||
t.Error("expected error on non-v2 frame")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergedSortsAndDedups(t *testing.T) {
|
||||
c := &client{
|
||||
configs: map[string][]signalInfo{},
|
||||
zooms: map[uint32]map[string]points{},
|
||||
}
|
||||
// two pushes, out of order, with one duplicate timestamp
|
||||
c.pushes = []*pushFrame{
|
||||
{sourceID: "s", signals: map[string]points{"A": {T: []float64{0.2, 0.1}, V: []float64{2, 1}}}},
|
||||
{sourceID: "s", signals: map[string]points{"A": {T: []float64{0.1, 0.3}, V: []float64{1, 3}}}},
|
||||
}
|
||||
m := c.merged()
|
||||
got := m["s:A"]
|
||||
want := []float64{0.1, 0.2, 0.3}
|
||||
if len(got.T) != len(want) {
|
||||
t.Fatalf("len = %d, want %d (%+v)", len(got.T), len(want), got)
|
||||
}
|
||||
for i := range want {
|
||||
if got.T[i] != want[i] {
|
||||
t.Errorf("t[%d] = %v, want %v", i, got.T[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEdgeCrosses(t *testing.T) {
|
||||
rising := points{T: []float64{0, 1, 2}, V: []float64{-1, 1, 2}}
|
||||
if !edgeCrosses(rising, 0.5, "rising", 0.0) {
|
||||
t.Error("rising cross not detected")
|
||||
}
|
||||
if edgeCrosses(rising, 0.5, "falling", 0.0) {
|
||||
t.Error("false falling detection on rising data")
|
||||
}
|
||||
falling := points{T: []float64{0, 1}, V: []float64{1, -1}}
|
||||
if !edgeCrosses(falling, 0.5, "falling", 0.0) {
|
||||
t.Error("falling cross not detected")
|
||||
}
|
||||
if !edgeCrosses(falling, 0.5, "both", 0.0) {
|
||||
t.Error("both should match a falling edge")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHas(t *testing.T) {
|
||||
if !has("live,zoom,trigger", "zoom") {
|
||||
t.Error("has should find zoom")
|
||||
}
|
||||
if has("live, window", "trigger") {
|
||||
t.Error("has should not find trigger")
|
||||
}
|
||||
if !has("live, window", "window") {
|
||||
t.Error("has should trim spaces")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
collect.py — Run the unit-test suites and gather coverage for the E2E report.
|
||||
|
||||
Produces two JSON artifacts in --out:
|
||||
|
||||
* ``unit_tests.json`` — per-suite {total, passed, failed, skipped, time_s, ok}
|
||||
for the C++ GTest binary, the Go chain-client tests, and the Python
|
||||
framework tests, plus grand totals.
|
||||
* ``coverage.json`` — per-language {pct, avail, note} for Python (coverage.py),
|
||||
Go (``go test -cover``) and C++ (lcov, best-effort: only when the build was
|
||||
instrumented with .gcno files; otherwise reported unavailable).
|
||||
|
||||
Each suite is isolated: a missing toolchain or a failing suite is recorded, never
|
||||
fatal, so the report always renders. Requires the MARTe env (LD_LIBRARY_PATH) to
|
||||
already be exported for the GTest binary — the orchestrator does this.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
def _run(cmd, cwd=None, env=None, timeout=600):
|
||||
try:
|
||||
p = subprocess.run(cmd, cwd=cwd, env=env, timeout=timeout,
|
||||
capture_output=True, text=True)
|
||||
return p.returncode, p.stdout, p.stderr
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
|
||||
return 127, "", str(e)
|
||||
|
||||
|
||||
# ── C++ GTest ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def gtest_suite(gtest_bin, work):
|
||||
s = {"name": "C++ GTest", "lang": "cpp", "total": 0, "passed": 0,
|
||||
"failed": 0, "skipped": 0, "time_s": 0.0, "ok": False, "avail": False}
|
||||
if not gtest_bin or not os.path.exists(gtest_bin):
|
||||
s["detail"] = "GTest binary not found"
|
||||
return s
|
||||
xml_p = os.path.join(work, "gtest.xml")
|
||||
rc, out, err = _run([gtest_bin, f"--gtest_output=xml:{xml_p}"], timeout=900)
|
||||
s["avail"] = True
|
||||
if os.path.exists(xml_p):
|
||||
try:
|
||||
root = ET.parse(xml_p).getroot()
|
||||
s["total"] = int(root.get("tests", 0))
|
||||
s["failed"] = int(root.get("failures", 0)) + int(root.get("errors", 0))
|
||||
s["skipped"] = int(root.get("disabled", 0)) + int(root.get("skipped", 0))
|
||||
s["time_s"] = float(root.get("time", 0.0))
|
||||
s["passed"] = s["total"] - s["failed"] - s["skipped"]
|
||||
s["ok"] = s["failed"] == 0 and s["total"] > 0
|
||||
except (ET.ParseError, ValueError) as e:
|
||||
s["detail"] = f"xml parse: {e}"
|
||||
else:
|
||||
s["detail"] = (err or out or "no xml produced")[-200:]
|
||||
return s
|
||||
|
||||
|
||||
# ── Go ────────────────────────────────────────────────────────────────────────
|
||||
|
||||
def go_suite(client_dir, work):
|
||||
s = {"name": "Go (chain-client)", "lang": "go", "total": 0, "passed": 0,
|
||||
"failed": 0, "skipped": 0, "time_s": 0.0, "ok": False, "avail": False}
|
||||
cov_p = os.path.join(work, "go_cover.out")
|
||||
rc, out, err = _run(["go", "test", "-json", f"-coverprofile={cov_p}", "./..."],
|
||||
cwd=client_dir)
|
||||
if rc == 127:
|
||||
s["detail"] = "go toolchain not found"
|
||||
return s
|
||||
s["avail"] = True
|
||||
cov_pct = None
|
||||
for line in out.splitlines():
|
||||
try:
|
||||
ev = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
act = ev.get("Action")
|
||||
if act == "pass" and ev.get("Test"):
|
||||
s["passed"] += 1
|
||||
s["total"] += 1
|
||||
elif act == "fail" and ev.get("Test"):
|
||||
s["failed"] += 1
|
||||
s["total"] += 1
|
||||
elif act == "skip" and ev.get("Test"):
|
||||
s["skipped"] += 1
|
||||
s["total"] += 1
|
||||
elif act == "output":
|
||||
m = re.search(r"coverage:\s+([\d.]+)%", ev.get("Output", ""))
|
||||
if m:
|
||||
cov_pct = float(m.group(1))
|
||||
s["ok"] = s["failed"] == 0 and s["total"] > 0
|
||||
s["cov_pct"] = cov_pct
|
||||
return s
|
||||
|
||||
|
||||
# ── Python ──────────────────────────────────────────────────────────────────
|
||||
|
||||
def py_suite(chain_dir, work):
|
||||
s = {"name": "Python (framework)", "lang": "python", "total": 0, "passed": 0,
|
||||
"failed": 0, "skipped": 0, "time_s": 0.0, "ok": False, "avail": True}
|
||||
cov_json = os.path.join(work, "py_cover.json")
|
||||
env = dict(os.environ)
|
||||
env["COVERAGE_FILE"] = os.path.join(work, ".coverage")
|
||||
have_cov = _run(["coverage", "--version"])[0] == 0
|
||||
if have_cov:
|
||||
cmd = ["coverage", "run", f"--source={chain_dir}", "-m", "unittest",
|
||||
"tests_py", "-v"]
|
||||
else:
|
||||
cmd = [sys.executable, "-m", "unittest", "tests_py", "-v"]
|
||||
rc, out, err = _run(cmd, cwd=chain_dir, env=env)
|
||||
text = out + "\n" + err
|
||||
m = re.search(r"Ran (\d+) tests? in ([\d.]+)s", text)
|
||||
if m:
|
||||
s["total"] = int(m.group(1))
|
||||
s["time_s"] = float(m.group(2))
|
||||
fm = re.search(r"failures=(\d+)", text)
|
||||
em = re.search(r"errors=(\d+)", text)
|
||||
sm = re.search(r"skipped=(\d+)", text)
|
||||
s["failed"] = (int(fm.group(1)) if fm else 0) + (int(em.group(1)) if em else 0)
|
||||
s["skipped"] = int(sm.group(1)) if sm else 0
|
||||
s["passed"] = s["total"] - s["failed"] - s["skipped"]
|
||||
s["ok"] = s["failed"] == 0 and s["total"] > 0
|
||||
pct = None
|
||||
if have_cov:
|
||||
_run(["coverage", "json", "-o", cov_json], cwd=chain_dir, env=env)
|
||||
if os.path.exists(cov_json):
|
||||
try:
|
||||
cj = json.load(open(cov_json))
|
||||
pct = round(cj["totals"]["percent_covered"], 1)
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
s["cov_pct"] = pct
|
||||
return s
|
||||
|
||||
|
||||
# ── C++ coverage (best-effort) ────────────────────────────────────────────────
|
||||
|
||||
def _parse_lcov_info(path, repo):
|
||||
"""Parse an LCOV tracefile into per-file line/function coverage.
|
||||
|
||||
Returns (files, totals) where ``files`` is a list of
|
||||
{path (repo-relative), lines_found, lines_hit, pct, funcs_found,
|
||||
funcs_hit} sorted worst-covered first, and ``totals`` aggregates the
|
||||
same line counts across all files. Only the line counters (DA/LF/LH)
|
||||
and function counters (FNF/FNH) are read; branch data is ignored.
|
||||
"""
|
||||
files = []
|
||||
cur = None
|
||||
repo_abs = os.path.abspath(repo) + os.sep
|
||||
try:
|
||||
fh = open(path)
|
||||
except OSError:
|
||||
return [], {"lines_found": 0, "lines_hit": 0, "pct": None}
|
||||
with fh:
|
||||
for line in fh:
|
||||
line = line.rstrip("\n")
|
||||
if line.startswith("SF:"):
|
||||
src = line[3:]
|
||||
rel = src[len(repo_abs):] if src.startswith(repo_abs) else src
|
||||
cur = {"path": rel, "lines_found": 0, "lines_hit": 0,
|
||||
"funcs_found": 0, "funcs_hit": 0}
|
||||
elif cur is None:
|
||||
continue
|
||||
elif line.startswith("LF:"):
|
||||
cur["lines_found"] = int(line[3:] or 0)
|
||||
elif line.startswith("LH:"):
|
||||
cur["lines_hit"] = int(line[3:] or 0)
|
||||
elif line.startswith("FNF:"):
|
||||
cur["funcs_found"] = int(line[4:] or 0)
|
||||
elif line.startswith("FNH:"):
|
||||
cur["funcs_hit"] = int(line[4:] or 0)
|
||||
elif line == "end_of_record":
|
||||
lf = cur["lines_found"]
|
||||
cur["pct"] = round(100.0 * cur["lines_hit"] / lf, 1) if lf else None
|
||||
files.append(cur)
|
||||
cur = None
|
||||
tot_f = sum(f["lines_found"] for f in files)
|
||||
tot_h = sum(f["lines_hit"] for f in files)
|
||||
totals = {"lines_found": tot_f, "lines_hit": tot_h,
|
||||
"pct": round(100.0 * tot_h / tot_f, 1) if tot_f else None}
|
||||
files.sort(key=lambda f: (f["pct"] if f["pct"] is not None else 101.0,
|
||||
f["path"]))
|
||||
return files, totals
|
||||
|
||||
|
||||
def cpp_coverage(repo, target):
|
||||
cov = {"name": "C++", "avail": False, "pct": None, "files": [],
|
||||
"note": "not instrumented (rebuild with --cpp-coverage)"}
|
||||
build = os.path.join(repo, "Build", target)
|
||||
gcno = []
|
||||
for root, _, files in os.walk(build):
|
||||
for fn in files:
|
||||
if fn.endswith(".gcno"):
|
||||
gcno.append(os.path.join(root, fn))
|
||||
if not gcno:
|
||||
return cov
|
||||
# lcov 2.x is strict by default; tolerate the benign mismatches that arise
|
||||
# from mixing instrumented project objects with non-instrumented MARTe2/STL
|
||||
# headers, and never let a single bad file abort the whole capture.
|
||||
ign = ["--ignore-errors",
|
||||
"mismatch,source,gcov,unused,empty,negative,unsupported,inconsistent"]
|
||||
raw = os.path.join(build, "coverage_raw.info")
|
||||
rc, out, err = _run(["lcov", "--capture", "--directory", build,
|
||||
"--output-file", raw, "--quiet"] + ign, timeout=900)
|
||||
if rc != 0 or not os.path.exists(raw):
|
||||
cov["note"] = "lcov capture failed: " + (err or out or "")[-160:]
|
||||
return cov
|
||||
# Keep only this repo's own sources so the number reflects project code,
|
||||
# not the MARTe2 framework headers dragged in by templates/inlines.
|
||||
info = os.path.join(build, "coverage.info")
|
||||
rc2, _, e2 = _run(["lcov", "--extract", raw,
|
||||
os.path.join(repo, "Source", "*"),
|
||||
os.path.join(repo, "Test", "*"),
|
||||
"--output-file", info, "--quiet"] + ign, timeout=300)
|
||||
summ_file = info if (rc2 == 0 and os.path.exists(info)) else raw
|
||||
# Parse the tracefile directly for per-file detail; this also yields the
|
||||
# aggregate so the headline number and the per-file table are consistent.
|
||||
fdetail, totals = _parse_lcov_info(summ_file, repo)
|
||||
if totals["pct"] is not None:
|
||||
cov.update(avail=True, pct=totals["pct"], files=fdetail,
|
||||
lines_found=totals["lines_found"],
|
||||
lines_hit=totals["lines_hit"],
|
||||
note="lcov (project sources)" if summ_file == info else "lcov")
|
||||
return cov
|
||||
# Fall back to lcov --summary if the tracefile had no parseable line data.
|
||||
rc3, summ, _ = _run(["lcov", "--summary", summ_file] + ign)
|
||||
m = re.search(r"lines[.\s]+:\s+([\d.]+)%", summ)
|
||||
if m:
|
||||
cov.update(avail=True, pct=float(m.group(1)),
|
||||
note="lcov (project sources)" if summ_file == info else "lcov")
|
||||
else:
|
||||
cov["note"] = "lcov summary unparsed"
|
||||
return cov
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description="Collect unit tests + coverage")
|
||||
p.add_argument("--repo", required=True)
|
||||
p.add_argument("--target", default="x86-linux")
|
||||
p.add_argument("--out", required=True)
|
||||
p.add_argument("--work", default=None,
|
||||
help="scratch dir for *.xml/cover files (default: --out)")
|
||||
p.add_argument("--cpp-coverage", action="store_true")
|
||||
args = p.parse_args()
|
||||
os.makedirs(args.out, exist_ok=True)
|
||||
work = args.work or args.out
|
||||
os.makedirs(work, exist_ok=True)
|
||||
chain_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
client_dir = os.path.join(chain_dir, "client")
|
||||
gtest_bin = os.path.join(args.repo, "Build", args.target, "GTest", "MainGTest.ex")
|
||||
|
||||
suites = [gtest_suite(gtest_bin, work),
|
||||
go_suite(client_dir, work),
|
||||
py_suite(chain_dir, work)]
|
||||
totals = {k: sum(s.get(k, 0) for s in suites)
|
||||
for k in ("total", "passed", "failed", "skipped")}
|
||||
ut = {"suites": suites, "totals": totals,
|
||||
"ok": all(s["ok"] for s in suites if s["avail"])}
|
||||
with open(os.path.join(args.out, "unit_tests.json"), "w") as f:
|
||||
json.dump(ut, f, indent=2)
|
||||
|
||||
langs = []
|
||||
py = next(s for s in suites if s["lang"] == "python")
|
||||
go = next(s for s in suites if s["lang"] == "go")
|
||||
langs.append({"name": "Python", "avail": py.get("cov_pct") is not None,
|
||||
"pct": py.get("cov_pct"), "note": "coverage.py"})
|
||||
langs.append({"name": "Go", "avail": go.get("cov_pct") is not None,
|
||||
"pct": go.get("cov_pct"), "note": "go test -cover"})
|
||||
cpp = cpp_coverage(args.repo, args.target) if args.cpp_coverage else \
|
||||
{"name": "C++", "avail": False, "pct": None, "note": "skipped (use --cpp-coverage)"}
|
||||
langs.append(cpp)
|
||||
with open(os.path.join(args.out, "coverage.json"), "w") as f:
|
||||
json.dump({"languages": langs}, f, indent=2)
|
||||
|
||||
print(f"unit_tests: {totals['passed']}/{totals['total']} pass "
|
||||
f"({totals['failed']} fail, {totals['skipped']} skip)")
|
||||
print("coverage: " + ", ".join(
|
||||
f"{l['name']}={l['pct']}%" if l["pct"] is not None else f"{l['name']}=n/a"
|
||||
for l in langs))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -90,6 +90,8 @@ def write_marte_cfg(scenario, path, input_bin, tap_bin=None):
|
||||
srcs = scenario["sources"]
|
||||
want_tap = scenario["oracle"] in ("fed", "both") and tap_bin is not None
|
||||
|
||||
_row_dt, _num_rows, producer_hz, _loop_hz = S.geometry(scenario)
|
||||
|
||||
gams = [] # +Functions entries
|
||||
datas = [] # +Data entries
|
||||
thread_funcs = ["TimerGAM"]
|
||||
@@ -98,7 +100,7 @@ def write_marte_cfg(scenario, path, input_bin, tap_bin=None):
|
||||
gams.append(
|
||||
" +TimerGAM = { Class = IOGAM "
|
||||
"InputSignals = { Counter = { DataSource = ReaderTimer Type = uint32 } "
|
||||
f"Time = {{ Frequency = {PRODUCER_HZ} DataSource = ReaderTimer Type = uint32 }} }} "
|
||||
f"Time = {{ Frequency = {producer_hz} DataSource = ReaderTimer Type = uint32 }} }} "
|
||||
"OutputSignals = { Counter = { DataSource = DDB Type = uint32 } "
|
||||
"Time = { DataSource = DDB Type = uint32 } } }")
|
||||
|
||||
|
||||
+17
-15
@@ -51,19 +51,19 @@ NUM_ROWS = S.NUM_ROWS # producer cycles written to the FileReader input
|
||||
ROW_DT = S.ROW_DT # seconds per producer cycle (row); 1 kHz producer
|
||||
|
||||
|
||||
def _sample_dt(sig):
|
||||
def _sample_dt(sig, row_dt=ROW_DT):
|
||||
"""Per-element time spacing (s) for a signal."""
|
||||
if sig["sampling_rate"]:
|
||||
return 1.0 / sig["sampling_rate"]
|
||||
e = sig["elements"]
|
||||
return ROW_DT / e if e > 1 else ROW_DT
|
||||
return row_dt / e if e > 1 else row_dt
|
||||
|
||||
|
||||
def _sample_times(sig):
|
||||
"""Flattened intended sample times (s): NUM_ROWS*elements values."""
|
||||
def _sample_times(sig, row_dt=ROW_DT, num_rows=NUM_ROWS):
|
||||
"""Flattened intended sample times (s): num_rows*elements values."""
|
||||
e = sig["elements"]
|
||||
sdt = _sample_dt(sig)
|
||||
rows = np.arange(NUM_ROWS, dtype=np.float64).reshape(-1, 1) * ROW_DT
|
||||
sdt = _sample_dt(sig, row_dt)
|
||||
rows = np.arange(num_rows, dtype=np.float64).reshape(-1, 1) * row_dt
|
||||
cols = np.arange(e, dtype=np.float64).reshape(1, -1) * sdt
|
||||
return (rows + cols).reshape(-1)
|
||||
|
||||
@@ -99,15 +99,16 @@ def _native(sig, vals):
|
||||
|
||||
def build_ground_truth(scenario):
|
||||
"""Return {"<src>:<sig>": gt_dict} for every signal in the scenario."""
|
||||
row_dt, num_rows, _ph, _lh = S.geometry(scenario)
|
||||
gt = {}
|
||||
for src in scenario["sources"]:
|
||||
for sig in src["signals"]:
|
||||
t = _sample_times(sig)
|
||||
t = _sample_times(sig, row_dt, num_rows)
|
||||
v = _native(sig, _values(sig, t))
|
||||
gt[f"{src['id']}:{sig['name']}"] = {
|
||||
"t": t, "v": v, "dt": _sample_dt(sig),
|
||||
"t": t, "v": v, "dt": _sample_dt(sig, row_dt),
|
||||
"formula": sig["formula"], "freq": sig["freq"],
|
||||
"elements": sig["elements"], "rows": NUM_ROWS,
|
||||
"elements": sig["elements"], "rows": num_rows,
|
||||
"type": sig["type"], "quant": sig["quant"],
|
||||
"range_min": sig["range_min"], "range_max": sig["range_max"],
|
||||
"is_time": sig["is_time"],
|
||||
@@ -126,25 +127,26 @@ def write_input(scenario, path):
|
||||
"""
|
||||
os.makedirs(os.path.dirname(os.path.abspath(path)), exist_ok=True)
|
||||
gt = build_ground_truth(scenario)
|
||||
row_dt, num_rows, _ph, _lh = S.geometry(scenario)
|
||||
|
||||
# write each source to its own file: <path> for src[0], <path>.<srcid> else.
|
||||
written = {}
|
||||
for i, src in enumerate(scenario["sources"]):
|
||||
p = path if i == 0 else f"{path}.{src['id']}"
|
||||
_write_source_bin(src, p)
|
||||
_write_source_bin(src, p, row_dt, num_rows)
|
||||
written[src["id"]] = p
|
||||
gt["_files"] = written
|
||||
return gt
|
||||
|
||||
|
||||
def _write_source_bin(src, path):
|
||||
def _write_source_bin(src, path, row_dt=ROW_DT, num_rows=NUM_ROWS):
|
||||
sigs = src["signals"]
|
||||
# per-signal native 2D arrays [NUM_ROWS, elements]
|
||||
# per-signal native 2D arrays [num_rows, elements]
|
||||
cols = {}
|
||||
for sig in sigs:
|
||||
t = _sample_times(sig)
|
||||
t = _sample_times(sig, row_dt, num_rows)
|
||||
v = _native(sig, _values(sig, t))
|
||||
cols[sig["name"]] = v.reshape(NUM_ROWS, sig["elements"])
|
||||
cols[sig["name"]] = v.reshape(num_rows, sig["elements"])
|
||||
|
||||
with open(path, "wb") as f:
|
||||
f.write(struct.pack("<I", len(sigs)))
|
||||
@@ -153,7 +155,7 @@ def _write_source_bin(src, path):
|
||||
name = (sig["name"] + "\0").encode()
|
||||
f.write((name + b"\0" * 32)[:32])
|
||||
f.write(struct.pack("<I", sig["elements"]))
|
||||
for r in range(NUM_ROWS):
|
||||
for r in range(num_rows):
|
||||
for sig in sigs:
|
||||
f.write(cols[sig["name"]][r].tobytes())
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
proc_perf.py — Snapshot a live process's CPU time and peak memory from /proc.
|
||||
|
||||
Usage: proc_perf.py <pid> <label> <out.json>
|
||||
|
||||
Reads /proc/<pid>/stat (utime+stime, in clock ticks) and /proc/<pid>/status
|
||||
(VmHWM = peak resident set, VmRSS = current) *while the process is alive* — peak
|
||||
RSS is only legible before the process exits, so the orchestrator calls this just
|
||||
before tearing the stack down. Emits a small JSON record:
|
||||
|
||||
{"label": ..., "avail": true, "cpu_s": float, "peak_rss_kb": int,
|
||||
"rss_kb": int, "threads": int}
|
||||
|
||||
If the process is already gone, writes {"label": ..., "avail": false}.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def _clk_tck():
|
||||
try:
|
||||
return os.sysconf("SC_CLK_TCK") or 100
|
||||
except (ValueError, OSError):
|
||||
return 100
|
||||
|
||||
|
||||
def snapshot(pid):
|
||||
stat_p = f"/proc/{pid}/stat"
|
||||
status_p = f"/proc/{pid}/status"
|
||||
if not os.path.exists(stat_p):
|
||||
return {"avail": False}
|
||||
try:
|
||||
with open(stat_p) as f:
|
||||
raw = f.read()
|
||||
# The comm field is parenthesised and may contain spaces/parens, so split
|
||||
# on the final ')': everything after it is space-separated, with state as
|
||||
# the first token. utime/stime are overall fields 14/15 → indices 11/12
|
||||
# of the post-')' tokens (pid + comm consumed before the split).
|
||||
after = raw[raw.rindex(")") + 1:].split()
|
||||
utime = int(after[11])
|
||||
stime = int(after[12])
|
||||
cpu_s = (utime + stime) / float(_clk_tck())
|
||||
rec: dict = {"avail": True, "cpu_s": cpu_s}
|
||||
with open(status_p) as f:
|
||||
for line in f:
|
||||
if line.startswith("VmHWM:"):
|
||||
rec["peak_rss_kb"] = int(line.split()[1])
|
||||
elif line.startswith("VmRSS:"):
|
||||
rec["rss_kb"] = int(line.split()[1])
|
||||
elif line.startswith("Threads:"):
|
||||
rec["threads"] = int(line.split()[1])
|
||||
return rec
|
||||
except (OSError, ValueError, IndexError):
|
||||
return {"avail": False}
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
print("usage: proc_perf.py <pid> <label> <out.json>", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
pid, label, out = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
rec = snapshot(pid)
|
||||
rec["label"] = label
|
||||
with open(out, "w") as f:
|
||||
json.dump(rec, f)
|
||||
if rec.get("avail"):
|
||||
print(f"perf {label}: cpu={rec.get('cpu_s', 0):.2f}s "
|
||||
f"peakRSS={rec.get('peak_rss_kb', 0)/1024:.1f}MB")
|
||||
else:
|
||||
print(f"perf {label}: unavailable (process gone)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,306 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
report_build.py — Consolidate the E2E run into report_data.json (+ trend plots).
|
||||
|
||||
Inputs (paths via flags):
|
||||
* results.json — per-scenario status + waveform metrics (orchestrator)
|
||||
* perf_<id>_*.json — per-scenario CPU/peak-RSS snapshots (proc_perf.py)
|
||||
* unit_tests.json — GTest/Go/Python suite results (collect.py)
|
||||
* coverage.json — per-language coverage (collect.py)
|
||||
|
||||
Outputs (into --out):
|
||||
* report_data.json — everything the Typst template renders, including a
|
||||
``regression`` block that diffs this run's headline metrics against the
|
||||
previous entry in history.jsonl (progression ▲ / regression ▼).
|
||||
* history.jsonl — appended one line of headline metrics per run.
|
||||
* trend_*.png — pass-rate / coverage / fidelity / memory over runs.
|
||||
|
||||
Throughput is derived as recorded-samples / recording-duration. Memory is the
|
||||
peak resident set (VmHWM). All inputs are optional: a missing artifact degrades
|
||||
to nulls so a partial run still produces a report.
|
||||
"""
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt # noqa: E402
|
||||
|
||||
REC_DUR_S = 4.0 # client -dur; samples/sec denominator
|
||||
|
||||
|
||||
def _load(path, default=None):
|
||||
if path and os.path.exists(path):
|
||||
try:
|
||||
return json.load(open(path))
|
||||
except (ValueError, OSError):
|
||||
return default
|
||||
return default
|
||||
|
||||
|
||||
def _git_sha(repo):
|
||||
try:
|
||||
return subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=repo,
|
||||
capture_output=True, text=True, timeout=10).stdout.strip()
|
||||
except (subprocess.SubprocessError, OSError):
|
||||
return "unknown"
|
||||
|
||||
|
||||
def _scenario_perf(work, sid):
|
||||
out = {}
|
||||
for role in ("hub", "marte"):
|
||||
rec = _load(os.path.join(work, f"perf_{sid}_{role}.json"), {})
|
||||
if rec and rec.get("avail"):
|
||||
out[role] = {"cpu_s": round(rec.get("cpu_s", 0.0), 3),
|
||||
"peak_rss_mb": round(rec.get("peak_rss_kb", 0) / 1024.0, 1),
|
||||
"threads": rec.get("threads")}
|
||||
return out
|
||||
|
||||
|
||||
def _scenario_descs():
|
||||
"""id -> human description, imported from the scenario matrix (best effort)."""
|
||||
try:
|
||||
from scenarios import SCENARIOS
|
||||
return {s["id"]: s.get("desc") for s in SCENARIOS}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def build_e2e(results, work):
|
||||
descs = _scenario_descs()
|
||||
scen = []
|
||||
corrs, rss_vals, cpu_vals, tput_vals = [], [], [], []
|
||||
for r in results.get("scenarios", []):
|
||||
sid = r["id"]
|
||||
metrics = r.get("metrics", {})
|
||||
sigs = []
|
||||
nrecv_total = 0
|
||||
for key, m in (metrics.get("signals", {}) or {}).items():
|
||||
nrecv_total += int(m.get("n_recv", 0) or 0)
|
||||
if "corr" in m:
|
||||
corrs.append(m["corr"])
|
||||
sigs.append({
|
||||
"key": key, "pass": m.get("pass"),
|
||||
"type": m.get("type"), "quant": m.get("quant"),
|
||||
"max_abs_err": m.get("max_abs_err"),
|
||||
"corr": m.get("corr"), "nrmse": m.get("nrmse"),
|
||||
"fidelity_ok": m.get("fidelity_ok"), "shape_ok": m.get("shape_ok"),
|
||||
"n_recv": m.get("n_recv"),
|
||||
})
|
||||
perf = _scenario_perf(work, sid)
|
||||
for role in perf.values():
|
||||
if role.get("peak_rss_mb"):
|
||||
rss_vals.append(role["peak_rss_mb"])
|
||||
if role.get("cpu_s"):
|
||||
cpu_vals.append(role["cpu_s"])
|
||||
tput = round(nrecv_total / REC_DUR_S, 1) if nrecv_total else 0.0
|
||||
if tput:
|
||||
tput_vals.append(tput)
|
||||
client = metrics.get("client", {}) or {}
|
||||
# waveform overview image (plots.py writes it into --work); record the
|
||||
# basename only when present so the Typst template can embed it without
|
||||
# tripping over a missing file (Typst read() throws on absence).
|
||||
wave_img = f"wave_{sid}.png"
|
||||
has_wave = os.path.exists(os.path.join(work, wave_img))
|
||||
scen.append({
|
||||
"id": sid, "status": r.get("status"),
|
||||
"desc": descs.get(sid),
|
||||
"known_issue": r.get("known_issue"),
|
||||
"signals": sigs, "perf": perf, "throughput_sps": tput,
|
||||
"live_frames": (client.get("live", {}) or {}).get("frames"),
|
||||
"rollup": client.get("_rollup", {}),
|
||||
# detailed client behavioural checks (chain-client checks_<id>.json),
|
||||
# surfaced so the report can show real zoom ranges + trigger captures
|
||||
# rather than only the pass/fail rollup booleans.
|
||||
"zoom": client.get("zoom", []) or [],
|
||||
"window": client.get("window", {}) or {},
|
||||
"trigger": client.get("trigger", []) or [],
|
||||
"wave_img": wave_img if has_wave else None,
|
||||
})
|
||||
agg = {
|
||||
"mean_corr": round(sum(corrs) / len(corrs), 4) if corrs else None,
|
||||
"mean_peak_rss_mb": round(sum(rss_vals) / len(rss_vals), 1) if rss_vals else None,
|
||||
"mean_cpu_s": round(sum(cpu_vals) / len(cpu_vals), 3) if cpu_vals else None,
|
||||
"mean_throughput_sps": round(sum(tput_vals) / len(tput_vals), 1) if tput_vals else None,
|
||||
}
|
||||
npass = sum(1 for s in scen if s["status"] == "PASS")
|
||||
nfail = sum(1 for s in scen if s["status"] == "FAIL")
|
||||
nskip = sum(1 for s in scen if s["status"] == "SKIP")
|
||||
nxfail = sum(1 for s in scen if s["status"] == "XFAIL")
|
||||
nxpass = sum(1 for s in scen if s["status"] == "XPASS")
|
||||
return {
|
||||
"overall": results.get("overall", "FAIL"),
|
||||
"n_pass": npass, "n_fail": nfail, "n_skip": nskip,
|
||||
"n_xfail": nxfail, "n_xpass": nxpass,
|
||||
"scenarios": scen, "agg": agg,
|
||||
}
|
||||
|
||||
|
||||
def headline(e2e, ut, cov):
|
||||
cov_by = {c["name"]: c.get("pct") for c in cov.get("languages", [])}
|
||||
t = ut.get("totals", {})
|
||||
return {
|
||||
"e2e_pass": e2e["n_pass"], "e2e_fail": e2e["n_fail"],
|
||||
"e2e_xfail": e2e.get("n_xfail", 0), "e2e_xpass": e2e.get("n_xpass", 0),
|
||||
"e2e_total": (e2e["n_pass"] + e2e["n_fail"] + e2e["n_skip"]
|
||||
+ e2e.get("n_xfail", 0) + e2e.get("n_xpass", 0)),
|
||||
"unit_pass": t.get("passed", 0), "unit_fail": t.get("failed", 0),
|
||||
"unit_total": t.get("total", 0),
|
||||
"cov_python": cov_by.get("Python"), "cov_go": cov_by.get("Go"),
|
||||
"cov_cpp": cov_by.get("C++"),
|
||||
"mean_corr": e2e["agg"]["mean_corr"],
|
||||
"mean_peak_rss_mb": e2e["agg"]["mean_peak_rss_mb"],
|
||||
"mean_cpu_s": e2e["agg"]["mean_cpu_s"],
|
||||
"mean_throughput_sps": e2e["agg"]["mean_throughput_sps"],
|
||||
}
|
||||
|
||||
|
||||
# field → "higher is better" (True), "lower is better" (False)
|
||||
_DIRECTION = {
|
||||
"e2e_pass": True, "e2e_fail": False, "unit_pass": True, "unit_fail": False,
|
||||
"cov_python": True, "cov_go": True, "cov_cpp": True, "mean_corr": True,
|
||||
"mean_peak_rss_mb": False, "mean_cpu_s": False, "mean_throughput_sps": True,
|
||||
}
|
||||
_LABELS = {
|
||||
"e2e_pass": "E2E scenarios passed", "e2e_fail": "E2E scenarios failed",
|
||||
"unit_pass": "Unit tests passed", "unit_fail": "Unit tests failed",
|
||||
"cov_python": "Python coverage %", "cov_go": "Go coverage %",
|
||||
"cov_cpp": "C++ coverage %", "mean_corr": "Mean sine corr",
|
||||
"mean_peak_rss_mb": "Mean peak RSS (MB)", "mean_cpu_s": "Mean CPU (s)",
|
||||
"mean_throughput_sps": "Mean throughput (samp/s)",
|
||||
}
|
||||
|
||||
|
||||
def regression(curr, prev):
|
||||
rows = []
|
||||
for k, label in _LABELS.items():
|
||||
c = curr.get(k)
|
||||
p = prev.get(k) if prev else None
|
||||
better = None
|
||||
delta = None
|
||||
if isinstance(c, (int, float)) and isinstance(p, (int, float)):
|
||||
delta = round(c - p, 4)
|
||||
if delta == 0:
|
||||
better = None
|
||||
else:
|
||||
better = (delta > 0) == _DIRECTION[k]
|
||||
rows.append({"name": label, "key": k, "current": c, "previous": p,
|
||||
"delta": delta, "better": better,
|
||||
"higher_better": _DIRECTION[k]})
|
||||
return rows
|
||||
|
||||
|
||||
def trend_plots(history, out):
|
||||
if not history:
|
||||
return []
|
||||
xs = list(range(len(history)))
|
||||
labels = [h.get("ts_short", str(i)) for i, h in enumerate(history)]
|
||||
made = []
|
||||
|
||||
def _plot(fname, series, title, ylabel):
|
||||
ys = [[h.get(k) for h in history] for _, k in series]
|
||||
if all(all(v is None for v in y) for y in ys):
|
||||
return
|
||||
fig, ax = plt.subplots(figsize=(7, 3))
|
||||
for (lbl, _), y in zip(series, ys):
|
||||
xp = [x for x, v in zip(xs, y) if v is not None]
|
||||
yp = [v for v in y if v is not None]
|
||||
if yp:
|
||||
ax.plot(xp, yp, "o-", label=lbl)
|
||||
ax.set_title(title)
|
||||
ax.set_ylabel(ylabel)
|
||||
ax.set_xticks(xs)
|
||||
ax.set_xticklabels(labels, rotation=45, ha="right", fontsize=7)
|
||||
ax.grid(alpha=0.3)
|
||||
ax.legend(fontsize=8)
|
||||
fig.tight_layout()
|
||||
p = os.path.join(out, fname)
|
||||
fig.savefig(p, dpi=110)
|
||||
plt.close(fig)
|
||||
made.append(p)
|
||||
|
||||
_plot("trend_tests.png",
|
||||
[("E2E pass", "e2e_pass"), ("Unit pass", "unit_pass")],
|
||||
"Passing tests over runs", "count")
|
||||
_plot("trend_coverage.png",
|
||||
[("Python", "cov_python"), ("Go", "cov_go"), ("C++", "cov_cpp")],
|
||||
"Code coverage over runs", "% covered")
|
||||
_plot("trend_fidelity.png", [("Mean sine corr", "mean_corr")],
|
||||
"Waveform fidelity over runs", "correlation")
|
||||
_plot("trend_perf.png",
|
||||
[("Peak RSS (MB)", "mean_peak_rss_mb"), ("CPU (s)", "mean_cpu_s")],
|
||||
"Resource use over runs", "value")
|
||||
return made
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="Build E2E report_data.json")
|
||||
ap.add_argument("--repo", required=True)
|
||||
ap.add_argument("--results", required=True)
|
||||
ap.add_argument("--work", required=True)
|
||||
ap.add_argument("--out", required=True)
|
||||
args = ap.parse_args()
|
||||
os.makedirs(args.out, exist_ok=True)
|
||||
|
||||
results = _load(args.results, {"overall": "FAIL", "scenarios": []})
|
||||
ut = _load(os.path.join(args.out, "unit_tests.json"), {"suites": [], "totals": {}})
|
||||
cov = _load(os.path.join(args.out, "coverage.json"), {"languages": []})
|
||||
|
||||
e2e = build_e2e(results, args.work)
|
||||
now = datetime.datetime.now()
|
||||
meta = {"timestamp": now.isoformat(timespec="seconds"),
|
||||
"ts_short": now.strftime("%m-%d %H:%M"),
|
||||
"git_sha": _git_sha(args.repo), "target": "x86-linux"}
|
||||
|
||||
hl = headline(e2e, ut, cov)
|
||||
|
||||
# history: read previous, then append current
|
||||
hist_path = os.path.join(args.out, "history.jsonl")
|
||||
history = []
|
||||
if os.path.exists(hist_path):
|
||||
for line in open(hist_path):
|
||||
line = line.strip()
|
||||
if line:
|
||||
try:
|
||||
history.append(json.loads(line))
|
||||
except ValueError:
|
||||
pass
|
||||
prev = history[-1] if history else None
|
||||
reg = regression(hl, prev)
|
||||
|
||||
entry = dict(hl)
|
||||
entry["timestamp"] = meta["timestamp"]
|
||||
entry["ts_short"] = meta["ts_short"]
|
||||
entry["git_sha"] = meta["git_sha"]
|
||||
entry["overall"] = e2e["overall"]
|
||||
with open(hist_path, "a") as f:
|
||||
f.write(json.dumps(entry) + "\n")
|
||||
history.append(entry)
|
||||
|
||||
plots = [os.path.basename(p) for p in trend_plots(history, args.out)]
|
||||
|
||||
doc = {
|
||||
"meta": meta, "e2e": e2e, "unit_tests": ut,
|
||||
"coverage": cov, "regression": reg, "headline": hl,
|
||||
"trend_plots": plots, "history_len": len(history),
|
||||
"is_first_run": prev is None,
|
||||
}
|
||||
with open(os.path.join(args.out, "report_data.json"), "w") as f:
|
||||
json.dump(doc, f, indent=2)
|
||||
|
||||
print(f"report_data.json: e2e {e2e['n_pass']}/{e2e['n_pass']+e2e['n_fail']+e2e['n_skip']}"
|
||||
f" pass, units {hl['unit_pass']}/{hl['unit_total']}, "
|
||||
f"cov py={hl['cov_python']} go={hl['cov_go']} cpp={hl['cov_cpp']}")
|
||||
if prev:
|
||||
ups = sum(1 for r in reg if r["better"] is True)
|
||||
downs = sum(1 for r in reg if r["better"] is False)
|
||||
print(f"regression vs previous run: {ups} improved, {downs} regressed")
|
||||
else:
|
||||
print("regression: first run (baseline established)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -24,12 +24,14 @@ mkdir -p "${OUT_DIR}" "${WORK}"
|
||||
SKIP_BUILD=0
|
||||
ONLY=""
|
||||
PDF_ONLY=0
|
||||
CPP_COV=0
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--skip-build) SKIP_BUILD=1 ;;
|
||||
--only) shift; ONLY="$1" ;;
|
||||
--pdf-only) PDF_ONLY=1 ;;
|
||||
--help|-h) echo "Usage: $0 [--skip-build] [--only <id>] [--pdf-only]"; exit 0 ;;
|
||||
--cpp-coverage) CPP_COV=1 ;;
|
||||
--help|-h) echo "Usage: $0 [--skip-build] [--only <id>] [--pdf-only] [--cpp-coverage]"; exit 0 ;;
|
||||
*) echo "unknown arg $1" >&2; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
@@ -156,6 +158,9 @@ while IFS='|' read -r ID WSPORT UDPPORT NET ORACLE TRIG CHECKS; do
|
||||
timeout 120 "${MARTE_APP}" -l RealTimeLoader -f "${MCFG}" -s Running > "${APP_LOG}" 2>&1 &
|
||||
APP_PID=$!
|
||||
sleep 1
|
||||
# APP_PID is the `timeout` wrapper; perf must target the real MARTeApp child.
|
||||
APP_PERF_PID="$(pgrep -P "${APP_PID}" 2>/dev/null | head -1)"
|
||||
[ -z "${APP_PERF_PID}" ] && APP_PERF_PID="${APP_PID}"
|
||||
|
||||
TRIGARG=""
|
||||
[ -n "${TRIG}" ] && TRIGARG="-trigsig ${TRIG}"
|
||||
@@ -166,6 +171,11 @@ while IFS='|' read -r ID WSPORT UDPPORT NET ORACLE TRIG CHECKS; do
|
||||
echo " client FAILED (see client_${ID}.log)"
|
||||
tail -3 "${OUT_DIR}/client_${ID}.log" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
# Snapshot CPU/peak-RSS while the stack is still alive (peak RSS is only
|
||||
# legible before exit), then tear it down.
|
||||
[ -n "${HUB_PID}" ] && ${PY} "${SCRIPT_DIR}/proc_perf.py" "${HUB_PID}" streamhub "${WORK}/perf_${ID}_hub.json" || true
|
||||
[ -n "${APP_PERF_PID}" ] && ${PY} "${SCRIPT_DIR}/proc_perf.py" "${APP_PERF_PID}" marte "${WORK}/perf_${ID}_marte.json" || true
|
||||
cleanup
|
||||
|
||||
# validate + plot
|
||||
@@ -183,33 +193,99 @@ trap - EXIT
|
||||
cleanup
|
||||
|
||||
# ── Aggregate results.json ───────────────────────────────────────────────────
|
||||
WORK="${WORK}" OUT_DIR="${OUT_DIR}" SCEN_IDS="${SCEN_IDS}" ${PY} - <<'PY'
|
||||
import json, os
|
||||
# Scenarios carrying a `known_issue` marker exercise a documented, not-yet-fixed
|
||||
# chain gap: a raw FAIL is reclassified XFAIL (expected failure — does not break
|
||||
# the green baseline) and a raw PASS becomes XPASS (the bug was unexpectedly
|
||||
# fixed; the marker should be dropped). Overall is PASS when nothing FAILs and
|
||||
# nothing unexpectedly XPASSes.
|
||||
WORK="${WORK}" OUT_DIR="${OUT_DIR}" SCEN_IDS="${SCEN_IDS}" \
|
||||
SCRIPT_DIR="${SCRIPT_DIR}" ${PY} - <<'PY'
|
||||
import json, os, sys
|
||||
work = os.environ["WORK"]; out = os.environ["OUT_DIR"]
|
||||
ids = os.environ["SCEN_IDS"].split()
|
||||
sys.path.insert(0, os.environ["SCRIPT_DIR"])
|
||||
try:
|
||||
from scenarios import SCENARIOS
|
||||
known = {s["id"]: s.get("known_issue") for s in SCENARIOS}
|
||||
except Exception:
|
||||
known = {}
|
||||
results = []
|
||||
for sid in ids:
|
||||
rec = {"id": sid}
|
||||
st = os.path.join(work, f"status_{sid}.txt")
|
||||
rec["status"] = open(st).read().strip() if os.path.exists(st) else "UNKNOWN"
|
||||
raw = open(st).read().strip() if os.path.exists(st) else "UNKNOWN"
|
||||
ki = known.get(sid)
|
||||
if ki:
|
||||
rec["known_issue"] = ki
|
||||
if raw == "FAIL":
|
||||
raw = "XFAIL" # expected failure — documented chain gap
|
||||
elif raw == "PASS":
|
||||
raw = "XPASS" # unexpectedly fixed — drop the marker
|
||||
rec["status"] = raw
|
||||
mp = os.path.join(work, f"metrics_{sid}.json")
|
||||
if os.path.exists(mp):
|
||||
rec["metrics"] = json.load(open(mp))
|
||||
results.append(rec)
|
||||
overall = all(r["status"] in ("PASS", "SKIP") for r in results) and bool(results)
|
||||
# Green when no hard FAIL and no XPASS (an XPASS means a known_issue marker is
|
||||
# now stale and must be removed — surfaced as a failure to force the cleanup).
|
||||
overall = (bool(results)
|
||||
and all(r["status"] in ("PASS", "SKIP", "XFAIL") for r in results))
|
||||
doc = {"overall": "PASS" if overall else "FAIL", "scenarios": results}
|
||||
with open(os.path.join(out, "results.json"), "w") as f:
|
||||
json.dump(doc, f, indent=2)
|
||||
print(f"\nresults.json: {sum(r['status']=='PASS' for r in results)} pass, "
|
||||
f"{sum(r['status']=='FAIL' for r in results)} fail, "
|
||||
f"{sum(r['status']=='SKIP' for r in results)} skip → {doc['overall']}")
|
||||
c = lambda st: sum(r["status"] == st for r in results)
|
||||
print(f"\nresults.json: {c('PASS')} pass, {c('FAIL')} fail, {c('SKIP')} skip, "
|
||||
f"{c('XFAIL')} xfail, {c('XPASS')} xpass → {doc['overall']}")
|
||||
PY
|
||||
|
||||
# ── Optional PDF ─────────────────────────────────────────────────────────────
|
||||
# ── Unit tests + coverage ────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "── Unit tests + coverage ──"
|
||||
|
||||
# Optional C++ line coverage: rebuild the project's libraries + GTest with gcov
|
||||
# instrumentation in place (OPTIM/LFLAGS are the MARTe2-sanctioned override
|
||||
# hooks), let collect.py run the instrumented GTest (emits .gcda) and lcov, then
|
||||
# restore a clean build so later --skip-build runs aren't left instrumented.
|
||||
CPP_COV_FLAG=""
|
||||
if [ "${CPP_COV}" -eq 1 ]; then
|
||||
echo " building instrumented (gcov) libraries + GTest ..."
|
||||
COV_O="--coverage"
|
||||
COV_L="-Wl,--no-as-needed -fPIC --coverage"
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc clean >/dev/null 2>&1 || true
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc core TARGET="${TARGET}" \
|
||||
OPTIM="${COV_O}" LFLAGS="${COV_L}" 2>&1 | tail -1
|
||||
for d in Test/Components/DataSources/UDPStreamer Test/Applications/StreamHub Test/GTest; do
|
||||
make -C "${REPO_ROOT}/${d}" -f Makefile.gcc TARGET="${TARGET}" \
|
||||
OPTIM="${COV_O}" LFLAGS="${COV_L}" 2>&1 | tail -1
|
||||
done
|
||||
CPP_COV_FLAG="--cpp-coverage"
|
||||
fi
|
||||
|
||||
${PY} "${SCRIPT_DIR}/collect.py" --repo "${REPO_ROOT}" --target "${TARGET}" \
|
||||
--out "${OUT_DIR}" --work "${WORK}" ${CPP_COV_FLAG} || true
|
||||
|
||||
if [ "${CPP_COV}" -eq 1 ]; then
|
||||
echo " restoring non-instrumented build ..."
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc clean >/dev/null 2>&1 || true
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc core apps TARGET="${TARGET}" 2>&1 | tail -1
|
||||
(cd "${SCRIPT_DIR}/client" && go build -o chain-client . >/dev/null 2>&1) || true
|
||||
fi
|
||||
|
||||
# ── Consolidated report data (+ history/regression + trend plots) ────────────
|
||||
${PY} "${SCRIPT_DIR}/report_build.py" --repo "${REPO_ROOT}" \
|
||||
--results "${OUT_DIR}/results.json" --work "${WORK}" --out "${OUT_DIR}" || true
|
||||
|
||||
# ── PDF ──────────────────────────────────────────────────────────────────────
|
||||
if command -v typst >/dev/null 2>&1 && [ -f "${SCRIPT_DIR}/E2E_Report.typ" ]; then
|
||||
cp "${SCRIPT_DIR}/E2E_Report.typ" "${OUT_DIR}/" 2>/dev/null || true
|
||||
(cd "${OUT_DIR}" && typst compile E2E_Report.typ E2E_Report.pdf 2>/dev/null) \
|
||||
&& echo "PDF: ${OUT_DIR}/E2E_Report.pdf"
|
||||
# Embedded waveform overviews live in WORK; the template references them by
|
||||
# bare name, so stage them next to report_data.json before compiling.
|
||||
cp "${WORK}"/wave_*.png "${OUT_DIR}/" 2>/dev/null || true
|
||||
if (cd "${OUT_DIR}" && typst compile E2E_Report.typ E2E_Report.pdf); then
|
||||
echo "PDF: ${OUT_DIR}/E2E_Report.pdf"
|
||||
else
|
||||
echo "typst compile failed (report_data.json present at ${OUT_DIR})"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Done — artifacts in ${OUT_DIR} and ${WORK}"
|
||||
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# run_stress.sh — Capacity/stress harness for the streaming chain.
|
||||
#
|
||||
# MARTe2 app (FileReader -> IOGAM -> UDPStreamer)
|
||||
# -> UDPS -> StreamHub(s) -> chain-client(s) (stress: liveness + zoom latency)
|
||||
# -> proc_perf (cpu/peakRSS) -> per-case gate -> stress_results.json
|
||||
#
|
||||
# It sweeps one load axis at a time (signal size/count, subscriber fan-out, source
|
||||
# count, WS-client count, zoom request rate — see stress.py) and gates each case on
|
||||
# survival + liveness (hard) and RSS + zoom-p95 latency (soft). This is the
|
||||
# capacity sibling of run_chain_e2e.sh (which gates waveform correctness).
|
||||
#
|
||||
# Usage: ./run_stress.sh [--skip-build] [--only <id>] [--axis <axis>]
|
||||
set -u
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
TARGET=x86-linux
|
||||
BUILD_DIR="${REPO_ROOT}/Build/${TARGET}"
|
||||
OUT_DIR="${BUILD_DIR}/E2E/chain/stress"
|
||||
WORK="/tmp/chain_stress"
|
||||
mkdir -p "${OUT_DIR}" "${WORK}"
|
||||
|
||||
SKIP_BUILD=0
|
||||
ONLY=""
|
||||
AXIS=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--skip-build) SKIP_BUILD=1 ;;
|
||||
--only) shift; ONLY="$1" ;;
|
||||
--axis) shift; AXIS="$1" ;;
|
||||
--help|-h) echo "Usage: $0 [--skip-build] [--only <id>] [--axis <axis>]"; exit 0 ;;
|
||||
*) echo "unknown arg $1" >&2; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
ENV_SCRIPT="${REPO_ROOT}/env.sh"
|
||||
[ -f "${ENV_SCRIPT}" ] || { echo "ERROR: ${ENV_SCRIPT} not found" >&2; exit 1; }
|
||||
: "${LD_LIBRARY_PATH:=}"
|
||||
source "${ENV_SCRIPT}"
|
||||
|
||||
COMP="${MARTe2_Components_DIR}/Build/${TARGET}/Components"
|
||||
export LD_LIBRARY_PATH="\
|
||||
${BUILD_DIR}/Components/DataSources/UDPStreamer:\
|
||||
${BUILD_DIR}/Components/Interfaces/UDPStream:\
|
||||
${MARTe2_DIR}/Build/${TARGET}/Core:\
|
||||
${COMP}/DataSources/LinuxTimer:\
|
||||
${COMP}/DataSources/FileDataSource:\
|
||||
${COMP}/GAMs/IOGAM:\
|
||||
${LD_LIBRARY_PATH:-}"
|
||||
|
||||
MARTE_APP="${MARTe2_DIR}/Build/${TARGET}/App/MARTeApp.ex"
|
||||
STREAMHUB_EX="${BUILD_DIR}/StreamHub/StreamHub.ex"
|
||||
CLIENT="${SCRIPT_DIR}/client/chain-client"
|
||||
PY="python3"
|
||||
|
||||
# ── Build ────────────────────────────────────────────────────────────────────
|
||||
if [ "${SKIP_BUILD}" -eq 0 ]; then
|
||||
echo "── Building components ──"
|
||||
make -C "${REPO_ROOT}/Source/Components/Interfaces/UDPStream" -f Makefile.gcc TARGET="${TARGET}" 2>&1 | tail -1
|
||||
make -C "${REPO_ROOT}/Source/Components/DataSources/UDPStreamer" -f Makefile.gcc TARGET="${TARGET}" 2>&1 | tail -1
|
||||
make -C "${REPO_ROOT}/Source/Applications/StreamHub" -f Makefile.gcc TARGET="${TARGET}" 2>&1 | tail -1
|
||||
fi
|
||||
if [ ! -x "${CLIENT}" ] || [ "${SKIP_BUILD}" -eq 0 ]; then
|
||||
echo "── Building chain-client ──"
|
||||
(cd "${SCRIPT_DIR}/client" && go build -o chain-client .) || { echo "client build failed"; exit 1; }
|
||||
fi
|
||||
[ -x "${MARTE_APP}" ] || { echo "ERROR: MARTeApp.ex not found at ${MARTE_APP}" >&2; exit 1; }
|
||||
[ -x "${STREAMHUB_EX}" ] || { echo "ERROR: StreamHub.ex not found" >&2; exit 1; }
|
||||
|
||||
# ── Validate the matrix, then run ────────────────────────────────────────────
|
||||
${PY} "${SCRIPT_DIR}/stress.py" >/dev/null || { echo "stress matrix invalid"; exit 1; }
|
||||
|
||||
ARGS=(--marte "${MARTE_APP}" --hub "${STREAMHUB_EX}" --client "${CLIENT}"
|
||||
--work "${WORK}" --out "${OUT_DIR}")
|
||||
[ -n "${ONLY}" ] && ARGS+=(--only "${ONLY}")
|
||||
[ -n "${AXIS}" ] && ARGS+=(--axis "${AXIS}")
|
||||
|
||||
${PY} "${SCRIPT_DIR}/stress_run.py" "${ARGS[@]}"
|
||||
RC=$?
|
||||
|
||||
echo ""
|
||||
echo "Done — results in ${OUT_DIR}/stress_results.json, logs in ${OUT_DIR}"
|
||||
exit ${RC}
|
||||
+370
-5
@@ -49,6 +49,13 @@ Scenario dict schema
|
||||
"oracle": "analytic" | "fed" | "both"
|
||||
"client_checks": subset of ["live","zoom","window","trigger"]
|
||||
"trig_signal": "src:sig" | None # which signal to trigger on
|
||||
"known_issue": str | None # if set, the scenario exercises a
|
||||
# documented, not-yet-fixed chain gap:
|
||||
# a FAIL is reclassified XFAIL (does not
|
||||
# break the baseline) and a PASS becomes
|
||||
# XPASS (the bug is unexpectedly fixed —
|
||||
# time to drop the marker). The string is
|
||||
# the human-readable reason.
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -75,6 +82,14 @@ NP_DTYPE = {
|
||||
"float32": "<f4", "float64": "<f8",
|
||||
}
|
||||
|
||||
# Wire constraints shared with the C++ UDPS layer. The UDPStreamer fragments the
|
||||
# serialised packet into chunks of at most MaxPayloadSize *payload* bytes and
|
||||
# prepends a UDPS_HEADER_SIZE-byte header, so the datagram it hands to sendto() is
|
||||
# MaxPayloadSize+UDPS_HEADER_SIZE bytes. That must not exceed the maximum UDP
|
||||
# payload or sendto() fails with EMSGSIZE.
|
||||
UDPS_HEADER_SIZE = 17 # bytes; mirrors Common/UDP/UDPSProtocol.h
|
||||
MAX_UDP_PAYLOAD = 65507 # 65535 - 20 (IP) - 8 (UDP)
|
||||
|
||||
FLOAT_TYPES = {"float32", "float64"}
|
||||
QUANT_TYPES = {"none", "uint8", "int8", "uint16", "int16"}
|
||||
QUANT_LEVELS = {"uint8": 255, "int8": 254, "uint16": 65535, "int16": 65534}
|
||||
@@ -91,6 +106,20 @@ ROW_DT = 1.0e-3 # seconds per producer cycle (row); 1 kHz producer
|
||||
LOOP_HZ = 1.0 / (NUM_ROWS * ROW_DT) # 5.0 Hz buffer fundamental
|
||||
|
||||
|
||||
def geometry(s):
|
||||
"""Resolve a scenario's producer geometry (per-scenario override or global).
|
||||
|
||||
Returns (row_dt, num_rows, producer_hz, loop_hz). Every data/config/validator
|
||||
consumer reads geometry through here so the override cannot drift apart from
|
||||
the seamless-loop fundamental used by the sine constraint.
|
||||
"""
|
||||
row_dt = s.get("row_dt") or ROW_DT
|
||||
num_rows = s.get("num_rows") or NUM_ROWS
|
||||
producer_hz = s.get("producer_hz") or int(round(1.0 / row_dt))
|
||||
loop_hz = 1.0 / (num_rows * row_dt)
|
||||
return row_dt, num_rows, producer_hz, loop_hz
|
||||
|
||||
|
||||
def _sig(name, type, elements=1, time_mode="PacketTime", time_signal=None,
|
||||
sampling_rate=None, quant="none", range_min=None, range_max=None,
|
||||
unit=None, formula="sine", freq=1.0, is_time=False):
|
||||
@@ -106,6 +135,7 @@ def _sig(name, type, elements=1, time_mode="PacketTime", time_signal=None,
|
||||
def validate_scenario(s):
|
||||
"""Return a list of validity error strings (empty == valid)."""
|
||||
errs = []
|
||||
row_dt, num_rows, _producer_hz, loop_hz = geometry(s)
|
||||
if s.get("network") not in ("unicast", "multicast"):
|
||||
errs.append("network must be unicast|multicast")
|
||||
if s.get("publishing") not in ("Strict", "Accumulate", "Decimate"):
|
||||
@@ -117,6 +147,12 @@ def validate_scenario(s):
|
||||
errs.append("Accumulate needs min_refresh_hz>0")
|
||||
if not s.get("sources"):
|
||||
errs.append("no sources")
|
||||
max_payload = s.get("max_payload")
|
||||
if max_payload is not None and max_payload + UDPS_HEADER_SIZE > MAX_UDP_PAYLOAD:
|
||||
errs.append(
|
||||
f"max_payload {max_payload} + {UDPS_HEADER_SIZE}B header exceeds the "
|
||||
f"{MAX_UDP_PAYLOAD}B UDP datagram limit (sendto EMSGSIZE); "
|
||||
f"cap at {MAX_UDP_PAYLOAD - UDPS_HEADER_SIZE}")
|
||||
for src in s.get("sources", []):
|
||||
if s["network"] == "multicast":
|
||||
if not src.get("multicast_group") or not src.get("data_port"):
|
||||
@@ -145,16 +181,77 @@ def validate_scenario(s):
|
||||
if sig["time_mode"] in ("FirstSample", "LastSample"):
|
||||
if not sig["sampling_rate"] or sig["sampling_rate"] <= 0:
|
||||
errs.append(f"{sig['name']}: First/LastSample needs sampling_rate>0")
|
||||
else:
|
||||
# The per-packet sample window must fit inside one producer
|
||||
# cycle, or successive packets' expanded timestamps overlap
|
||||
# and the hub's binary-search ring (which assumes a sorted
|
||||
# time axis) is corrupted — the s17/s18 failure class.
|
||||
window = (sig["elements"] - 1) / sig["sampling_rate"]
|
||||
if window > row_dt + 1e-12:
|
||||
errs.append(
|
||||
f"{sig['name']}: {sig['time_mode']} window "
|
||||
f"{window * 1e3:.4f} ms > row period {row_dt * 1e3:.4f} ms "
|
||||
f"(non-monotonic ring); raise producer rate or "
|
||||
f"sampling_rate, or lower elements")
|
||||
if sig["formula"] == "sine" and sig.get("freq"):
|
||||
ratio = sig["freq"] / LOOP_HZ
|
||||
ratio = sig["freq"] / loop_hz
|
||||
if abs(ratio - round(ratio)) > 1e-9 or round(ratio) < 1:
|
||||
errs.append(f"{sig['name']}: sine freq {sig['freq']} must be a "
|
||||
f"positive multiple of LOOP_HZ={LOOP_HZ} (seamless loop)")
|
||||
f"positive multiple of LOOP_HZ={loop_hz} (seamless loop)")
|
||||
return errs
|
||||
|
||||
|
||||
# ── Starter set (expanded to the full covering matrix in Task 8) ──────────────
|
||||
SCENARIOS = [
|
||||
# ── Curated covering matrix ───────────────────────────────────────────────────
|
||||
# The first three scenarios are referenced positionally by tests_py.py
|
||||
# (SCENARIOS[0..2]) and are kept verbatim. The remainder is built with the helpers
|
||||
# below, which auto-allocate unique WS/UDP/DATA ports so the matrix can grow
|
||||
# without manual bookkeeping. Coverage goal: every UDPStreamer option *value*
|
||||
# (all 10 types, scalar+array shapes, all four TimeModes, all five quant kinds,
|
||||
# the three publishing modes, unicast+multicast, fragmentation via small payload,
|
||||
# multi-source) appears at least once, plus deliberately chosen high-risk
|
||||
# interactions (decimate+quant+array, accumulate+fullarray, multicast+decimate,
|
||||
# fragmentation+decimate). Non-sine formulas (counter/ramp) are preferred for
|
||||
# pure type/shape coverage because only the fidelity oracle gates them; sine is
|
||||
# used where the shape metric should be tracked. MCAST_GROUP must have a route on
|
||||
# the test host or those scenarios report SKIP (the orchestrator probes it).
|
||||
import itertools
|
||||
|
||||
MCAST_GROUP = "239.0.7.7"
|
||||
_ws = itertools.count(8104)
|
||||
_udp = itertools.count(44616, 2)
|
||||
_data = itertools.count(45616, 2)
|
||||
|
||||
|
||||
def _src(sid, signals, multicast=False):
|
||||
return {
|
||||
"id": sid, "udp_port": next(_udp),
|
||||
"data_port": next(_data) if multicast else None,
|
||||
"multicast_group": MCAST_GROUP if multicast else None,
|
||||
"signals": signals,
|
||||
}
|
||||
|
||||
|
||||
def mk(sid, desc, sources, network="unicast", publishing="Strict",
|
||||
ratio=None, min_refresh_hz=None, max_payload=1400,
|
||||
oracle="analytic", checks=("live", "zoom"), trig=None,
|
||||
known_issue=None, row_dt=None, num_rows=None, producer_hz=None):
|
||||
# row_dt / num_rows / producer_hz override the global producer geometry for
|
||||
# this scenario only (default None == use the suite-wide NUM_ROWS / ROW_DT /
|
||||
# 1 kHz). They are kept together so the per-cycle wall gap (1/producer_hz),
|
||||
# the encoded time-step (row_dt) and the seamless-loop fundamental
|
||||
# (1/(num_rows*row_dt)) stay mutually consistent.
|
||||
return {
|
||||
"id": sid, "desc": desc, "network": network, "publishing": publishing,
|
||||
"ratio": ratio, "min_refresh_hz": min_refresh_hz,
|
||||
"max_payload": max_payload, "ws_port": next(_ws),
|
||||
"sources": sources, "oracle": oracle,
|
||||
"client_checks": list(checks), "trig_signal": trig,
|
||||
"known_issue": known_issue,
|
||||
"row_dt": row_dt, "num_rows": num_rows, "producer_hz": producer_hz,
|
||||
}
|
||||
|
||||
|
||||
_STARTERS = [
|
||||
{
|
||||
"id": "s01_scalar_uint32",
|
||||
"desc": "Single uint32 scalar counter, Strict unicast (type fidelity)",
|
||||
@@ -177,7 +274,8 @@ SCENARIOS = [
|
||||
"id": "s02_array_float32_fullarray",
|
||||
"desc": "100-elem float32 array, FullArray time mode, uint64 ns time array",
|
||||
"network": "unicast", "publishing": "Strict",
|
||||
"ratio": None, "min_refresh_hz": None, "max_payload": 65507,
|
||||
"ratio": None, "min_refresh_hz": None,
|
||||
"max_payload": MAX_UDP_PAYLOAD - UDPS_HEADER_SIZE,
|
||||
"ws_port": 8102,
|
||||
"sources": [{
|
||||
"id": "src", "udp_port": 44612, "data_port": None,
|
||||
@@ -214,11 +312,278 @@ SCENARIOS = [
|
||||
},
|
||||
]
|
||||
|
||||
# ── Type fidelity: one scalar per remaining MARTe type (fidelity-only) ────────
|
||||
_TYPES = [
|
||||
mk("s04_int8_scalar", "int8 scalar counter, type fidelity",
|
||||
[_src("src", [_sig("Cnt", "int8", 1, formula="counter")])]),
|
||||
mk("s05_uint8_scalar", "uint8 scalar counter, type fidelity",
|
||||
[_src("src", [_sig("Cnt", "uint8", 1, formula="counter")])]),
|
||||
mk("s06_int16_scalar", "int16 scalar ramp, type fidelity",
|
||||
[_src("src", [_sig("Ramp", "int16", 1, formula="ramp")])]),
|
||||
mk("s07_uint16_scalar", "uint16 scalar ramp, type fidelity",
|
||||
[_src("src", [_sig("Ramp", "uint16", 1, formula="ramp")])]),
|
||||
mk("s08_int32_scalar", "int32 scalar counter, type fidelity",
|
||||
[_src("src", [_sig("Cnt", "int32", 1, formula="counter")])]),
|
||||
mk("s09_int64_scalar", "int64 scalar counter, type fidelity",
|
||||
[_src("src", [_sig("Cnt", "int64", 1, formula="counter")])]),
|
||||
mk("s10_uint64_scalar", "uint64 scalar counter, type fidelity",
|
||||
[_src("src", [_sig("Cnt", "uint64", 1, formula="counter")])]),
|
||||
mk("s11_float64_scalar", "float64 scalar sine 5 Hz (double-precision path)",
|
||||
[_src("src", [_sig("Sine", "float64", 1, formula="sine", freq=5.0,
|
||||
unit="V")])],
|
||||
checks=("live", "zoom", "trigger"), trig="src:Sine"),
|
||||
]
|
||||
|
||||
# ── Array shapes (NumberOfElements) ──────────────────────────────────────────
|
||||
_ARRAYS = [
|
||||
mk("s12_f32_arr8", "float32 8-elem array sine 5 Hz",
|
||||
[_src("src", [_sig("Wave", "float32", 8, formula="sine", freq=5.0)])]),
|
||||
mk("s13_f32_arr32", "float32 32-elem array sine 10 Hz",
|
||||
[_src("src", [_sig("Wave", "float32", 32, formula="sine", freq=10.0)])]),
|
||||
mk("s14_f64_arr64", "float64 64-elem array ramp",
|
||||
[_src("src", [_sig("Ramp", "float64", 64, formula="ramp")])]),
|
||||
mk("s15_i16_arr16", "int16 16-elem array counter",
|
||||
[_src("src", [_sig("Cnt", "int16", 16, formula="counter")])]),
|
||||
mk("s16_f32_arr256", "float32 256-elem array sine 5 Hz (large frame)",
|
||||
[_src("src", [_sig("Wave", "float32", 256, formula="sine", freq=5.0)])],
|
||||
max_payload=MAX_UDP_PAYLOAD - UDPS_HEADER_SIZE),
|
||||
mk("s39_uint8_arr32", "uint8 32-elem array counter (wrap fidelity)",
|
||||
[_src("src", [_sig("Cnt", "uint8", 32, formula="counter")])]),
|
||||
mk("s40_int8_arr16", "int8 16-elem array counter (wrap fidelity)",
|
||||
[_src("src", [_sig("Cnt", "int8", 16, formula="counter")])]),
|
||||
]
|
||||
|
||||
# ── Time modes (each non-PacketTime mode needs a TimeSignal in the source) ────
|
||||
_TIMEMODES = [
|
||||
# sampling_rate = elements/ROW_DT (8/0.001 = 8000) so the per-cycle window
|
||||
# of 8 samples fills exactly one 1 kHz producer cycle. A smaller rate makes
|
||||
# each cycle's window wider than the inter-cycle gap, so successive windows
|
||||
# overlap and the published timestamps stop being monotonic — which corrupts
|
||||
# the hub's binary-search range/zoom queries (they assume a sorted ring).
|
||||
mk("s17_lastsample", "float32 8-elem LastSample, uint64 ns scalar anchor",
|
||||
[_src("src", [
|
||||
_sig("Tns", "uint64", 1, unit="ns", formula="time_ns", is_time=True),
|
||||
_sig("Data", "float32", 8, time_mode="LastSample",
|
||||
time_signal="Tns", sampling_rate=8000.0, formula="counter"),
|
||||
])]),
|
||||
mk("s18_firstsample", "float32 8-elem FirstSample, uint32 us scalar anchor",
|
||||
[_src("src", [
|
||||
_sig("Tus", "uint32", 1, unit="us", formula="time_us", is_time=True),
|
||||
_sig("Data", "float32", 8, time_mode="FirstSample",
|
||||
time_signal="Tus", sampling_rate=8000.0, formula="counter"),
|
||||
])]),
|
||||
mk("s19_fullarray_f64", "float64 50-elem FullArray sine 5 Hz, uint64 ns time",
|
||||
[_src("src", [
|
||||
_sig("TimeArr", "uint64", 50, unit="ns", formula="time_ns",
|
||||
is_time=True),
|
||||
_sig("Wave", "float64", 50, time_mode="FullArray",
|
||||
time_signal="TimeArr", formula="sine", freq=5.0, unit="V"),
|
||||
])],
|
||||
oracle="both"),
|
||||
mk("s43_fullarray_quant", "float32 16-elem FullArray quant uint16 sine 5 Hz",
|
||||
[_src("src", [
|
||||
_sig("TimeArr", "uint64", 16, unit="ns", formula="time_ns",
|
||||
is_time=True),
|
||||
_sig("Wave", "float32", 16, time_mode="FullArray",
|
||||
time_signal="TimeArr", quant="uint16", range_min=-1.0,
|
||||
range_max=1.0, formula="sine", freq=5.0, unit="V"),
|
||||
])]),
|
||||
]
|
||||
|
||||
# ── Quantization (each QuantizedType, on float signals) ──────────────────────
|
||||
_QUANT = [
|
||||
mk("s20_quant_uint8", "float32 scalar quant uint8 [-1,1] sine 5 Hz",
|
||||
[_src("src", [_sig("Sine", "float32", 1, quant="uint8", range_min=-1.0,
|
||||
range_max=1.0, formula="sine", freq=5.0)])]),
|
||||
mk("s21_quant_int8", "float32 scalar quant int8 [-10,10] sine 5 Hz",
|
||||
[_src("src", [_sig("Sine", "float32", 1, quant="int8", range_min=-10.0,
|
||||
range_max=10.0, formula="sine", freq=5.0)])]),
|
||||
mk("s22_quant_int16", "float32 scalar quant int16 [-100,100] ramp",
|
||||
[_src("src", [_sig("Ramp", "float32", 1, quant="int16", range_min=-100.0,
|
||||
range_max=100.0, formula="ramp")])]),
|
||||
mk("s23_quant_f64_arr", "float64 16-elem quant uint16 [-2,2] sine 5 Hz",
|
||||
[_src("src", [_sig("Wave", "float64", 16, quant="uint16", range_min=-2.0,
|
||||
range_max=2.0, formula="sine", freq=5.0)])]),
|
||||
]
|
||||
|
||||
# ── Publishing modes (Strict covered; Accumulate + Decimate here) ────────────
|
||||
_PUBLISH = [
|
||||
mk("s24_accumulate", "float32 scalar sine 5 Hz, Accumulate @50 Hz refresh",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)])],
|
||||
publishing="Accumulate", min_refresh_hz=50.0),
|
||||
mk("s25_decimate4", "float32 scalar sine 5 Hz, Decimate ratio 4",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)])],
|
||||
publishing="Decimate", ratio=4),
|
||||
mk("s26_decimate10_arr", "float32 8-elem counter, Decimate ratio 10",
|
||||
[_src("src", [_sig("Cnt", "float32", 8, formula="counter")])],
|
||||
publishing="Decimate", ratio=10),
|
||||
mk("s46_accumulate_arr",
|
||||
"Accumulate @200 Hz: accumulated scalar sine + 16-elem array passenger",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0),
|
||||
_sig("Wave", "float32", 16, formula="sine", freq=5.0)])],
|
||||
publishing="Accumulate", min_refresh_hz=200.0),
|
||||
mk("s45_decimate_multisig", "Decimate ratio 2 over a 2-signal source",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0),
|
||||
_sig("Cnt", "uint32", 1, formula="counter")])],
|
||||
publishing="Decimate", ratio=2),
|
||||
]
|
||||
|
||||
# ── Payload size / fragmentation (small MaxPayloadSize vs large array) ───────
|
||||
_PAYLOAD = [
|
||||
mk("s27_frag_f64_128", "float64 128-elem ramp, MaxPayload 512 (fragmented)",
|
||||
[_src("src", [_sig("Ramp", "float64", 128, formula="ramp")])],
|
||||
max_payload=512),
|
||||
mk("s28_frag_f32_100", "float32 100-elem sine 5 Hz, MaxPayload 256 (fragmented)",
|
||||
[_src("src", [_sig("Wave", "float32", 100, formula="sine", freq=5.0)])],
|
||||
max_payload=256),
|
||||
mk("s48_f64_arr_big_payload", "float64 100-elem ramp, MaxPayload 65490 (single frame)",
|
||||
[_src("src", [_sig("Ramp", "float64", 100, formula="ramp")])],
|
||||
max_payload=MAX_UDP_PAYLOAD - UDPS_HEADER_SIZE),
|
||||
]
|
||||
|
||||
# ── Multicast ────────────────────────────────────────────────────────────────
|
||||
_MCAST = [
|
||||
mk("s29_mcast_scalar", "multicast float32 scalar sine 5 Hz",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)],
|
||||
multicast=True)],
|
||||
network="multicast"),
|
||||
mk("s30_mcast_arr_fullarray", "multicast float32 32-elem FullArray sine 5 Hz",
|
||||
[_src("src", [
|
||||
_sig("TimeArr", "uint64", 32, unit="ns", formula="time_ns",
|
||||
is_time=True),
|
||||
_sig("Wave", "float32", 32, time_mode="FullArray",
|
||||
time_signal="TimeArr", formula="sine", freq=5.0),
|
||||
], multicast=True)],
|
||||
network="multicast"),
|
||||
mk("s47_mcast_multisrc", "multicast, two sources (scalar each)",
|
||||
[_src("a", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)],
|
||||
multicast=True),
|
||||
_src("b", [_sig("Cnt", "uint32", 1, formula="counter")],
|
||||
multicast=True)],
|
||||
network="multicast"),
|
||||
]
|
||||
|
||||
# ── Multiple sources (independent UDPStreamer blocks, one hub) ───────────────
|
||||
_MULTISRC = [
|
||||
mk("s31_two_src", "two unicast sources: float32 sine + uint32 counter",
|
||||
[_src("a", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)]),
|
||||
_src("b", [_sig("Cnt", "uint32", 1, formula="counter")])]),
|
||||
mk("s32_three_src", "three unicast sources: int16 ramp / float64 sine / uint8 counter",
|
||||
[_src("a", [_sig("Ramp", "int16", 1, formula="ramp")]),
|
||||
_src("b", [_sig("Sine", "float64", 1, formula="sine", freq=5.0)]),
|
||||
_src("c", [_sig("Cnt", "uint8", 1, formula="counter")])]),
|
||||
]
|
||||
|
||||
# ── High-risk interactions ───────────────────────────────────────────────────
|
||||
_INTERACT = [
|
||||
mk("s33_dec_arr_quant", "Decimate 2 + 16-elem quant uint16 sine 5 Hz",
|
||||
[_src("src", [_sig("Wave", "float32", 16, quant="uint16", range_min=-1.0,
|
||||
range_max=1.0, formula="sine", freq=5.0)])],
|
||||
publishing="Decimate", ratio=2),
|
||||
mk("s34_acc_fullarray",
|
||||
"Accumulate @100 Hz: accumulated scalar + 32-elem FullArray sine passenger",
|
||||
[_src("src", [
|
||||
_sig("Sine", "float32", 1, formula="sine", freq=5.0),
|
||||
_sig("TimeArr", "uint64", 32, unit="ns", formula="time_ns",
|
||||
is_time=True),
|
||||
_sig("Wave", "float32", 32, time_mode="FullArray",
|
||||
time_signal="TimeArr", formula="sine", freq=5.0),
|
||||
])],
|
||||
publishing="Accumulate", min_refresh_hz=100.0),
|
||||
mk("s35_mcast_decimate", "multicast + Decimate ratio 5, float32 scalar sine 5 Hz",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)],
|
||||
multicast=True)],
|
||||
network="multicast", publishing="Decimate", ratio=5),
|
||||
mk("s36_big_frag_dec", "float64 64-elem ramp, MaxPayload 256 + Decimate 4",
|
||||
[_src("src", [_sig("Ramp", "float64", 64, formula="ramp")])],
|
||||
max_payload=256, publishing="Decimate", ratio=4),
|
||||
mk("s49_mixed_quant_raw", "one source: quant uint8 sine + raw float32 sine",
|
||||
[_src("src", [
|
||||
_sig("Q", "float32", 1, quant="uint8", range_min=-1.0, range_max=1.0,
|
||||
formula="sine", freq=5.0),
|
||||
_sig("Raw", "float32", 1, formula="sine", freq=5.0),
|
||||
])]),
|
||||
]
|
||||
|
||||
# ── Trigger + client-check coverage (rising/falling/both swept by the client) ─
|
||||
_TRIGGER = [
|
||||
mk("s37_trig_ramp_i32", "trigger on int32 ramp scalar",
|
||||
[_src("src", [_sig("Ramp", "int32", 1, formula="ramp")])],
|
||||
checks=("live", "trigger"), trig="src:Ramp"),
|
||||
mk("s38_trig_f64_sine", "trigger on float64 sine 5 Hz scalar",
|
||||
[_src("src", [_sig("Sine", "float64", 1, formula="sine", freq=5.0)])],
|
||||
checks=("live", "zoom", "trigger"), trig="src:Sine"),
|
||||
mk("s44_window_check", "float32 sine 5 Hz scalar, window time-range check",
|
||||
[_src("src", [_sig("Sine", "float32", 1, formula="sine", freq=5.0)])],
|
||||
checks=("live", "zoom", "window")),
|
||||
mk("s50_trig_quant", "trigger on quantised uint16 sine 10 Hz",
|
||||
[_src("src", [_sig("Sine", "float32", 1, quant="uint16", range_min=-5.0,
|
||||
range_max=5.0, formula="sine", freq=10.0)])],
|
||||
checks=("live", "trigger"), trig="src:Sine"),
|
||||
]
|
||||
|
||||
# ── Misc scalar coverage (unit annotation, counter on float) ─────────────────
|
||||
_MISC = [
|
||||
mk("s41_f32_unit", "float32 scalar ramp with Unit=V",
|
||||
[_src("src", [_sig("Ramp", "float32", 1, formula="ramp", unit="V")])]),
|
||||
mk("s42_f64_counter", "float64 scalar counter (large integer values)",
|
||||
[_src("src", [_sig("Cnt", "float64", 1, formula="counter")])]),
|
||||
]
|
||||
|
||||
# ── High sample-rate / high-throughput stress ────────────────────────────────
|
||||
# Eight signals, each a 1000-element float32 array carrying 1 ms worth of 1 MSps
|
||||
# data, published once per 1 kHz producer cycle. Aggregate wire rate is
|
||||
# 8 x 1 MSps x 4 B = 32 MB/s. A single scalar uint64 ns anchor (FirstSample) is
|
||||
# shared by all eight data signals; the per-packet sample window
|
||||
# (1000 / 1 MHz = 1 ms) equals the 1 kHz inter-packet gap so the expanded
|
||||
# per-sample timestamps stay monotonic for the hub's binary-search ring. Ramp
|
||||
# formula keeps the gate fidelity-only (robust to the UDP loss expected at rate).
|
||||
#
|
||||
# Packet sizing — DATA payload is 8 (ns anchor) + 8 x 1000 x 4 = 32008 B, which
|
||||
# is deliberately kept under the 64 KB single-datagram ceiling. That ceiling is
|
||||
# the UDPSClient reassembly buffer (UDPSReassemblySlot::payload[65535]) plus its
|
||||
# offset overflow guard: a packet whose payload exceeds ~64 KB can never be
|
||||
# reassembled (fragment 1 lands past the buffer and is dropped), so high-rate
|
||||
# streaming must use single-datagram packets. max_payload is set to the maximum
|
||||
# valid value (UDP limit - 17 B header) so the 32 KB packet is sent unfragmented.
|
||||
_HIGHRATE = [
|
||||
mk("s51_8x1msps_100hz",
|
||||
"8x float32 10k-elem arrays @1 MSps, FirstSample, 100 Hz packets (~32 MB/s, "
|
||||
"320 KB/cycle fragmented)",
|
||||
[_src("src", [
|
||||
_sig("Tns", "uint64", 1, unit="ns", formula="time_ns", is_time=True),
|
||||
] + [
|
||||
_sig(f"S{i}", "float32", 10000, time_mode="FirstSample",
|
||||
time_signal="Tns", sampling_rate=1.0e6, formula="ramp")
|
||||
for i in range(8)
|
||||
])],
|
||||
max_payload=40000, row_dt=0.01, num_rows=50, producer_hz=100,
|
||||
checks=("live", "zoom")),
|
||||
]
|
||||
|
||||
SCENARIOS = (_STARTERS + _TYPES + _ARRAYS + _TIMEMODES + _QUANT + _PUBLISH +
|
||||
_PAYLOAD + _MCAST + _MULTISRC + _INTERACT + _TRIGGER + _MISC +
|
||||
_HIGHRATE)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
ok = True
|
||||
seen_ids, seen_ws, seen_udp = set(), set(), set()
|
||||
for s in SCENARIOS:
|
||||
errs = validate_scenario(s)
|
||||
# uniqueness invariants the orchestrator relies on
|
||||
if s["id"] in seen_ids:
|
||||
errs.append("duplicate id")
|
||||
seen_ids.add(s["id"])
|
||||
if s["ws_port"] in seen_ws:
|
||||
errs.append(f"duplicate ws_port {s['ws_port']}")
|
||||
seen_ws.add(s["ws_port"])
|
||||
for src in s["sources"]:
|
||||
if src["udp_port"] in seen_udp:
|
||||
errs.append(f"duplicate udp_port {src['udp_port']}")
|
||||
seen_udp.add(src["udp_port"])
|
||||
print(f"{s['id']:32s} {'OK' if not errs else errs}")
|
||||
ok = ok and not errs
|
||||
print(f"\n{len(SCENARIOS)} scenarios, {'ALL VALID' if ok else 'INVALID PRESENT'}")
|
||||
sys.exit(0 if ok else 1)
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
stress.py — Declarative stress matrix for the streaming chain.
|
||||
|
||||
Where scenarios.py exercises *correctness* (every option value, exact waveform
|
||||
fidelity), this module exercises *capacity*: it pushes one axis of load at a time
|
||||
and records how the two server processes behave. The two components under stress:
|
||||
|
||||
* UDPStreamer (datasource) — serialises + sends UDPS packets each RT cycle.
|
||||
Stress axes: signal size (bytes/packet), signal count, subscriber count
|
||||
(UDPStreamer fans a unicast source out to up to 16 clients).
|
||||
* StreamHub (hub) — ring storage, LTTB decimation, WS fan-out, zoom.
|
||||
Stress axes: signal size, source count (independent UDPStreamer feeds),
|
||||
WS client count, and client request (zoom) rate.
|
||||
|
||||
What is measured (not waveform fidelity — at these rates UDP loss is expected and
|
||||
the hub decimates to PushRate anyway, so end-to-end sample loss is not the gate):
|
||||
|
||||
* survival — neither server crashed/hung for the whole run (hard gate).
|
||||
* liveness — every WS client kept receiving monotonic, wall-clock-stamped
|
||||
pushes under the load (hard gate).
|
||||
* cpu / peakRSS — of marte and hub, captured by proc_perf.py (scaling curves;
|
||||
soft gate against generous ceilings).
|
||||
* zoom latency — p50/p95 round-trip of zoom queries issued under load (soft
|
||||
gate; the headline responsiveness metric for the hub).
|
||||
|
||||
Stress-case dict schema (a superset of the scenarios.py scenario dict, so the
|
||||
gen_data.py / gen_cfg.py generators consume it unchanged):
|
||||
|
||||
{ ...all scenario keys (id, network, publishing, max_payload, ws_port,
|
||||
sources, oracle, client_checks, trig_signal, row_dt/num_rows/...),
|
||||
"shape": "hub" | "ds_fanout",
|
||||
"stress": {
|
||||
"axis": str, # which load axis this case varies (for the report)
|
||||
"level": number, # the axis value (x for the scaling curve)
|
||||
"clients": int, # parallel WS clients (hub shape)
|
||||
"hubs": int, # parallel subscriber hubs (ds_fanout shape)
|
||||
"reqrate": float, # zoom requests/sec/client (0 = one-shot checks)
|
||||
"dur": float, # live-load duration (s)
|
||||
"gate": { "min_frames": int, "max_marte_rss_mb": float,
|
||||
"max_hub_rss_mb": float, "max_zoom_p95_ms": float },
|
||||
} }
|
||||
|
||||
The matrix keeps every datagram a single UDP fragment (payload < 64 KB): the
|
||||
UDPSClient reassembly buffer caps a deliverable packet at ~64 KB, so sustained
|
||||
high-rate streaming must stay below it (see scenarios.py s51). Cases therefore
|
||||
sweep *count* and *rate*, not oversized single packets.
|
||||
"""
|
||||
import itertools
|
||||
|
||||
import scenarios as S
|
||||
|
||||
# Dedicated port ranges, disjoint from scenarios.py (ws 8101-8151, udp 44610-).
|
||||
_ws = itertools.count(8300)
|
||||
_udp = itertools.count(45000, 2)
|
||||
_data = itertools.count(46000, 2)
|
||||
|
||||
# Producer geometry knobs shared across the matrix. 1 kHz producer (default),
|
||||
# float32 arrays sized so one cycle's array is a single sub-64 KB datagram.
|
||||
F32 = "float32"
|
||||
|
||||
|
||||
def _f32_arr(name, elements, sampling_rate=1.0e6):
|
||||
"""A float32 array signal timestamped FirstSample off the shared ns anchor.
|
||||
|
||||
sampling_rate defaults to elements*producer_hz so the per-cycle window equals
|
||||
one 1 kHz producer cycle (keeps the hub ring's time axis monotonic, the same
|
||||
constraint scenarios.py enforces for First/LastSample)."""
|
||||
return S._sig(name, F32, elements, time_mode="FirstSample",
|
||||
time_signal="Tns", sampling_rate=sampling_rate, formula="ramp")
|
||||
|
||||
|
||||
def _source(sid, n_signals, elements, multicast=False):
|
||||
"""One UDPStreamer source: a uint64 ns anchor + n_signals float32 arrays.
|
||||
|
||||
sampling_rate = elements / row_dt(1 ms) = elements * 1000 keeps each array's
|
||||
1 ms window aligned to the 1 kHz cycle regardless of `elements`."""
|
||||
rate = elements * 1000.0
|
||||
sigs = [S._sig("Tns", "uint64", 1, unit="ns", formula="time_ns",
|
||||
is_time=True)]
|
||||
sigs += [_f32_arr(f"S{i}", elements, rate) for i in range(n_signals)]
|
||||
return {
|
||||
"id": sid, "udp_port": next(_udp),
|
||||
"data_port": next(_data) if multicast else None,
|
||||
"multicast_group": S.MCAST_GROUP if multicast else None,
|
||||
"signals": sigs,
|
||||
}
|
||||
|
||||
|
||||
def _packet_bytes(n_signals, elements):
|
||||
"""Approx DATA payload bytes/packet: ns anchor + n_signals*elements*4."""
|
||||
return 8 + n_signals * elements * 4
|
||||
|
||||
|
||||
def mk_stress(sid, axis, level, sources, shape="hub", clients=1, hubs=1,
|
||||
reqrate=0.0, dur=6.0, network="unicast", publishing="Strict",
|
||||
ratio=None, min_refresh_hz=None, gate=None):
|
||||
case = {
|
||||
"id": sid, "desc": f"stress {axis}={level}",
|
||||
"network": network, "publishing": publishing,
|
||||
"ratio": ratio, "min_refresh_hz": min_refresh_hz,
|
||||
"max_payload": S.MAX_UDP_PAYLOAD - S.UDPS_HEADER_SIZE,
|
||||
"ws_port": next(_ws), "sources": sources,
|
||||
"oracle": "analytic", "client_checks": ["live", "zoom"],
|
||||
"trig_signal": None, "known_issue": None,
|
||||
"row_dt": None, "num_rows": None, "producer_hz": None,
|
||||
"shape": shape,
|
||||
"stress": {
|
||||
"axis": axis, "level": level, "clients": clients, "hubs": hubs,
|
||||
"reqrate": reqrate, "dur": dur,
|
||||
"gate": gate or {},
|
||||
},
|
||||
}
|
||||
return case
|
||||
|
||||
|
||||
# Default gate: at least a handful of frames per client, generous RSS ceilings,
|
||||
# and a 1 s p95 zoom round-trip cap. Stress cases tune these per axis.
|
||||
def _gate(min_frames=5, marte_rss=512.0, hub_rss=1024.0, zoom_p95=1000.0):
|
||||
return {"min_frames": min_frames, "max_marte_rss_mb": marte_rss,
|
||||
"max_hub_rss_mb": hub_rss, "max_zoom_p95_ms": zoom_p95}
|
||||
|
||||
|
||||
# ── UDPStreamer (datasource) stress ───────────────────────────────────────────
|
||||
# Single source + single hub; the load lands on the UDPStreamer serialise/send
|
||||
# path and is read back through one WS client (proc_perf measures marte).
|
||||
|
||||
# size: one float32 array, growing element count → bigger single-datagram packet.
|
||||
_DS_SIZE = [
|
||||
mk_stress(f"ds_size_{e}", "ds_signal_elements", e,
|
||||
[_source("src", 1, e)], gate=_gate())
|
||||
for e in (1000, 4000, 8000, 15000) # 4 KB → 60 KB packets (sub-64 KB cap)
|
||||
]
|
||||
|
||||
# count: many 1000-element float32 arrays in one source → wider packet + more
|
||||
# per-cycle serialise work.
|
||||
_DS_COUNT = [
|
||||
mk_stress(f"ds_count_{n}", "ds_signal_count", n,
|
||||
[_source("src", n, 1000)], gate=_gate())
|
||||
for n in (1, 4, 8, 15) # 15*4 KB ≈ 60 KB packet (sub-64 KB cap)
|
||||
]
|
||||
|
||||
# clients (fan-out): one source, M subscriber hubs (ds_fanout shape). The
|
||||
# UDPStreamer copies every packet to each unicast client (max 16); CPU should
|
||||
# scale with M. Each hub gets its own WS port + one client.
|
||||
_DS_CLIENTS = [
|
||||
mk_stress(f"ds_clients_{m}", "ds_subscriber_hubs", m,
|
||||
[_source("src", 4, 2000)], shape="ds_fanout", hubs=m,
|
||||
gate=_gate(hub_rss=1024.0))
|
||||
for m in (1, 2, 4, 8)
|
||||
]
|
||||
|
||||
# ── StreamHub (hub) stress ────────────────────────────────────────────────────
|
||||
# All measured against a single hub; proc_perf measures the hub process.
|
||||
|
||||
# size: hub ring/decimation cost vs per-signal width.
|
||||
_HUB_SIZE = [
|
||||
mk_stress(f"hub_size_{e}", "hub_signal_elements", e,
|
||||
[_source("src", 1, e)], gate=_gate())
|
||||
for e in (1000, 4000, 8000, 15000)
|
||||
]
|
||||
|
||||
# sources: N independent UDPStreamer feeds into one hub (each its own udp_port).
|
||||
_HUB_SOURCES = [
|
||||
mk_stress(f"hub_sources_{n}", "hub_source_count", n,
|
||||
[_source(f"s{i}", 2, 1000) for i in range(n)],
|
||||
gate=_gate(marte_rss=1024.0))
|
||||
for n in (1, 2, 4, 8)
|
||||
]
|
||||
|
||||
# clients: one source, C parallel WS clients all recording live + zooming.
|
||||
_HUB_CLIENTS = [
|
||||
mk_stress(f"hub_clients_{c}", "hub_ws_clients", c,
|
||||
[_source("src", 2, 2000)], clients=c, gate=_gate())
|
||||
for c in (1, 4, 8, 16)
|
||||
]
|
||||
|
||||
# request rate: one source, a few clients each issuing zoom queries at a sustained
|
||||
# rate; the headline gate is zoom p95 latency under that query load.
|
||||
_HUB_REQRATE = [
|
||||
mk_stress(f"hub_reqrate_{r}", "hub_zoom_reqrate_hz", r,
|
||||
[_source("src", 2, 2000)], clients=4, reqrate=r, dur=8.0,
|
||||
gate=_gate(zoom_p95=1500.0))
|
||||
for r in (5, 20, 50)
|
||||
]
|
||||
|
||||
STRESS_CASES = (_DS_SIZE + _DS_COUNT + _DS_CLIENTS +
|
||||
_HUB_SIZE + _HUB_SOURCES + _HUB_CLIENTS + _HUB_REQRATE)
|
||||
|
||||
|
||||
def validate_case(c):
|
||||
"""Stress-case validity = scenario validity + stress-specific bounds."""
|
||||
errs = S.validate_scenario(c)
|
||||
st = c.get("stress", {})
|
||||
if c["shape"] == "ds_fanout":
|
||||
if st["hubs"] < 1 or st["hubs"] > 16:
|
||||
errs.append(f"{c['id']}: ds_fanout hubs must be 1..16 "
|
||||
f"(UDPStreamer max unicast clients)")
|
||||
if c["shape"] == "hub" and (st["clients"] < 1):
|
||||
errs.append(f"{c['id']}: hub clients must be >= 1")
|
||||
# Single-datagram ceiling: keep each source's packet < 64 KB so it never
|
||||
# needs reassembly (the deliverable-packet cap).
|
||||
for src in c["sources"]:
|
||||
n_data = sum(1 for s in src["signals"] if not s["is_time"])
|
||||
elem = max((s["elements"] for s in src["signals"]
|
||||
if not s["is_time"]), default=0)
|
||||
pb = _packet_bytes(n_data, elem)
|
||||
if pb >= 65536:
|
||||
errs.append(f"{c['id']}: source {src['id']} packet {pb} B exceeds "
|
||||
f"the 64 KB single-datagram cap")
|
||||
return errs
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
ok = True
|
||||
seen_ids, seen_ws, seen_udp = set(), set(), set()
|
||||
by_axis = {}
|
||||
for c in STRESS_CASES:
|
||||
errs = validate_case(c)
|
||||
if c["id"] in seen_ids:
|
||||
errs.append("duplicate id")
|
||||
seen_ids.add(c["id"])
|
||||
if c["ws_port"] in seen_ws:
|
||||
errs.append(f"duplicate ws_port {c['ws_port']}")
|
||||
seen_ws.add(c["ws_port"])
|
||||
for src in c["sources"]:
|
||||
if src["udp_port"] in seen_udp:
|
||||
errs.append(f"duplicate udp_port {src['udp_port']}")
|
||||
seen_udp.add(src["udp_port"])
|
||||
by_axis.setdefault(c["stress"]["axis"], []).append(c["id"])
|
||||
print(f"{c['id']:20s} {c['shape']:9s} "
|
||||
f"{'OK' if not errs else errs}")
|
||||
ok = ok and not errs
|
||||
print(f"\n{len(STRESS_CASES)} stress cases across {len(by_axis)} axes, "
|
||||
f"{'ALL VALID' if ok else 'INVALID PRESENT'}")
|
||||
sys.exit(0 if ok else 1)
|
||||
Executable
+298
@@ -0,0 +1,298 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
stress_run.py — Orchestrator for the streaming-chain stress matrix (stress.py).
|
||||
|
||||
Where run_chain_e2e.sh drives scenarios.py for *correctness*, this drives
|
||||
STRESS_CASES for *capacity*. Per case it:
|
||||
|
||||
1. generates the FileReader input + MARTe app cfg + 1..M StreamHub cfgs
|
||||
(reusing gen_data / gen_cfg unchanged — a stress case is a scenario superset),
|
||||
2. launches the server stack:
|
||||
* "hub" shape: 1 MARTe UDPStreamer feed + 1 StreamHub, then N
|
||||
parallel chain-clients (stress mode) on that one hub,
|
||||
* "ds_fanout" shape: 1 MARTe feed + M independent StreamHubs all
|
||||
subscribing to the same UDPStreamer (unicast fan-out), 1 client each,
|
||||
3. drives the clients in stress mode (liveness + sustained zoom-latency),
|
||||
4. snapshots CPU / peak-RSS of marte and every hub *while alive* (proc_perf),
|
||||
5. evaluates the per-case gate (survival + liveness hard gates; RSS + zoom-p95
|
||||
soft gates against the case's ceilings),
|
||||
|
||||
and writes stress_results.json (one record per case, carrying the axis/level for
|
||||
later scaling-curve plots). Server binaries + LD_LIBRARY_PATH come from the
|
||||
caller (run_stress.sh sources env.sh); this module only orchestrates.
|
||||
"""
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import gen_cfg # noqa: E402
|
||||
import gen_data # noqa: E402
|
||||
import proc_perf # noqa: E402
|
||||
import stress as ST # noqa: E402
|
||||
|
||||
# WS port probing bases. StreamHub does not set SO_REUSEADDR, so a leftover
|
||||
# listener (e.g. an orphaned hub from an aborted run) keeps a fixed port wedged;
|
||||
# we therefore probe for genuinely-free ports at launch rather than trusting a
|
||||
# static assignment. ds_fanout hubs probe from one base, single hubs from another.
|
||||
FANOUT_WS_BASE = 9000
|
||||
SINGLE_WS_BASE = 9100
|
||||
|
||||
|
||||
def _popen(cmd, log_path):
|
||||
"""Launch cmd in its own session, stdout+stderr → log_path."""
|
||||
f = open(log_path, "w")
|
||||
return subprocess.Popen(cmd, stdout=f, stderr=subprocess.STDOUT,
|
||||
start_new_session=True), f
|
||||
|
||||
|
||||
def _free_ports(n, base):
|
||||
"""Find n free TCP ports on 127.0.0.1 at/above base.
|
||||
|
||||
Probed ports are closed and handed straight to the hub launch; the race
|
||||
window is negligible for this sequential localhost harness, and probing is
|
||||
what makes the suite robust to leftover wedged listeners."""
|
||||
found = []
|
||||
cand = base
|
||||
while len(found) < n and cand < base + 1000:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.bind(("127.0.0.1", cand))
|
||||
found.append(cand)
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
s.close()
|
||||
cand += 1
|
||||
if len(found) < n:
|
||||
raise RuntimeError(f"could not find {n} free ports from {base}")
|
||||
return found
|
||||
|
||||
|
||||
def _hub_ports(case):
|
||||
st = case["stress"]
|
||||
if case["shape"] == "ds_fanout":
|
||||
return _free_ports(st["hubs"], FANOUT_WS_BASE)
|
||||
return _free_ports(1, SINGLE_WS_BASE)
|
||||
|
||||
|
||||
def _teardown(procs_files):
|
||||
for p, _f in procs_files:
|
||||
if p.poll() is None:
|
||||
try:
|
||||
os.killpg(os.getpgid(p.pid), signal.SIGTERM)
|
||||
except (ProcessLookupError, PermissionError):
|
||||
pass
|
||||
deadline = time.time() + 5
|
||||
for p, _f in procs_files:
|
||||
try:
|
||||
p.wait(timeout=max(0.1, deadline - time.time()))
|
||||
except subprocess.TimeoutExpired:
|
||||
try:
|
||||
os.killpg(os.getpgid(p.pid), signal.SIGKILL)
|
||||
except (ProcessLookupError, PermissionError):
|
||||
pass
|
||||
for _p, f in procs_files:
|
||||
try:
|
||||
f.close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def run_case(case, bins, work, out):
|
||||
sid = case["id"]
|
||||
st = case["stress"]
|
||||
input_bin = os.path.join(work, f"sinput_{sid}.bin")
|
||||
marte_cfg = os.path.join(work, f"sm_{sid}.cfg")
|
||||
|
||||
gen_data.write_input(case, input_bin)
|
||||
gen_cfg.write_marte_cfg(case, marte_cfg, input_bin)
|
||||
|
||||
ports = _hub_ports(case)
|
||||
hub_pf = [] # (proc, file)
|
||||
for i, p in enumerate(ports):
|
||||
hc = copy.deepcopy(case)
|
||||
hc["ws_port"] = p
|
||||
hcfg = os.path.join(work, f"sh_{sid}_{i}.cfg")
|
||||
gen_cfg.write_hub_cfg(hc, hcfg)
|
||||
proc, f = _popen([bins["hub"], "-cfg", hcfg],
|
||||
os.path.join(out, f"shub_{sid}_{i}.log"))
|
||||
hub_pf.append((proc, f))
|
||||
time.sleep(1.0)
|
||||
|
||||
marte_proc, marte_f = _popen(
|
||||
[bins["marte"], "-l", "RealTimeLoader", "-f", marte_cfg, "-s", "Running"],
|
||||
os.path.join(out, f"smarte_{sid}.log"))
|
||||
time.sleep(1.5)
|
||||
|
||||
dur, reqrate = st["dur"], st["reqrate"]
|
||||
# clean stale client outputs so a missing file means "client failed".
|
||||
for i in range(max(st["clients"], st["hubs"])):
|
||||
sp = os.path.join(work, f"stress_{sid}_c{i}.json")
|
||||
if os.path.exists(sp):
|
||||
os.remove(sp)
|
||||
|
||||
client_pf = []
|
||||
if case["shape"] == "ds_fanout":
|
||||
targets = [(i, ports[i]) for i in range(len(ports))]
|
||||
else:
|
||||
targets = [(i, ports[0]) for i in range(st["clients"])]
|
||||
for cid, wsport in targets:
|
||||
cmd = [bins["client"], "-mode", "stress",
|
||||
"-hub", f"127.0.0.1:{wsport}", "-scenario", sid,
|
||||
"-clientid", str(cid), "-dur", str(dur),
|
||||
"-reqrate", str(reqrate), "-out", work,
|
||||
"-timeout", f"{int(dur) + 90}s"]
|
||||
proc, f = _popen(cmd, os.path.join(out, f"sclient_{sid}_c{cid}.log"))
|
||||
client_pf.append((proc, f))
|
||||
|
||||
deadline = time.time() + dur + 60
|
||||
for proc, _f in client_pf:
|
||||
try:
|
||||
proc.wait(timeout=max(1.0, deadline - time.time()))
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
for _p, f in client_pf:
|
||||
f.close()
|
||||
|
||||
# survival + perf must be read while the stack is still alive.
|
||||
survival = (marte_proc.poll() is None
|
||||
and all(h.poll() is None for h, _ in hub_pf))
|
||||
perf_marte = proc_perf.snapshot(marte_proc.pid)
|
||||
perf_hubs = [proc_perf.snapshot(h.pid) for h, _ in hub_pf]
|
||||
|
||||
_teardown([(marte_proc, marte_f)] + hub_pf)
|
||||
|
||||
clients = []
|
||||
for cid, _ in targets:
|
||||
jp = os.path.join(work, f"stress_{sid}_c{cid}.json")
|
||||
if os.path.exists(jp):
|
||||
with open(jp) as f:
|
||||
clients.append(json.load(f))
|
||||
|
||||
return _evaluate(case, survival, perf_marte, perf_hubs, clients)
|
||||
|
||||
|
||||
def _rss_mb(rec):
|
||||
return rec.get("peak_rss_kb", 0) / 1024.0 if rec.get("avail") else 0.0
|
||||
|
||||
|
||||
def _evaluate(case, survival, perf_marte, perf_hubs, clients):
|
||||
g = case["stress"].get("gate", {})
|
||||
fails = []
|
||||
|
||||
if not survival:
|
||||
fails.append("server process died during run")
|
||||
if not clients:
|
||||
fails.append("no client results recorded")
|
||||
|
||||
min_frames = g.get("min_frames", 1)
|
||||
for c in clients:
|
||||
cid = c.get("clientId")
|
||||
if c.get("frames", 0) < min_frames:
|
||||
fails.append(f"c{cid} frames {c.get('frames')} < {min_frames}")
|
||||
if not c.get("monotonic", False):
|
||||
fails.append(f"c{cid} non-monotonic time axis")
|
||||
if not c.get("wallclock", False):
|
||||
fails.append(f"c{cid} non-wallclock timestamps")
|
||||
|
||||
marte_rss = _rss_mb(perf_marte)
|
||||
if "max_marte_rss_mb" in g and marte_rss > g["max_marte_rss_mb"]:
|
||||
fails.append(f"marte peakRSS {marte_rss:.0f}MB > {g['max_marte_rss_mb']}MB")
|
||||
hub_rss_max = max((_rss_mb(h) for h in perf_hubs), default=0.0)
|
||||
if "max_hub_rss_mb" in g and hub_rss_max > g["max_hub_rss_mb"]:
|
||||
fails.append(f"hub peakRSS {hub_rss_max:.0f}MB > {g['max_hub_rss_mb']}MB")
|
||||
|
||||
p95s = [c["zoomP95ms"] for c in clients if c.get("zoomCount", 0) > 0]
|
||||
zoom_p95 = max(p95s) if p95s else 0.0
|
||||
p50s = [c["zoomP50ms"] for c in clients if c.get("zoomCount", 0) > 0]
|
||||
zoom_p50 = max(p50s) if p50s else 0.0
|
||||
if "max_zoom_p95_ms" in g and zoom_p95 > g["max_zoom_p95_ms"]:
|
||||
fails.append(f"zoom p95 {zoom_p95:.0f}ms > {g['max_zoom_p95_ms']}ms")
|
||||
|
||||
st = case["stress"]
|
||||
return {
|
||||
"id": case["id"], "shape": case["shape"],
|
||||
"axis": st["axis"], "level": st["level"],
|
||||
"status": "PASS" if not fails else "FAIL",
|
||||
"survival": survival,
|
||||
"clients": len(clients),
|
||||
"min_frames": min(((c.get("frames", 0)) for c in clients), default=0),
|
||||
"marte_cpu_s": perf_marte.get("cpu_s", 0.0),
|
||||
"marte_rss_mb": round(marte_rss, 1),
|
||||
"hub_cpu_s": round(sum(h.get("cpu_s", 0.0) for h in perf_hubs), 2),
|
||||
"hub_rss_mb": round(hub_rss_max, 1),
|
||||
"zoom_count": sum(c.get("zoomCount", 0) for c in clients),
|
||||
"zoom_fail": sum(c.get("zoomFail", 0) for c in clients),
|
||||
"zoom_p50_ms": round(zoom_p50, 1),
|
||||
"zoom_p95_ms": round(zoom_p95, 1),
|
||||
"fails": fails,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description="Run the streaming-chain stress matrix")
|
||||
p.add_argument("--marte", required=True, help="MARTeApp.ex path")
|
||||
p.add_argument("--hub", required=True, help="StreamHub.ex path")
|
||||
p.add_argument("--client", required=True, help="chain-client path")
|
||||
p.add_argument("--work", required=True, help="scratch dir")
|
||||
p.add_argument("--out", required=True, help="report/log dir")
|
||||
p.add_argument("--only", default="", help="run a single case id")
|
||||
p.add_argument("--axis", default="", help="run only cases on this axis")
|
||||
args = p.parse_args()
|
||||
|
||||
os.makedirs(args.work, exist_ok=True)
|
||||
os.makedirs(args.out, exist_ok=True)
|
||||
bins = {"marte": args.marte, "hub": args.hub, "client": args.client}
|
||||
|
||||
cases = ST.STRESS_CASES
|
||||
if args.only:
|
||||
cases = [c for c in cases if c["id"] == args.only]
|
||||
if args.axis:
|
||||
cases = [c for c in cases if c["stress"]["axis"] == args.axis]
|
||||
if not cases:
|
||||
print("no stress cases selected", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
results = []
|
||||
for c in cases:
|
||||
errs = ST.validate_case(c)
|
||||
if errs:
|
||||
print(f"══ {c['id']}: INVALID {errs} ══")
|
||||
results.append({"id": c["id"], "axis": c["stress"]["axis"],
|
||||
"level": c["stress"]["level"], "status": "FAIL",
|
||||
"fails": errs})
|
||||
continue
|
||||
print(f"\n══ stress {c['id']} ({c['shape']} {c['stress']['axis']}="
|
||||
f"{c['stress']['level']}) ══")
|
||||
rec = run_case(c, bins, args.work, args.out)
|
||||
results.append(rec)
|
||||
tag = rec["status"]
|
||||
print(f" {tag} frames>={rec.get('min_frames')} "
|
||||
f"marteCPU={rec.get('marte_cpu_s', 0):.1f}s "
|
||||
f"marteRSS={rec.get('marte_rss_mb', 0):.0f}MB "
|
||||
f"hubRSS={rec.get('hub_rss_mb', 0):.0f}MB "
|
||||
f"zoom p50/p95={rec.get('zoom_p50_ms', 0):.0f}/"
|
||||
f"{rec.get('zoom_p95_ms', 0):.0f}ms")
|
||||
if rec.get("fails"):
|
||||
for fmsg in rec["fails"]:
|
||||
print(f" - {fmsg}")
|
||||
|
||||
overall = bool(results) and all(r["status"] == "PASS" for r in results)
|
||||
doc = {"overall": "PASS" if overall else "FAIL", "cases": results}
|
||||
rp = os.path.join(args.out, "stress_results.json")
|
||||
with open(rp, "w") as f:
|
||||
json.dump(doc, f, indent=2)
|
||||
npass = sum(r["status"] == "PASS" for r in results)
|
||||
print(f"\nstress_results.json: {npass}/{len(results)} pass → {doc['overall']}")
|
||||
sys.exit(0 if overall else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
tests_py.py — Unit tests for the streaming-chain E2E Python framework.
|
||||
|
||||
Run directly (``python3 -m unittest tests_py``) or, for coverage, via collect.py
|
||||
which wraps it in ``coverage run``. These exercise the pure logic of the
|
||||
generators, the waveform oracle, the config emitter, the RCV1 reader and the
|
||||
/proc perf sampler — i.e. everything the orchestrator depends on, without needing
|
||||
a live MARTe/StreamHub stack.
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import scenarios as S
|
||||
import gen_data as G
|
||||
import gen_cfg as C
|
||||
import validate_waveform as V
|
||||
import proc_perf as P
|
||||
|
||||
|
||||
class TestScenarios(unittest.TestCase):
|
||||
def test_all_starter_scenarios_valid(self):
|
||||
for s in S.SCENARIOS:
|
||||
self.assertEqual(S.validate_scenario(s), [], f"{s['id']} invalid")
|
||||
|
||||
def test_seamless_loop_constraint(self):
|
||||
s = {
|
||||
"id": "x", "network": "unicast", "publishing": "Strict",
|
||||
"ratio": None, "min_refresh_hz": None, "max_payload": 1400,
|
||||
"ws_port": 9000,
|
||||
"sources": [{"id": "s", "udp_port": 1, "data_port": None,
|
||||
"multicast_group": None,
|
||||
"signals": [S._sig("Bad", "float32", freq=3.0)]}],
|
||||
"oracle": "analytic", "client_checks": ["live"], "trig_signal": None,
|
||||
}
|
||||
errs = S.validate_scenario(s)
|
||||
self.assertTrue(any("multiple of LOOP_HZ" in e for e in errs), errs)
|
||||
s["sources"][0]["signals"][0]["freq"] = S.LOOP_HZ * 2
|
||||
self.assertEqual(S.validate_scenario(s), [])
|
||||
|
||||
def test_bad_quant_rejected(self):
|
||||
s = {
|
||||
"id": "x", "network": "unicast", "publishing": "Strict",
|
||||
"ratio": None, "min_refresh_hz": None, "max_payload": 1400,
|
||||
"ws_port": 9000,
|
||||
"sources": [{"id": "s", "udp_port": 1, "data_port": None,
|
||||
"multicast_group": None,
|
||||
"signals": [S._sig("Q", "int32", quant="uint8",
|
||||
range_min=0, range_max=1, formula="ramp")]}],
|
||||
"oracle": "analytic", "client_checks": ["live"], "trig_signal": None,
|
||||
}
|
||||
errs = S.validate_scenario(s)
|
||||
self.assertTrue(any("quant only on float" in e for e in errs), errs)
|
||||
|
||||
|
||||
class TestGenData(unittest.TestCase):
|
||||
def test_ground_truth_shapes(self):
|
||||
gt = G.build_ground_truth(S.SCENARIOS[1]) # s02: TimeArr+Wave, 100 elem
|
||||
wave = gt["src:Wave"]
|
||||
self.assertEqual(wave["elements"], 100)
|
||||
self.assertEqual(wave["v"].size, S.NUM_ROWS * 100)
|
||||
self.assertEqual(wave["t"].size, S.NUM_ROWS * 100)
|
||||
|
||||
def test_binary_roundtrip(self):
|
||||
sc = S.SCENARIOS[0] # s01: Counter(uint32)+Sine(float32)
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p = os.path.join(d, "in.bin")
|
||||
gt = G.write_input(sc, p)
|
||||
cols = V.read_marte_binary(p)
|
||||
self.assertIn("Counter", cols)
|
||||
self.assertIn("Sine", cols)
|
||||
# counter is row index → first/last match ground truth
|
||||
self.assertEqual(cols["Counter"].reshape(-1)[0], gt["src:Counter"]["v"][0])
|
||||
self.assertEqual(int(cols["Counter"].reshape(-1)[5]), 5)
|
||||
|
||||
|
||||
class TestOracle(unittest.TestCase):
|
||||
def _gt(self, **kw):
|
||||
t = np.linspace(0, 1, 200)
|
||||
base = {"v": np.sin(2 * np.pi * 5 * t), "type": "float32", "quant": "none",
|
||||
"formula": "sine", "freq": 5.0, "range_min": -1.0, "range_max": 1.0,
|
||||
"elements": 1, "rows": 200, "is_time": False, "t": t,
|
||||
"dt": t[1] - t[0]}
|
||||
base.update(kw)
|
||||
return base, t
|
||||
|
||||
def test_quant_tol_is_one_level(self):
|
||||
gt, _ = self._gt(quant="uint16", range_min=-5.0, range_max=5.0)
|
||||
tol, step = V._tol(gt)
|
||||
self.assertAlmostEqual(step, 10.0 / 65535, places=9)
|
||||
self.assertGreaterEqual(tol, step) # one full level, not half
|
||||
|
||||
def test_good_passes_bad_fails(self):
|
||||
gt, t = self._gt(quant="uint16")
|
||||
_, step = V._tol(gt)
|
||||
good = gt["v"] + (np.random.rand(200) - 0.5) * step
|
||||
bad = gt["v"] + (np.random.rand(200) - 0.5) * step * 50
|
||||
self.assertTrue(V.compare_signal(gt, t, good)["pass"])
|
||||
self.assertFalse(V.compare_signal(gt, t, bad)["pass"])
|
||||
|
||||
def test_wrong_frequency_fails_shape(self):
|
||||
gt, t = self._gt()
|
||||
wrong = np.sin(2 * np.pi * 50 * t) # 10x frequency
|
||||
m = V.compare_signal(gt, t, wrong)
|
||||
self.assertFalse(m["shape_ok"], m)
|
||||
|
||||
def test_integer_offgrid_fails(self):
|
||||
gt, t = self._gt(type="uint32", quant="none",
|
||||
v=np.arange(200, dtype=np.float64), formula="counter")
|
||||
self.assertTrue(V.compare_signal(gt, t, np.arange(50, 150, dtype=float))["pass"])
|
||||
self.assertFalse(V.compare_signal(gt, t, np.array([1.5, 999.0]))["pass"])
|
||||
|
||||
|
||||
class TestRCV1(unittest.TestCase):
|
||||
def test_read_received(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p = os.path.join(d, "r.bin")
|
||||
t = [0.0, 0.1, 0.2]
|
||||
v = [1.0, 2.0, 3.0]
|
||||
buf = bytearray(b"RCV1")
|
||||
buf += struct.pack("<I", 1)
|
||||
key = b"src:Sig"
|
||||
buf += struct.pack("<H", len(key)) + key + struct.pack("<I", len(t))
|
||||
for x in t:
|
||||
buf += struct.pack("<d", x)
|
||||
for x in v:
|
||||
buf += struct.pack("<d", x)
|
||||
open(p, "wb").write(buf)
|
||||
r = V.read_received(p)
|
||||
self.assertIn("src:Sig", r)
|
||||
tt, vv = r["src:Sig"]
|
||||
self.assertEqual(list(vv), v)
|
||||
|
||||
|
||||
class TestGenCfg(unittest.TestCase):
|
||||
def test_tap_routes_through_ddb(self):
|
||||
sc = S.SCENARIOS[1] # s02, oracle=both
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
mc = os.path.join(d, "m.cfg")
|
||||
C.write_marte_cfg(sc, mc, os.path.join(d, "in.bin"),
|
||||
tap_bin=os.path.join(d, "tap.bin"))
|
||||
cfg = open(mc).read()
|
||||
self.assertIn("StreamGAM_src", cfg)
|
||||
self.assertIn("TapGAM", cfg)
|
||||
# TapGAM must read from the DDB (prefixed name), not the FileReader
|
||||
self.assertIn("src_Wave", cfg)
|
||||
tap_block = cfg[cfg.index("+TapGAM"):]
|
||||
tap_in = tap_block[tap_block.index("InputSignals"):tap_block.index("OutputSignals")]
|
||||
self.assertNotIn("FileReaderDS", tap_in)
|
||||
|
||||
def test_no_tap_direct(self):
|
||||
sc = S.SCENARIOS[0] # s01, oracle=analytic
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
mc = os.path.join(d, "m.cfg")
|
||||
C.write_marte_cfg(sc, mc, os.path.join(d, "in.bin"))
|
||||
cfg = open(mc).read()
|
||||
self.assertNotIn("TapGAM", cfg)
|
||||
self.assertIn("ReaderGAM_src", cfg)
|
||||
|
||||
def test_hub_cfg_has_ports(self):
|
||||
sc = S.SCENARIOS[0]
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
hc = os.path.join(d, "h.cfg")
|
||||
C.write_hub_cfg(sc, hc)
|
||||
cfg = open(hc).read()
|
||||
self.assertIn(f"WSPort = {sc['ws_port']}", cfg)
|
||||
self.assertIn(f"Port = {sc['sources'][0]['udp_port']}", cfg)
|
||||
|
||||
|
||||
class TestProcPerf(unittest.TestCase):
|
||||
def test_snapshot_self(self):
|
||||
rec = P.snapshot(os.getpid())
|
||||
self.assertTrue(rec["avail"])
|
||||
self.assertIn("cpu_s", rec)
|
||||
self.assertGreaterEqual(rec["cpu_s"], 0.0)
|
||||
|
||||
def test_snapshot_missing(self):
|
||||
self.assertFalse(P.snapshot(2 ** 30).get("avail", False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user