Skip to content

Commit

Permalink
Fix #2379, implement SB bulk transfer test
Browse files Browse the repository at this point in the history
Add a functional test that moves a large number of messages across the
bus as fast as possible (i.e. with no delay).  The process is timed, thus
offering some metric as to the single thread/single core performance of
the software bus implementation underneath.

Note that due to vast differences between hardware, results should only
be compared between successive runs on the exact same hardware, such as
before and after a change was made.
  • Loading branch information
jphickey committed Jun 16, 2023
1 parent 112bc51 commit 8753a09
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 2 deletions.
28 changes: 28 additions & 0 deletions modules/cfe_assert/inc/cfe_assert.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,23 @@ typedef void (*CFE_Assert_StatusCallback_t)(uint8 MessageType, const char *Prefi
*/
#define CFE_Assert_STATUS_STORE(FN) CFE_Assert_Status_Store(FN, __FILE__, __LINE__, #FN)

/**
** \brief Check if the stored status matches a possible value
**
** Allows the caller to check the value from a previous invocation of CFE_Assert_STATUS_STORE()
** without directly asserting on the value or changing test state.
**
** This may be useful in situations where a large volume of tests are being performed, such as
** during performance or load testing, where reporting all "PASS" cases may add signficant
** extra CPU usage and log volume, interfering with the result. This macro can be followed
** or combined with CFE_Assert_STATUS_MAY_BE / CFE_Assert_STATUS_MUST_BE to do actual reporting.
** \sa #CFE_Assert_STATUS_STORE, #CFE_Assert_STATUS_MAY_BE, #CFE_Assert_STATUS_MUST_BE
**
** \returns Actual CFE_Status_t value from the call
*/
#define CFE_Assert_STATUS_SILENTCHECK(expected) CFE_Assert_Status_SilentCheck(expected)

/*****************************************************************************/
/**
** \brief Retroactively check for an acceptable status value from CFE_Assert_STATUS_STORE
Expand Down Expand Up @@ -357,6 +374,17 @@ bool CFE_Assert_StatusCheck(CFE_Status_t Status, bool ExpectSuccess, UtAssert_Ca
*/
CFE_Status_t CFE_Assert_Status_Store(CFE_Status_t Status, const char *File, uint32 Line, const char *Text);

/**
** \brief Helper function to silently check status of a previously stored result
**
** \par Description
** This helper function will check the status previously stored to a
** temporary holding area, but does not assert on it.
**
** \returns true if status code matched, false if it did not match.
*/
bool CFE_Assert_Status_SilentCheck(CFE_Status_t Status);

/**
** \brief Helper function for nominal CFE calls with deferred check
**
Expand Down
7 changes: 6 additions & 1 deletion modules/cfe_assert/src/cfe_assert_runner.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ CFE_Status_t CFE_Assert_Status_Store(CFE_Status_t Status, const char *File, uint
return Status;
}

bool CFE_Assert_Status_SilentCheck(CFE_Status_t Status)
{
return (Status == CFE_Assert_Global.StoredStatus);
}

bool CFE_Assert_Status_DeferredCheck(CFE_Status_t Status, UtAssert_CaseType_t CaseType, const char *File, uint32 Line,
const char *Text)
{
Expand All @@ -125,7 +130,7 @@ bool CFE_Assert_Status_DeferredCheck(CFE_Status_t Status, UtAssert_CaseType_t Ca
}
else
{
Result = (Status == CFE_Assert_Global.StoredStatus);
Result = CFE_Assert_Status_SilentCheck(Status);
if (Result)
{
/* no extra tag added to "true" conditions */
Expand Down
3 changes: 2 additions & 1 deletion modules/cfe_testcase/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ include_directories(inc)

# Filenames based on doxygen groups.
# Create the app module
add_cfe_app(cfe_testcase
add_cfe_app(cfe_testcase
src/cfe_test.c
src/cfe_test_table.c
src/es_application_control_test.c
Expand All @@ -23,6 +23,7 @@ add_cfe_app(cfe_testcase
src/message_id_test.c
src/msg_api_test.c
src/resource_id_misc_test.c
src/sb_performance_test.c
src/sb_pipe_mang_test.c
src/sb_sendrecv_test.c
src/sb_subscription_test.c
Expand Down
1 change: 1 addition & 0 deletions modules/cfe_testcase/src/cfe_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ void CFE_TestMain(void)
SBPipeMangSetup();
SBSendRecvTestSetup();
SBSubscriptionTestSetup();
SBPerformanceTestSetup();
TBLContentAccessTestSetup();
TBLContentMangTestSetup();
TBLInformationTestSetup();
Expand Down
1 change: 1 addition & 0 deletions modules/cfe_testcase/src/cfe_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void FSUtilTestSetup(void);
void MessageIdTestSetup(void);
void MsgApiTestSetup(void);
void ResourceIdMiscTestSetup(void);
void SBPerformanceTestSetup(void);
void SBPipeMangSetup(void);
void SBSendRecvTestSetup(void);
void SBSubscriptionTestSetup(void);
Expand Down
147 changes: 147 additions & 0 deletions modules/cfe_testcase/src/sb_performance_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/************************************************************************
* NASA Docket No. GSC-18,719-1, and identified as “core Flight System: Bootes”
*
* Copyright (c) 2020 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
************************************************************************/

/**
* @file
*
* Functional test of SB transmit/receive API performance
*
* The intent of this test is to perform a set of SB message transfers
* at a sufficiently high rate / volume such that the performance of
* the implementation can be characterized. Note that this
* cannot (currently) measure the performance directly, it merely implements a
* scenario that allows the performance to be measured by an external test
* harness.
*/

#include "cfe_test.h"
#include "cfe_msgids.h"
#include "cfe_test_msgids.h"

/* A simple command message */
typedef struct
{
CFE_MSG_CommandHeader_t CommandHeader;
uint32 CmdPayload;
} CFE_FT_TestCmdMessage_t;

/* A simple telemetry message */
typedef struct
{
CFE_MSG_TelemetryHeader_t TelemetryHeader;
uint32 TlmPayload;
} CFE_FT_TestTlmMessage_t;

/*
* This test procedure should be agnostic to specific MID values, but it should
* not overlap/interfere with real MIDs used by other apps.
*/
static const CFE_SB_MsgId_t CFE_FT_CMD_MSGID = CFE_SB_MSGID_WRAP_VALUE(CFE_TEST_CMD_MID);
static const CFE_SB_MsgId_t CFE_FT_TLM_MSGID = CFE_SB_MSGID_WRAP_VALUE(CFE_TEST_HK_TLM_MID);

void TestBulkTransmitRecv(void)
{
CFE_SB_PipeId_t PipeId1 = CFE_SB_INVALID_PIPE;
CFE_SB_PipeId_t PipeId2 = CFE_SB_INVALID_PIPE;
CFE_FT_TestCmdMessage_t CmdMsg;
CFE_FT_TestTlmMessage_t TlmMsg;
CFE_SB_Buffer_t * MsgBuf;
const CFE_FT_TestCmdMessage_t *CmdPtr;
const CFE_FT_TestTlmMessage_t *TlmPtr;
uint32 SendCount;
OS_time_t StartTime;
OS_time_t ElapsedTime;

memset(&CmdMsg, 0, sizeof(CmdMsg));
memset(&TlmMsg, 0, sizeof(TlmMsg));

UtPrintf("Testing: Bulk SB Transmit/Receive");
CFE_PSP_GetTime(&StartTime);

/* Setup, create a pipe and subscribe (one cmd, one tlm) */
UtAssert_INT32_EQ(CFE_SB_CreatePipe(&PipeId1, 5, "TestPipe1"), CFE_SUCCESS);
UtAssert_INT32_EQ(CFE_SB_CreatePipe(&PipeId2, 5, "TestPipe2"), CFE_SUCCESS);
UtAssert_INT32_EQ(CFE_SB_SubscribeEx(CFE_FT_CMD_MSGID, PipeId1, CFE_SB_DEFAULT_QOS, 3), CFE_SUCCESS);
UtAssert_INT32_EQ(CFE_SB_SubscribeEx(CFE_FT_TLM_MSGID, PipeId2, CFE_SB_DEFAULT_QOS, 3), CFE_SUCCESS);

/* Initialize the message content */
UtAssert_INT32_EQ(CFE_MSG_Init(CFE_MSG_PTR(CmdMsg.CommandHeader), CFE_FT_CMD_MSGID, sizeof(CmdMsg)), CFE_SUCCESS);
UtAssert_INT32_EQ(CFE_MSG_Init(CFE_MSG_PTR(TlmMsg.TelemetryHeader), CFE_FT_TLM_MSGID, sizeof(TlmMsg)), CFE_SUCCESS);

for (SendCount = 0; SendCount < 1000000; ++SendCount)
{
CmdMsg.CmdPayload = SendCount;
TlmMsg.TlmPayload = ~SendCount;

/* In order to not "flood" with test results, this should be silent unless a failure occurs */
CFE_Assert_STATUS_STORE(CFE_SB_TransmitMsg(CFE_MSG_PTR(CmdMsg.CommandHeader), true));
if (!CFE_Assert_STATUS_SILENTCHECK(CFE_SUCCESS))
{
break;
}

CFE_Assert_STATUS_STORE(CFE_SB_TransmitMsg(CFE_MSG_PTR(TlmMsg.TelemetryHeader), true));
if (!CFE_Assert_STATUS_SILENTCHECK(CFE_SUCCESS))
{
break;
}

CFE_Assert_STATUS_STORE(CFE_SB_ReceiveBuffer(&MsgBuf, PipeId1, CFE_SB_POLL));
if (!CFE_Assert_STATUS_SILENTCHECK(CFE_SUCCESS))
{
break;
}

/* As above, to avoid flooding of test cases, only report mismatch here */
CmdPtr = (const void *)MsgBuf;
if (CmdPtr->CmdPayload != CmdMsg.CmdPayload)
{
UtAssert_UINT32_EQ(CmdPtr->CmdPayload, CmdMsg.CmdPayload);
break;
}

CFE_Assert_STATUS_STORE(CFE_SB_ReceiveBuffer(&MsgBuf, PipeId2, CFE_SB_POLL));
if (!CFE_Assert_STATUS_SILENTCHECK(CFE_SUCCESS))
{
break;
}

TlmPtr = (const void *)MsgBuf;
if (TlmPtr->TlmPayload != TlmMsg.TlmPayload)
{
UtAssert_UINT32_EQ(TlmPtr->TlmPayload, TlmMsg.TlmPayload);
break;
}

/* report progress periodically */
if ((SendCount % 50000) == 0)
{
UtPrintf("Success after %lu messages", (unsigned long)SendCount);
}
}

CFE_PSP_GetTime(&ElapsedTime);
ElapsedTime = OS_TimeSubtract(ElapsedTime, StartTime);

UtAssert_MIR("Elapsed time for SB bulk message test: %lu usec", OS_TimeGetTotalMicroseconds(ElapsedTime));
}

void SBPerformanceTestSetup(void)
{
UtTest_Add(TestBulkTransmitRecv, NULL, NULL, "Test Bulk SB Transmit/Receive");
}

0 comments on commit 8753a09

Please sign in to comment.