X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=o-du%2Fphy.git;a=blobdiff_plain;f=wls_lib%2Ftestapp%2Ftestapp.c;fp=wls_lib%2Ftestapp%2Ftestapp.c;h=1bd9a84e1d1620b13f40c88d166dc6c388a69e18;hp=0000000000000000000000000000000000000000;hb=9d66fca5c45c8b3e0d6eab6d51a90c8e9d2614dc;hpb=2fbf70096f64af622da983e88c5a64e90ad9bdbd diff --git a/wls_lib/testapp/testapp.c b/wls_lib/testapp/testapp.c new file mode 100644 index 0000000..1bd9a84 --- /dev/null +++ b/wls_lib/testapp/testapp.c @@ -0,0 +1,1486 @@ +/****************************************************************************** +* +* 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; +}