/****************************************************************************** * * Copyright (c) 2019 Intel. * * 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. * *******************************************************************************/ /** * WLS interface test application * (contains functional unit tests and diagnostics to test wls * supported by WLS interface) */ #define _GNU_SOURCE #include // for printf #include // for memset #include // for SIGINT #include // for usleep #include // for rand #include // for getopt #include #include #include #include "ttypes.h" #include "wls_lib.h" #include "pool.h" #define HANDLE PVOID #define K 1024 #define M (K*K) #define DEFAULT_TEST_MEMORY_SIZE 256*M #define DEFAUTL_TEST_BLOCK_SIZE 16*K #define DEFAULT_MESSAGE_COUNT_PER_MS 10 #define DEFAULT_MAX_MESSAGE_SIZE 2000 #define DEFUALT_MIN_MESSAGE_SIZE 100 #define APP_QUEUE_SIZE 255 /* number of elements each queue of the WLS being registered will have */ #define MAX_MESSAGES 1000 /* per ms */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif typedef enum { APP_TC_SANITY_TEST = 0, } APP_TEST_CASES; typedef struct tagAPP_PARAMS { char *wls_dev_name; int aff_core; int test_id; int rx_id; int tx_id; int n_messages; int max_size; int min_size; int interface_count; U8 master; U8 debug; U8 crc; U8 trusted; } APP_PARAMS, *PAPP_PARAMS; typedef struct tagAPP_MESSAGE { U32 id; } APP_MESSAGE, *PAPP_MESSAGE; typedef struct tagAPP_CONTEXT { V32 ExitStatus; HANDLE hWls; U32 master; PVOID shm_memory; POOL Pool; // The pool descriptor void* PoolStrPtr; // The pool storage pointer to keep indexes U16 RxID; U16 TxID; U16 nInterfaces; // number of RX identifiers used by the APP // U16 InitQueueSize; // for invalid messages test (to trigger WLS blocking) // U32 MsgPerMs; U32 MaxMsgSize; U32 MinMsgSize; U32 TxCnt; U32 RxCnt; U64 nTxMsgs; // Messages transmitted U64 nTxOctets; // Octets transmitted U64 nRxMsgs; // Messages received U64 nRxOcters; // Octets received U64 Cycles; // number of 1ms cycles int AppSanityMsgSize; // 4 or 8 depending on CRC feature U8 Debug; // when TRUE app cycle is 1 sec, otherwise 1ms U8 TrustedDataSource; // for trusted data sources ICC service removes msg validity checking. void (*Receive)(HANDLE h); void (*Transmit)(HANDLE h); void (*ThreadReceive)(HANDLE h); void (*ThreadTransmit)(HANDLE h); int (*wls_put)(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags); unsigned long long (*wls_get)(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags); unsigned long long (*wls_wget)(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags); U8 *pLastRx; // used for scatter-gather test U32 LastRxSize; // used for scatter-gather test U32 *pServiceBuffer; U32 TxMsgCnt; PVOID TxMessages[MAX_MESSAGES]; U32 TxMessageSizes[MAX_MESSAGES]; // <-- required for Ping-Pong test to store received sizes int core; } APP_CONTEXT, *PAPP_CONTEXT; APP_CONTEXT AppContext; static int pool_alloc = 0; static int pool_free = 0; static void ShowData(void* ptr, unsigned int size) { U8 *d = ptr; unsigned int i; for (i = 0; i < size; i++) { if (!(i & 0xf)) printf("\n"); printf("%02x ", d[i]); } printf("\n"); } static void App_SigExitCallback(int signum) { (void) signum; AppContext.ExitStatus = TRUE; } static void* WlsVaToPa(void * ptr) { PAPP_CONTEXT pCtx = &AppContext; return (void*) WLS_VA2PA(pCtx->hWls, ptr); } static void* WlsPaToVa(void * ptr) { PAPP_CONTEXT pCtx = &AppContext; return (void*) WLS_PA2VA(pCtx->hWls, (U64) ptr); } static void* App_Alloc(void* h, unsigned long size) { (void) h; (void) size; void * retval = NULL; if (AppContext.master) { retval = PoolAlloc(&(AppContext.Pool)); //printf("pPool->FreeGet %d == pPool->FreePut %d\n", AppContext.Pool.FreeGet, AppContext.Pool.FreePut); } else { retval = (void*) WLS_DequeueBlock(AppContext.hWls); if (retval) retval = (void*) WlsPaToVa(retval); else printf("WLS_DequeueBlock returned null\n"); } if (retval == NULL) { printf("no memory %d %d\n", pool_alloc, pool_free); exit(-1); } else pool_alloc++; return retval; } static int App_Free(void* h, void* pMsg) { (void) h; if (AppContext.master) if (pMsg) { pool_free++; return (PoolFree(&(AppContext.Pool), pMsg) == 1 ? 0 : -1); } else { printf("Free Null pointer\n"); exit(-1); } else return 0; } static int App_MemoryInit(void* h, unsigned long size, U32 BlockSize) { int ret = 0; unsigned long long* pUsed; unsigned long long* pFree; PAPP_CONTEXT pCtx = &AppContext; U32 nBlocksSlave = 0; U32 nElmNum = size / BlockSize - 1; // We need to allocate the memory for indexes and to initialize the // pool descriptor, (x+1) is used to prevent queues overflow pCtx->PoolStrPtr = malloc((nElmNum + 1) * 4 * sizeof (unsigned long long)); if (pCtx->PoolStrPtr == NULL) return -1; pFree = (unsigned long long*) pCtx->PoolStrPtr; pUsed = pFree + (nElmNum + 1); ret = PoolInit(&pCtx->Pool, h, nElmNum, BlockSize, pFree, pUsed); if (ret == 0) { if (AppContext.master) { int res = TRUE; /* allocate blocks for Slave to Master transmittion */ while (res) { void* pBlock = App_Alloc(AppContext.hWls, DEFAUTL_TEST_BLOCK_SIZE); if (pBlock) { res = WLS_EnqueueBlock(AppContext.hWls, (U64) WlsVaToPa(pBlock)); if (res) nBlocksSlave++; else App_Free(AppContext.hWls, pBlock); } else res = FALSE; } printf("Slave has %d free blocks\n", nBlocksSlave); } } return ret; } /********************************/ #define FAST_CRC16 1 #if (FAST_CRC16) const U8 mb_table_level1[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 }; const U8 mb_table_level2[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 }; #if 0 // big endian CPU U16 crc16(U16 crc, U8 data) { U8 index; U8 crc_Low = crc & 0xFF; U8 crc_High = crc >> 8; index = (crc_High ^ data) & 0xFF; crc_High = crc_Low ^ mb_table_level1[ index ]; crc_Low = mb_table_level2[ index ]; return (crc_High << 8) | crc_Low; } #else // little endian CPU #if 0 static U16 CRC16_Update(U16 crc, U8 data) { U8 index; U8 crc_High = crc >> 8; U8 crc_Low = crc & 0xFF; index = crc_Low ^ data; crc_Low = crc_High ^ mb_table_level1[ index ]; crc_High = mb_table_level2[ index ]; return (crc_High << 8) | crc_Low; } #endif #endif #if 0 /*********************************************** * CRC16 polynomial : X16 + X15 + X2 + 1 * * FAST CRC16 routine * * ---> pData - msg to be protected * * ---> size - msg size in bytes * * ---> aCRC - initializer (0xFFFF for 1st page)* * <--- crc16 * ***********************************************/ static U16 CRC16_NoInit(U16 aCRC, U8 *pData, U16 size) { if (!size) return aCRC; else { U8 index; U8 crc_High = aCRC >> 8; U8 crc_Low = aCRC & 0xFF; do { index = crc_Low ^ *pData++; crc_Low = crc_High ^ mb_table_level1[ index ]; crc_High = mb_table_level2[ index ]; } while (--size); return (crc_High << 8) | crc_Low; } } #endif #else // SLOW (canonic CRC16 calculation) /*********************************************** * CRC16 polynomial : X16 + X15 + X2 + 1 * * ---> pData - msg to be protected * * ---> size - msg size in bytes * * ---> aCRC - initializer (0xFFFF for 1st page)* * <--- crc16 * ***********************************************/ U16 CRC16_NoInit(U16 aCRC, U8 *pData, U16 size) { U8 i, tmp; if (!size) return aCRC; do { aCRC ^= *pData++; for (i = 0; i < 8; i++) { tmp = aCRC & 0x01; aCRC >>= 1; if (tmp) { aCRC ^= CRC16_DIVISOR; } } } while (--size); return aCRC; } #endif // FAST_CRC16 #define CRC32_INIT_VAL 0xFFFFFFFF #define CRC32_DIVISOR 0xA0000001 static U32 ICC_CRC32(U8 *pData, U32 size) { U32 retval = CRC32_INIT_VAL; U8 i, tmp; if (!size) return CRC32_INIT_VAL; // mean CRC error do { retval ^= *pData++; for (i = 8; i > 0; --i) { tmp = retval & 0x01; retval >>= 1; if (tmp) { retval ^= CRC32_DIVISOR; } } } while (--size); return retval; } #if 0 static U16 ICC_CRC16(U8 *pData, U16 size) { #define CRC16_ERROR (0xffff) return CRC16_NoInit(CRC16_ERROR, pData, size); // use 0xFFFF as first initializer } #endif static int app_PutMessageCRC(void* h, unsigned long long pMsg, unsigned int MsgSize, unsigned short MsgTypeID, unsigned short Flags) { U8 *p; U64 pMsgVa = (U64) WlsPaToVa((void*) pMsg); if (pMsgVa == 0) { return 0; } p = (U8 *) pMsgVa; #if 1 U32 crc = ICC_CRC32((U8 *) pMsgVa, MsgSize - sizeof (crc)); // CRC32 p[MsgSize - 4] = (crc >> 0) & 0xff; p[MsgSize - 3] = (crc >> 8) & 0xff; p[MsgSize - 2] = (crc >> 16) & 0xff; p[MsgSize - 1] = (crc >> 24) & 0xff; #else U16 crc = ICC_CRC16((U8 *) pMsg, MsgSize - sizeof (crc)); // CRC16 p[MsgSize - 2] = (crc >> 0) & 0xff; p[MsgSize - 1] = (crc >> 8) & 0xff; #endif return WLS_Put(h, (unsigned long long) pMsg, MsgSize, MsgTypeID, Flags); } static unsigned long long app_GetMessageCRC(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags) { U64 pMsgPa = WLS_Get(h, MsgSize, MsgTypeID, Flags); U64 pMsg = (U64) WlsPaToVa((void*) pMsgPa); if (pMsg) { U32 size = *MsgSize; #if 1 U32 crc = ICC_CRC32((U8*) pMsg, size); #else U16 crc = ICC_CRC16((U8*) pMsg, size); #endif if (crc != 0) { printf("CRC error detected for message %p, size_%lu\n", (void*) pMsg, (long) size); ShowData((U8*) pMsg, size); } } return pMsgPa; } static unsigned long long app_WGetMessageCRC(void* h, unsigned int *MsgSize, unsigned short *MsgTypeID, unsigned short *Flags) { U64 pMsgPa = WLS_WGet(h, MsgSize, MsgTypeID, Flags); U64 pMsg = (U64) WlsPaToVa((void*) pMsgPa); if (pMsg) { U32 size = *MsgSize; #if 1 U32 crc = ICC_CRC32((U8*) pMsg, size); #else U16 crc = ICC_CRC16((U8*) pMsg, size); #endif if (crc != 0) { printf("CRC error detected for message %p, size_%lu\n", (void*) pMsg, (long) size); ShowData((U8*) pMsg, size); } } return pMsgPa; } static void CreateMessage(PAPP_MESSAGE p, U32 size) { (void) size; p->id = AppContext.TxCnt++; } static void CheckMessage(PAPP_MESSAGE p, U32 size) { if (AppContext.RxCnt && p->id != AppContext.RxCnt) { // char buf[8*K]; printf("rx message(id_%llu)_%lx error expected_%lu, received_%lu\n", (long long) AppContext.nRxMsgs, (U64) p, (long) AppContext.RxCnt, (long) p->id); ShowData(p, size); // if (TL_GetStatistics(AppContext.hWls, buf, sizeof(buf))) // printf("%s", buf); } AppContext.RxCnt = p->id; AppContext.RxCnt += 1; } /** ******************************************************************************* * * @fn app_AllocMultiple * @brief used to allocate multiple blocks of the same size from the WLS * * @param[h] hWls - app thread WLS handle * @param[o] pMsgs - ptr to beginning of array of points to allocated blocks * @param[o] pMsgSizes - array to write size for each allocated blocks * @param[i] nMsgs - number of blocks to allocate * @return U32 - number of allocated blocks * * @description * The routine is used allocate multiple blocks from the ICC service, * the blocks are supposed to be same size blocks, satisfying * appContext.MaxMsgSize parameter. * In case the service is unable to provide requested number of blocks, * smaller count is allocated. The routine returns actual number of allocated * blocks * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static U32 app_AllocMultiple(HANDLE hWls, PVOID *pMsgs, U32 *pMsgSizes, U32 nMsgs) { unsigned n = 0; unsigned i, j; memset(pMsgs, 0x00, sizeof (PVOID) * nMsgs); while (nMsgs--) { pMsgs[n] = App_Alloc(hWls, AppContext.MaxMsgSize); pMsgSizes[n] = AppContext.MaxMsgSize; if (!pMsgs[n]) { printf("empty pool allocated_%u out of %lu\n", n, (long) AppContext.MsgPerMs); break; } n += 1; } // check for duplicated pointers for (i = 0; i < n; i++) { for (j = i + 1; j < n; j++) { if (pMsgs[i] == pMsgs[j]) { printf("duplicated pointer %p (msg_id1_%u, msg_id2_%u)\n", pMsgs[i], i, j); break; } } } return n; //ShowData(TxMessages, sizeof(TxMessages)); } /** ******************************************************************************* * * @fn app_SanityTestTransmitter * @brief transmitter of default test case (0). * * @param[h] hWls - app thread WLS handle * @return void * * @description * The routine is used in test case 0 (non-blocking sanity unit test) * The transmitter does allocate multiple blocks of the same size from the ICC * service. Then it fills each block with incremental counter and transfers * to other application specified by parameter TxID. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_SanityTestTransmitter(HANDLE hWls) { U8 *pMsg; unsigned n = app_AllocMultiple(hWls, AppContext.TxMessages, AppContext.TxMessageSizes, AppContext.MsgPerMs); unsigned fn = n; unsigned cnt = 0; unsigned k = 0; unsigned alloc = n; // lets transmit some message for test while (n--) { pMsg = AppContext.TxMessages[cnt++]; if (pMsg) { U32 size = (rand() % AppContext.MaxMsgSize); if (size < AppContext.MinMsgSize) size = AppContext.MinMsgSize; memset(pMsg, cnt, size); CreateMessage((PAPP_MESSAGE) pMsg, size); if ((AppContext.wls_put(hWls, (U64) WlsVaToPa(pMsg), size, AppContext.TxID, 0) != 0)) { printf("could not send the message_%p\n", pMsg); break; } else { k++; } AppContext.nTxOctets += size; AppContext.nTxMsgs += 1; } } if (alloc != k) printf("inorrect sent %d alloc %d \n", k, alloc); cnt = 0; while (fn--) { pMsg = AppContext.TxMessages[cnt++]; if (pMsg) { if (App_Free(hWls, pMsg) != 0) printf("could not release the message_%p\n", pMsg); } else printf("pMsg is NULL [%d]\n", cnt); } if (cnt != k) { printf("inorrect free sent %d free %d \nQuiting...\n", k, cnt); AppContext.ExitStatus = 1; } } #if 0 /** ******************************************************************************* * * @fn app_ScatterGatherTransmitter * @brief transmitter of default test case (15/16). * * @param[h] hWls - app thread WLS handle * @return void * * @description * The routine is used in test case 0 (non-blocking sanity unit test) * The transmitter does allocate multiple blocks of the same size from the ICC * service. Then it fills each block with incremental counter and transfers * to other application specified by parameter TxID. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_ScatterGatherTransmitter(HANDLE hWls) { U8 *pMsg; unsigned n = app_AllocMultiple(hWls, AppContext.TxMessages, AppContext.TxMessageSizes, AppContext.MsgPerMs + 2); unsigned i, cnt = 0, flags = 0; U8 *p, *pOriginMsg = (U8 *)App_Alloc(hWls, AppContext.MaxMsgSize); unsigned TotalSize = 0; unsigned fn = n; unsigned k = 0; unsigned alloc = n; if (!pOriginMsg) { printf("No memory for App_Alloc()\n"); return; } flags = rand() & 0xff; for(i = 0; i < AppContext.MaxMsgSize; i++) pOriginMsg[i] = (flags + i) & 0xff; // scatter original message among several blocks for(i = 0; i < n; i++) { U32 size = (rand() % (AppContext.MaxMsgSize / n)); if (size < AppContext.MinMsgSize) size = AppContext.MinMsgSize; TotalSize += size; AppContext.TxMessageSizes[i] = size; //printf("size%d=%lu\n", i, size); } // adjust size of the last block if (TotalSize < AppContext.MaxMsgSize) { AppContext.TxMessageSizes[n - 1] += AppContext.MaxMsgSize - TotalSize; } else if (TotalSize > AppContext.MaxMsgSize) { printf("error: size of the scatted blocks exceeding size of the original message\n"); } p = pOriginMsg; for(i = 0; i < n; i++) { // copy data into the scattered blocks pMsg = AppContext.TxMessages[i]; memcpy(pMsg, p, AppContext.TxMessageSizes[i]); p += AppContext.TxMessageSizes[i]; } // transmit original message first if (AppContext.wls_put(hWls, (U64)WlsVaToPa(pOriginMsg), AppContext.MaxMsgSize, AppContext.TxID, 0) != 0) { printf("could not send the message_%p\n", pOriginMsg); if (App_Free(hWls, pOriginMsg) != 0) printf("could not release the message_%p\n", pOriginMsg); } else { AppContext.nTxOctets += AppContext.MaxMsgSize; AppContext.nTxMsgs += 1; } if(pOriginMsg){ if (App_Free(hWls, pOriginMsg) != 0) printf("could not release the message_%p\n", pMsg); } else printf("pOriginMsg is NULL \n"); // transmit scattered messages following their creation order while (n--) { pMsg = AppContext.TxMessages[cnt]; if (!cnt) flags = WLS_SG_FIRST; else if (n == 0) flags = WLS_SG_LAST; else flags = WLS_SG_NEXT; if (AppContext.wls_put(hWls, (U64)WlsVaToPa(pMsg), AppContext.TxMessageSizes[cnt], AppContext.TxID, flags) != 0) { printf("could not send the message_%p\n", pMsg); if (App_Free(hWls, pMsg) != 0) printf("could not release the message_%p\n", pMsg); } else k++; AppContext.nTxOctets += AppContext.TxMessageSizes[cnt]; AppContext.nTxMsgs += 1; cnt++; } if(alloc != k) printf("inorrect sent %d alloc %d \n", k, alloc); cnt = 0; while (fn--) { pMsg = AppContext.TxMessages[cnt++]; if(pMsg){ if (App_Free(hWls, pMsg) != 0) printf("could not release the message_%p\n", pMsg); } else printf("pMsg is NULL [%d]\n", cnt); } if(cnt != k) printf("inorrect free sent %d free %d \n", k, cnt); } #endif /** ******************************************************************************* * * @fn app_SanityTestReceiver * @brief default sanity checking receiver used in multiple tests. * * @param[h] hWls - app thread WLS handle * @return void * * @description * The routine takes received messages and checks the sanity incremental * counter to confirm the order. In case the counter does not correspond to * expected counter (misordered message or incorrect message) an error is * printed to STDOUT. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_SanityTestReceiver(HANDLE hWls) { (void) hWls; U32 MsgSize; U8 *pMsg; U8 *pMsgPa; U8 *pMsgVa; U8 TempBuf[16 * K]; unsigned short MsgTypeID; unsigned short Flags; U32 nBlocksSlave = 0; // handle RX receiver while (((pMsgPa = (U8 *) AppContext.wls_get(AppContext.hWls, &MsgSize, &MsgTypeID, &Flags)) != NULL)) { pMsgVa = (U8 *) WlsPaToVa(pMsgPa); if (pMsgVa == NULL) { printf("va: %lx pa: %lx\n", (long) pMsgVa, (long) pMsgPa); continue; } pMsg = pMsgVa; if (((U64) pMsg & 0x3) == 0) { // aligned message CheckMessage((PAPP_MESSAGE) pMsg, MsgSize); } else { // misaligned message printf("Unaligned message\n"); MsgSize = (MsgSize > sizeof (TempBuf)) ? sizeof (TempBuf) : MsgSize; memcpy(TempBuf, pMsg, MsgSize); // handle received message CheckMessage((PAPP_MESSAGE) TempBuf, MsgSize); } App_Free(AppContext.hWls, pMsg); AppContext.nRxOcters += MsgSize; AppContext.nRxMsgs += 1; if (AppContext.master) { int res = TRUE; /* allocate blocks for Slave to Master transmittion */ while (res) { void* pBlock = App_Alloc(AppContext.hWls, DEFAUTL_TEST_BLOCK_SIZE); if (pBlock) { res = WLS_EnqueueBlock(AppContext.hWls, (U64) WlsVaToPa(pBlock)); if (res) nBlocksSlave++; else App_Free(AppContext.hWls, pBlock); } else res = FALSE; } } } } #if 0 /** ******************************************************************************* * * @fn app_ScatterGatherReceiver * @brief scatter gather test receiver * * @param[h] hWls - app thread WLS handle * @return void * * @description * The routine takes received messages and checks the sanity incremental * counter to confirm the order. In case the counter does not correspond to * expected counter (misordered message or incorrect message) an error is * printed to STDOUT. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_ScatterGatherReceiver(HANDLE hWls) { (void)hWls; U32 MsgSize; U8 *pMsg; U8 *pMsgPa; U8 *pMsgVa; U32 size; U8 err = 0; unsigned short MsgTypeID; unsigned short Flags; // handle RX receiver while ((pMsgPa = (U8*) AppContext.wls_get(AppContext.hWls, &MsgSize, &MsgTypeID, &Flags)) != NULL) { pMsgVa = (U8 *)WlsPaToVa(pMsgPa); pMsg = pMsgVa; AppContext.nRxOcters += MsgSize; AppContext.nRxMsgs += 1; if (!AppContext.pLastRx) { AppContext.pLastRx = pMsg; AppContext.LastRxSize = MsgSize; } else // compare with received and release both { U32 i; if (AppContext.LastRxSize != MsgSize) printf("received wrong size, unsync? try to re-run app both clusters\n"); size = MsgSize; if (size > AppContext.LastRxSize) size = AppContext.LastRxSize; for(i = 0; i < size; i++) { if (pMsg[i] != AppContext.pLastRx[i]) { // error content doesn't match err = TRUE; break; } } if (err) { printf("content verification failed, scatter-gather test FAIL\n"); // terminate AppContext.Receive = NULL; AppContext.Transmit = NULL; App_Free(AppContext.hWls, pMsg); App_Free(AppContext.hWls, AppContext.pLastRx); return; } App_Free(AppContext.hWls, pMsg); App_Free(AppContext.hWls, AppContext.pLastRx); AppContext.pLastRx = NULL; } } } static U32 app_GetTime(void) { struct timeval tv; U32 time_ms = 0; if (gettimeofday(&tv, NULL) == 0) time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; return time_ms; } #endif /****************************************************************************** * * * Application common routines * * * ******************************************************************************/ /** ******************************************************************************* * * @fn app_UpdateStatistics * @brief is used to update RX and TX statistics * * @param[n] void * @return void * * @description * The routine prints out the statistics of received and transmitted * messages. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_UpdateStatistics(void) { AppContext.Cycles += 1; if (AppContext.Debug || AppContext.Cycles % 1000 == 0) { printf("Rx(id_%u) (%llu) - (%llu KiB)\n", AppContext.RxID, (long long) AppContext.nRxMsgs, (long long) AppContext.nRxOcters >> 10); printf("Tx(id_%u) (%llu) - (%llu KiB)\n", AppContext.TxID, (long long) AppContext.nTxMsgs, (long long) AppContext.nTxOctets >> 10); } } /** ******************************************************************************* * * @fn app_Help * @brief prints app help content * * @param[n] void * @return void * * @description * The routine is used to print help content to stdout. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_Help(void) { char help_content[] = \ "WLS test application\n\n"\ "Usage: testapp [-c ] [-r ] [-t ] [-n ]\n\n"\ "supports the following parameters:\n\n" "-c | --testcase 0 - default sanity test\n"\ " 1 - misaligned pointers test\n"\ " 2 - aligned 4 pointers test\n"\ " 3 - random pools test\n"\ " 4 - ping-pong (ZBC test)\n"\ " 5 - invalid messages test\n\n"\ "--trusted switches WLS to trusted mode\n"\ "-r | --rxid used to specify RxTypeID\n"\ "-t | --txid used to specify TxTypeID\n"\ "-n | --msgcount used to specify number of messages per timeframe\n"\ "-l | --minsize specifies MIN message size in bytes\n"\ "-s | --maxsize specifies MAX message size in bytes\n"\ "--crc enables CRC generation and checking\n"\ "--debug increases sleep interval to 1 second\n"\ "-m | --master set predefined rxid and txid\n"; printf("%s", help_content); } /** ******************************************************************************* * * @fn app_ParseArgs * @brief is used to parse incoming app args * * @param[i] argc - app arg count * @param[i] argv - array of args * @param[o] params - app startup params filled basing on args parse * @return number of parsed args * * @description * The routine is parse input args and convert them into app startup params * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static int app_ParseArgs(int argc, char ** argv, PAPP_PARAMS params) { int c; int *pInt; int cnt = 0; struct option long_options[] = { {"wlsdev", required_argument, 0, 'w'}, {"affinity", required_argument, 0, 'a'}, {"testcase", required_argument, 0, 'c'}, {"rxid", required_argument, 0, 'r'}, {"txid", required_argument, 0, 't'}, {"msgcount", required_argument, 0, 'n'}, {"maxsize", required_argument, 0, 's'}, {"minsize", required_argument, 0, 'l'}, {"master", no_argument, 0, 'm'}, {"debug", no_argument, 0, 'd'}, /* slow down the app cycle from 1ms to 1s*/ {"icount", required_argument, 0, 'i'}, {"crc", no_argument, 0, 1}, {"trusted", no_argument, 0, 2}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; memset(params, 0, sizeof (*params)); // set default values here params->interface_count = 1; while (1) { //int this_option_optind = optind ? optind : 1; int option_index = 0; c = getopt_long(argc, argv, "a:w:c:r:t:n:s:l:mdi:h", long_options, &option_index); if (c == -1) break; cnt += 1; pInt = NULL; switch (c) { case 'a': // test Case selection pInt = ¶ms->aff_core; break; case 'c': // test Case selection pInt = ¶ms->test_id; break; case 'r': // rx id selection pInt = ¶ms->rx_id; break; case 't': // tx id selection pInt = ¶ms->tx_id; break; case 's': // select message size pInt = ¶ms->max_size; break; case 'l': // select message size pInt = ¶ms->min_size; break; case 'n': // select number of messages pInt = ¶ms->n_messages; break; case 'i': // select number of interfaces to register pInt = ¶ms->interface_count; break; case 'm': params->master = TRUE; break; case 'd': params->debug = TRUE; break; case 'w': params->wls_dev_name = optarg; break; case 'h': app_Help(); exit(0); case 2: params->trusted = TRUE; break; case 1: // crc checking enabled params->crc = TRUE; break; } if (pInt && optarg) { // get int arg if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) { sscanf(optarg, "%x", (unsigned *) pInt); } else { *pInt = atoi(optarg); } } } return cnt; } static int app_set_affinity(int coreNum) { cpu_set_t cpuset; int i, rc; /* set main thread affinity mask to CPU7 */ CPU_ZERO(&cpuset); CPU_SET(coreNum, &cpuset); rc = pthread_setaffinity_np(pthread_self(), sizeof (cpu_set_t), &cpuset); if (rc) { perror("pthread_setaffinity_np failed"); printf("pthread_setaffinity_np failed: %d", rc); } /* check the actual affinity mask assigned to the thread */ CPU_ZERO(&cpuset); rc = pthread_getaffinity_np(pthread_self(), sizeof (cpu_set_t), &cpuset); if (rc) { perror("pthread_getaffinity_np failed"); printf("pthread_getaffinity_np failed: %d", rc); } printf("set affinity: "); for (i = 0; i < CPU_SETSIZE; i++) if (CPU_ISSET(i, &cpuset)) printf(" CPU %d\n", i); if (!CPU_ISSET(coreNum, &cpuset)) { printf("affinity failed"); } /** A new thread created by pthread_create(3) inherits a copy of its creator's CPU affinity mask. */ return rc; } /** ******************************************************************************* * * @fn app_ApplyParams * @brief is used to apply application startup parameters * * @param[i] params - app startup params * @return void * * @description * The applies startup parameters * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_ApplyParams(PAPP_PARAMS params) { // apply parameters printf("selected test case %d - ", params->test_id); switch (params->test_id) { case APP_TC_SANITY_TEST: default: printf("NON-BLOCKING SANITY TEST\n"); AppContext.Receive = app_SanityTestReceiver; AppContext.Transmit = app_SanityTestTransmitter; break; } AppContext.wls_put = WLS_Put; AppContext.wls_get = WLS_Get; AppContext.wls_wget = WLS_WGet; AppContext.MsgPerMs = DEFAULT_MESSAGE_COUNT_PER_MS; AppContext.MaxMsgSize = DEFAULT_MAX_MESSAGE_SIZE; AppContext.MinMsgSize = DEFUALT_MIN_MESSAGE_SIZE; AppContext.AppSanityMsgSize = sizeof (APP_MESSAGE); if (params->master) { printf("WLS test app (supposed to run as MEMORY MASTER)\n"); AppContext.master = TRUE; AppContext.RxID = 1; AppContext.TxID = 2; } else { AppContext.master = FALSE; AppContext.RxID = 2; AppContext.TxID = 1; } if (params->rx_id) AppContext.RxID = params->rx_id; if (params->tx_id) AppContext.TxID = params->tx_id; if (params->n_messages && params->n_messages < MAX_MESSAGES) AppContext.MsgPerMs = params->n_messages; if (params->min_size && params->min_size >= 4) AppContext.MinMsgSize = params->min_size; // default is 1 RX interface printf("if count = %u\n", params->interface_count); AppContext.nInterfaces = 1; if (params->interface_count == 0) { printf("WLS test app started as simple data source, no RX ID will be specified\n"); AppContext.nInterfaces = 0; AppContext.RxID = 0; // override RxID } else if (params->interface_count <= 7) { AppContext.nInterfaces = params->interface_count; } AppContext.TrustedDataSource = params->trusted; if (params->crc) { if (AppContext.MinMsgSize < 8) AppContext.MinMsgSize = 8; AppContext.wls_put = app_PutMessageCRC; AppContext.wls_get = app_GetMessageCRC; AppContext.wls_wget = app_WGetMessageCRC; AppContext.AppSanityMsgSize += 4; // + sizeof CRC } if (params->max_size && params->max_size <= 16 * K) AppContext.MaxMsgSize = params->max_size; if (params->max_size < params->min_size) params->max_size = params->min_size; AppContext.Debug = params->debug; if (params->aff_core) { AppContext.core = params->aff_core; app_set_affinity(AppContext.core); } printf("The application started with:\n"); printf("Core ................ %d\n", AppContext.core); printf("Rx interface count .. %d\n", AppContext.nInterfaces); printf("RxID ................ %d\n", AppContext.RxID); printf("TxID ................ %d\n", AppContext.TxID); if (AppContext.Debug) printf("Generating .......... %lu Messages per second (DEBUG MODE)\n", (long) AppContext.MsgPerMs); else printf("Generating .......... %lu Messages per ms\n", (long) AppContext.MsgPerMs); printf("Max Message Size .... %lu bytes\n", (long) AppContext.MaxMsgSize); printf("Min Message Size .... %lu bytes\n", (long) AppContext.MinMsgSize); printf("Number of threads ... 1\n"); printf("CRC checking ........ "); if (params->crc) printf("ENABLED\n"); else printf("DISABLED\n"); } /** ******************************************************************************* * * @fn app_ReleaseAllocatedBuffers * @brief releases ICC buffers allocated by the application * * @param[n] void * @return void * * @description * In process of making some tests when signal to close the application * happens the app may keep some allocated buffers from the ICC pools. This * routine does release these buffers back to ICC. * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ******************************************************************************/ static void app_ReleaseAllocatedBuffers(void) { if (AppContext.TxMsgCnt && AppContext.master) do { AppContext.TxMsgCnt -= 1; App_Free(AppContext.hWls, AppContext.TxMessages[ AppContext.TxMsgCnt ]); } while (AppContext.TxMsgCnt != 0); } /** ******************************************************************************* * * @fn main * @brief ICC test application main routine * * @param[n] void * @return void * * @description * Contains logic of the test (one RX/TX thread) * * @references * MS-111070-SP * * @ingroup icc_service_unit_test * ****************************************************************************/ int main(int argc, char* argv[]) { int retval = 0; APP_PARAMS params; signal(SIGINT, App_SigExitCallback); memset(&AppContext, 0, sizeof (AppContext)); memset(¶ms, 0, sizeof (params)); #ifdef DPDK_WLS int ret = rte_eal_init(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); argc -= ret; argv += ret; #endif app_ParseArgs(argc, argv, ¶ms); app_ApplyParams(¶ms); AppContext.InitQueueSize = APP_QUEUE_SIZE; AppContext.hWls = WLS_Open(params.wls_dev_name, AppContext.master, DEFAULT_TEST_MEMORY_SIZE); if (!AppContext.hWls) { printf("could not register WLS client\n"); return 1; } else { printf("WLS has been registered\n"); } AppContext.shm_memory = WLS_Alloc(AppContext.hWls, DEFAULT_TEST_MEMORY_SIZE); if (AppContext.shm_memory == NULL) { if (AppContext.master) printf("could not create WLS shared memory\n"); else printf("could not attach WLS shared memory\n"); return -1; } if (AppContext.master) { if (App_MemoryInit(AppContext.shm_memory, DEFAULT_TEST_MEMORY_SIZE, DEFAUTL_TEST_BLOCK_SIZE) != 0) { WLS_Free(AppContext.hWls, AppContext.shm_memory); WLS_Close(AppContext.hWls); exit(1); } } // APPLICATION MAIN LOOP while (!AppContext.ExitStatus && (AppContext.Receive || AppContext.Transmit)) { if (AppContext.Receive) AppContext.Receive(AppContext.hWls); if (AppContext.Debug) //usleep(10000); // 1 sec delay sleep(1); // 1 sec delay else usleep(1000); // 1 ms delay if (AppContext.Transmit) AppContext.Transmit(AppContext.hWls); app_UpdateStatistics(); } app_ReleaseAllocatedBuffers(); printf("deregistering WLS (TxTotal_%llu, RxTotal_%llu)\n", (long long) AppContext.nTxMsgs, (long long) AppContext.nRxMsgs); WLS_Free(AppContext.hWls, AppContext.shm_memory); WLS_Close(AppContext.hWls); return retval; }