sonic-buildimage/platform/nephos/nephos-modules/modules/src/netif_perf.c
simonJi2018 259d51a94f [nephos]: upgrade compile sdk.deb from online to dpkg and fix compile error (#2800)
* upgrade compile sdk.deb from online to dpkg and upgrade docker syncd and orchagent to stretch

* Delete docker-orchagent-nephos.mk

Delete docker-orchagent-nephos.mk

* Update docker-syncd-nephos.mk

* Update Dockerfile.j2
2019-04-29 18:25:40 -07:00

657 lines
20 KiB
C
Executable File

/* Copyright (C) 2019 Nephos, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program.
*/
/* FILE NAME: netif_perf.c
* PURPOSE:
* It provide customer performance test API.
* NOTES:
*/
#include <nps_error.h>
#include <nps_types.h>
#include <netif_osal.h>
#include <netif_perf.h>
#if defined (NPS_EN_TAURUS)
#include <hal_tau_pkt_knl.h>
#endif
/* -------------------------------------------------------------- switch */
#if defined (NPS_EN_ARIES)
#define PERF_TX_CHANNEL_NUM_MAX (HAL_ARI_PKT_TX_CHANNEL_LAST)
#define PERF_RX_CHANNEL_NUM_MAX (HAL_ARI_PKT_RX_CHANNEL_LAST)
typedef HAL_ARI_PKT_TX_SW_GPD_T PERF_TX_SW_GPD;
typedef HAL_ARI_PKT_RX_SW_GPD_T PERF_RX_SW_GPD;
#endif
#if defined (NPS_EN_TAURUS)
#define PERF_TX_CHANNEL_NUM_MAX (HAL_TAU_PKT_TX_CHANNEL_LAST)
#define PERF_RX_CHANNEL_NUM_MAX (HAL_TAU_PKT_RX_CHANNEL_LAST)
typedef HAL_TAU_PKT_TX_SW_GPD_T PERF_TX_SW_GPD;
typedef HAL_TAU_PKT_RX_SW_GPD_T PERF_RX_SW_GPD;
#endif
/* -------------------------------------------------------------- common */
#define PERF_TX_PERF_NUM (1000000) /* max: 4294967 */
#define PERF_TX_PERF_MESG (50000)
#define PERF_TX_PERF_FAIL (10000)
#define PERF_RX_PERF_NUM (1000000) /* max: 4294967 */
#define PERF_RX_PERF_MESG (50000)
#define PERF_RX_PERF_FAIL (10000)
/* -------------------------------------------------------------- callbacks for chip dependency */
/* Tx */
typedef NPS_ERROR_NO_T
(*PERF_TX_GET_INTR_T)(
const UI32_T unit,
const UI32_T channel,
UI32_T *ptr_intr_cnt);
typedef NPS_ERROR_NO_T
(*PERF_TX_GET_NETDEV_T)(
const UI32_T unit,
const UI32_T port,
struct net_device **pptr_net_dev);
typedef NPS_ERROR_NO_T
(*PERF_TX_PREPARE_GPD_T)(
const UI32_T unit,
const NPS_ADDR_T phy_addr,
const UI32_T len,
const UI32_T port,
PERF_TX_SW_GPD *ptr_sw_gpd);
typedef NPS_ERROR_NO_T
(*PERF_TX_SEND_GPD_T)(
const UI32_T unit,
const UI32_T channel,
PERF_TX_SW_GPD *ptr_sw_gpd);
/* Rx */
typedef NPS_ERROR_NO_T
(*PERF_RX_GET_INTR_T)(
const UI32_T unit,
const UI32_T channel,
UI32_T *ptr_intr_cnt);
/* -------------------------------------------------------------- structs */
typedef enum
{
PERF_DIR_TX = 0,
PERF_DIR_RX,
PERF_DIR_LAST,
} PERF_DIR_T;
typedef struct
{
UI32_T unit;
UI32_T channel;
UI32_T len;
UI32_T num;
UI32_T port;
BOOL_T test_skb;
} PERF_COOKIE_T;
typedef struct
{
/* netif-only */
PERF_COOKIE_T tx_cookie [PERF_TX_CHANNEL_NUM_MAX];
NPS_THREAD_ID_T tx_task [PERF_TX_CHANNEL_NUM_MAX];
NPS_SEMAPHORE_ID_T start_sync [PERF_TX_CHANNEL_NUM_MAX];
NPS_SEMAPHORE_ID_T end_sync [PERF_TX_CHANNEL_NUM_MAX];
UI32_T send_ok [PERF_TX_CHANNEL_NUM_MAX];
UI32_T send_fail [PERF_TX_CHANNEL_NUM_MAX];
/* chip dependent callbacks */
PERF_TX_GET_INTR_T get_intr_cnt;
PERF_TX_GET_NETDEV_T get_netdev;
PERF_TX_PREPARE_GPD_T prepare_gpd;
PERF_TX_SEND_GPD_T send_gpd;
} PERF_TX_PERF_CB_T;
typedef struct
{
/* netif-only */
BOOL_T rx_test;
NPS_SEMAPHORE_ID_T start_sync;
NPS_SEMAPHORE_ID_T end_sync;
UI32_T target_num;
UI32_T target_len;
UI32_T recv_pass;
UI32_T recv_fail;
/* duplicate packets */
UI32_T rch_qid_map_lo [PERF_RX_CHANNEL_NUM_MAX];
UI32_T rch_qid_map_hi [PERF_RX_CHANNEL_NUM_MAX];
/* chip dependent callbacks */
PERF_RX_GET_INTR_T get_intr_cnt;
} PERF_RX_PERF_CB_T;
/* -------------------------------------------------------------- statics */
static PERF_TX_PERF_CB_T _perf_tx_perf_cb =
{
#if defined (NPS_EN_ARIES)
.get_intr_cnt = hal_ari_pkt_getTxIntrCnt,
.get_netdev = hal_ari_pkt_getNetDev, /* test_skb = TRUE */
.prepare_gpd = hal_ari_pkt_prepareGpd, /* test_skb = FALSE */
.send_gpd = hal_ari_pkt_sendGpd, /* test_skb = FALSE */
#endif
#if defined (NPS_EN_TAURUS)
.get_intr_cnt = hal_tau_pkt_getTxIntrCnt,
.get_netdev = hal_tau_pkt_getNetDev, /* test_skb = TRUE */
.prepare_gpd = hal_tau_pkt_prepareGpd, /* test_skb = FALSE */
.send_gpd = hal_tau_pkt_sendGpd, /* test_skb = FALSE */
#endif
};
static PERF_RX_PERF_CB_T _perf_rx_perf_cb =
{
#if defined (NPS_EN_ARIES)
.get_intr_cnt = hal_ari_pkt_getRxIntrCnt,
#endif
#if defined (NPS_EN_TAURUS)
.get_intr_cnt = hal_tau_pkt_getRxIntrCnt,
#endif
};
/* -------------------------------------------------------------- functions */
static void
_perf_duplicateRxPacket(
const UI32_T unit,
const UI32_T rx_channel,
const BOOL_T enable)
{
;
}
static void
_perf_showPerf(
PERF_DIR_T dir,
UI32_T channel,
UI32_T len,
UI32_T num,
UI32_T intr,
UI32_T duration)
{
UI32_T tx_channel = 0;
UI32_T tx_fail = 0;
if (duration < 1000)
{
osal_printf("***Error***, %d packets cost < 1000 us.\n", num);
return ;
}
osal_printf("\n");
if (PERF_DIR_TX == dir)
{
osal_printf("Tx-perf\n");
}
else
{
osal_printf("Rx-perf\n");
}
osal_printf("------------------------------------\n");
osal_printf("channel number : %d\n", channel);
osal_printf("packet length (bytes): %d\n", len);
osal_printf("packet number : %d\n", num);
osal_printf("time duration (us) : %d\n", duration);
osal_printf("------------------------------------\n");
osal_printf("avg. packet rate (pps) : %d\n", (num * 1000) / (duration / 1000));
osal_printf("avg. throughput (Mbps) : %d\n", ((num / 1000) * len * 8) / (duration / 1000));
osal_printf("interrupt number : %d\n", intr);
if (PERF_DIR_TX == dir)
{
for (tx_channel = 0; tx_channel < channel; tx_channel++)
{
tx_fail += _perf_tx_perf_cb.send_fail[tx_channel];
}
osal_printf("Tx fail : %d\n", tx_fail);
}
osal_printf("------------------------------------\n");
}
static void
_perf_getIntrCnt(
UI32_T unit,
PERF_DIR_T dir,
UI32_T *ptr_intr_cnt)
{
UI32_T intr_cnt = 0;
UI32_T channel = 0;
if (PERF_DIR_TX == dir)
{
for (channel = 0; channel < PERF_TX_CHANNEL_NUM_MAX; channel++)
{
_perf_tx_perf_cb.get_intr_cnt(unit, channel, &intr_cnt);
*ptr_intr_cnt += intr_cnt;
}
}
else
{
for (channel = 0; channel < PERF_RX_CHANNEL_NUM_MAX; channel++)
{
_perf_rx_perf_cb.get_intr_cnt(unit, channel, &intr_cnt);
*ptr_intr_cnt += intr_cnt;
}
}
}
static void
_perf_txCallback(
const UI32_T unit,
PERF_TX_SW_GPD *ptr_sw_gpd,
void *ptr_virt_addr)
{
/* free dma */
osal_dma_free(ptr_virt_addr);
/* free gpd */
osal_free(ptr_sw_gpd);
}
static void
_perf_txTask(
void *ptr_argv)
{
NPS_ERROR_NO_T rc = NPS_E_OK;
UI32_T unit = ((PERF_COOKIE_T *)ptr_argv)->unit;
UI32_T channel = ((PERF_COOKIE_T *)ptr_argv)->channel;
UI32_T len = ((PERF_COOKIE_T *)ptr_argv)->len;
UI32_T num = ((PERF_COOKIE_T *)ptr_argv)->num;
UI32_T port = ((PERF_COOKIE_T *)ptr_argv)->port;
BOOL_T test_skb = ((PERF_COOKIE_T *)ptr_argv)->test_skb;
/* test targets */
PERF_TX_SW_GPD *ptr_sw_gpd = NULL;
struct sk_buff *ptr_skb = NULL;
/* temp variables */
UI32_T send_fail = 0;
void *ptr_virt_addr = NULL;
NPS_ADDR_T phy_addr = 0x0;
osal_initRunThread();
do
{
rc = osal_waitEvent(&_perf_tx_perf_cb.start_sync[channel]);
if (NPS_E_OK != osal_isRunThread())
{
break; /* deinit-thread */
}
while (_perf_tx_perf_cb.send_ok[channel] < num)
{
if (0 == (_perf_tx_perf_cb.send_ok[channel] % PERF_TX_PERF_MESG))
{
printk("T");
}
if (TRUE == test_skb)
{
ptr_skb = osal_skb_alloc(len);
ptr_skb->len = len;
_perf_tx_perf_cb.get_netdev(unit, port, &ptr_skb->dev);
/* send skb */
osal_skb_send(ptr_skb);
}
else
{
ptr_sw_gpd = osal_alloc(sizeof(PERF_TX_SW_GPD));
if (NULL == ptr_sw_gpd)
{
osal_printf("***Error***, alloc sw-gpd fail.\n");
break;
}
/* prepare buf */
ptr_virt_addr = osal_dma_alloc(len);
phy_addr = osal_dma_convertVirtToPhy(ptr_virt_addr);
/* trans skb to gpd */
osal_memset(ptr_sw_gpd, 0x0, sizeof(PERF_TX_SW_GPD));
ptr_sw_gpd->callback = (void *)_perf_txCallback;
ptr_sw_gpd->ptr_cookie = (void *)ptr_virt_addr;
ptr_sw_gpd->gpd_num = 1;
ptr_sw_gpd->ptr_next = NULL;
ptr_sw_gpd->channel = channel;
/* prepare gpd */
rc = _perf_tx_perf_cb.prepare_gpd(unit, phy_addr, len, port, ptr_sw_gpd);
/* send gpd */
rc = _perf_tx_perf_cb.send_gpd(unit, channel, ptr_sw_gpd);
if (NPS_E_OK == rc)
{
_perf_tx_perf_cb.send_ok[channel]++;
send_fail = 0;
}
else
{
_perf_tx_perf_cb.send_fail[channel]++;
if (send_fail++ >= PERF_TX_PERF_FAIL)
{
osal_printf("***Error***, Tch-%d send fail over %d packet(s). (rc: %d)\n",
channel, PERF_TX_PERF_FAIL, rc);
break;
}
_perf_txCallback(unit, ptr_sw_gpd, ptr_virt_addr);
osal_sleepThread(1000);
}
}
}
osal_triggerEvent(&_perf_tx_perf_cb.end_sync[channel]);
}
while (NPS_E_OK == osal_isRunThread());
osal_exitRunThread();
}
static void
_perf_txDeinit(
const UI32_T unit,
const UI32_T tx_channel)
{
UI32_T channel = 0;
for (channel = 0; channel < tx_channel; channel++)
{
/* destroy Tx resources */
osal_stopThread (&_perf_tx_perf_cb.tx_task [channel]);
osal_triggerEvent(&_perf_tx_perf_cb.start_sync [channel]);
osal_destroyThread(&_perf_tx_perf_cb.tx_task [channel]);
osal_destroyEvent(&_perf_tx_perf_cb.end_sync [channel]);
osal_destroyEvent(&_perf_tx_perf_cb.start_sync [channel]);
}
}
static void
_perf_txInit(
const UI32_T unit,
const UI32_T tx_channel,
const UI32_T len,
BOOL_T test_skb)
{
UI32_T channel = 0;
for (channel = 0; channel < tx_channel; channel++)
{
_perf_tx_perf_cb.send_ok [channel] = 0;
_perf_tx_perf_cb.send_fail[channel] = 0;
/* create Tx resources */
osal_createEvent("TX_START", &_perf_tx_perf_cb.start_sync [channel]);
osal_createEvent("TX_END", &_perf_tx_perf_cb.end_sync [channel]);
_perf_tx_perf_cb.tx_cookie[channel].unit = unit;
_perf_tx_perf_cb.tx_cookie[channel].channel = channel;
_perf_tx_perf_cb.tx_cookie[channel].len = len;
_perf_tx_perf_cb.tx_cookie[channel].num = PERF_TX_PERF_NUM / tx_channel;
_perf_tx_perf_cb.tx_cookie[channel].port = 0;
_perf_tx_perf_cb.tx_cookie[channel].test_skb = test_skb;
osal_createThread(
"TX_PERF", 64 * 1024, 90,
_perf_txTask,
(void *)&_perf_tx_perf_cb.tx_cookie[channel],
&_perf_tx_perf_cb.tx_task[channel]);
}
}
static void
_perf_rxDeinit(
const UI32_T unit,
const UI32_T rx_channel)
{
/* turn-off Rx test */
_perf_rx_perf_cb.rx_test = FALSE;
/* destroy Rx resources */
osal_destroyEvent(&_perf_rx_perf_cb.end_sync);
osal_destroyEvent(&_perf_rx_perf_cb.start_sync);
/* disable duplicate Rx packets to channels */
_perf_duplicateRxPacket(unit, rx_channel, FALSE);
}
static void
_perf_rxInit(
const UI32_T unit,
const UI32_T rx_channel,
const UI32_T len)
{
/* enable duplicate Rx packets to channels */
_perf_duplicateRxPacket(unit, rx_channel, TRUE);
/* create Rx callback resources */
_perf_rx_perf_cb.target_num = PERF_RX_PERF_NUM;
_perf_rx_perf_cb.target_len = len;
_perf_rx_perf_cb.recv_pass = 0;
osal_createEvent("RX_START", &_perf_rx_perf_cb.start_sync);
osal_createEvent("RX_END", &_perf_rx_perf_cb.end_sync);
/* turn-on Rx test */
_perf_rx_perf_cb.rx_test = TRUE;
}
/* FUNCTION NAME: perf_rxCallback
* PURPOSE:
* To count the Rx-gpd for Rx-test.
* INPUT:
* len -- To check if the Rx-gpd length equals to test length.
* OUTPUT:
* None
* RETURN:
* NPS_E_OK -- Successful operation.
* NOTES:
* None
*/
NPS_ERROR_NO_T
perf_rxCallback(
const UI32_T len)
{
/* check length */
if (len == _perf_rx_perf_cb.target_len)
{
_perf_rx_perf_cb.recv_pass++;
}
else
{
if (_perf_rx_perf_cb.recv_fail++ >= PERF_RX_PERF_FAIL)
{
_perf_rx_perf_cb.recv_fail = 0;
}
}
/* send signals */
if (0 == _perf_rx_perf_cb.recv_pass)
{
; /* do nothing */
}
else if (1 == _perf_rx_perf_cb.recv_pass)
{
osal_triggerEvent(&_perf_rx_perf_cb.start_sync);
}
else if (_perf_rx_perf_cb.recv_pass == _perf_rx_perf_cb.target_num)
{
osal_triggerEvent(&_perf_rx_perf_cb.end_sync);
}
else if (0 == (_perf_rx_perf_cb.recv_pass % PERF_RX_PERF_MESG))
{
printk("R");
}
return (NPS_E_OK);
}
/* FUNCTION NAME: perf_rxTest
* PURPOSE:
* To check if Rx-test is going.
* INPUT:
* None
* OUTPUT:
* None
* RETURN:
* NPS_E_OK -- Successful operation.
* NOTES:
* None
*/
NPS_ERROR_NO_T
perf_rxTest(void)
{
if (FALSE == _perf_rx_perf_cb.rx_test)
{
return (NPS_E_OTHERS);
}
return (NPS_E_OK);
}
/* FUNCTION NAME: perf_test
* PURPOSE:
* To do Tx-test or Rx-test.
* INPUT:
* len -- Test length
* tx_channel -- Test Tx channel numbers
* rx_channel -- Test Rx channel numbers
* test_skb -- Test GPD or SKB
* OUTPUT:
* None
* RETURN:
* NPS_E_OK -- Successful operation.
* NOTES:
* None
*/
NPS_ERROR_NO_T
perf_test(
UI32_T len,
UI32_T tx_channel,
UI32_T rx_channel,
BOOL_T test_skb)
{
NPS_ERROR_NO_T rc = NPS_E_OK;
NPS_TIME_T start_time;
NPS_TIME_T end_time;
UI32_T unit = 0, channel = 0;
UI32_T tx_pkt_cnt = 0, tx_start_intr = 0, tx_end_intr = 0;
UI32_T rx_pkt_cnt = 0, rx_start_intr = 0, rx_end_intr = 0;
if ((0 == tx_channel) && (0 == rx_channel))
{
return (NPS_E_NOT_SUPPORT);
}
/* start test */
if ((tx_channel > 0) && (rx_channel > 0))
{
_perf_getIntrCnt(unit, PERF_DIR_TX, &tx_start_intr);
_perf_getIntrCnt(unit, PERF_DIR_RX, &rx_start_intr);
_perf_txInit(unit, tx_channel, len, test_skb);
_perf_rxInit(unit, rx_channel, len);
/* wait 1st Rx GPD done */
osal_waitEvent(&_perf_rx_perf_cb.start_sync);
/* ------------- in-time ------------- */
osal_getTime(&start_time);
for (channel = 0; channel < tx_channel; channel++)
{
osal_triggerEvent(&_perf_tx_perf_cb.start_sync[channel]);
}
for (channel = 0; channel < tx_channel; channel++)
{
osal_waitEvent(&_perf_tx_perf_cb.end_sync[channel]);
tx_pkt_cnt += _perf_tx_perf_cb.send_ok[channel];
}
rx_pkt_cnt = _perf_rx_perf_cb.recv_pass;
osal_getTime(&end_time);
/* ------------- in-time ------------- */
_perf_txDeinit(unit, tx_channel);
_perf_rxDeinit(unit, rx_channel);
_perf_getIntrCnt(unit, PERF_DIR_TX, &tx_end_intr);
_perf_getIntrCnt(unit, PERF_DIR_RX, &rx_end_intr);
_perf_showPerf(PERF_DIR_TX,
tx_channel, len, tx_pkt_cnt, tx_end_intr - tx_start_intr, end_time - start_time);
_perf_showPerf(PERF_DIR_RX,
rx_channel, len, rx_pkt_cnt, rx_end_intr - rx_start_intr, end_time - start_time);
}
else if (tx_channel > 0)
{
_perf_getIntrCnt(unit, PERF_DIR_TX, &tx_start_intr);
_perf_txInit(unit, tx_channel, len, test_skb);
/* ------------- in-time ------------- */
osal_getTime(&start_time);
for (channel = 0; channel < tx_channel; channel++)
{
osal_triggerEvent(&_perf_tx_perf_cb.start_sync[channel]);
}
for (channel = 0; channel < tx_channel; channel++)
{
osal_waitEvent(&_perf_tx_perf_cb.end_sync[channel]);
tx_pkt_cnt += _perf_tx_perf_cb.send_ok[channel];
}
osal_getTime(&end_time);
/* ------------- in-time ------------- */
_perf_txDeinit(unit, tx_channel);
_perf_getIntrCnt(unit, PERF_DIR_TX, &tx_end_intr);
_perf_showPerf(PERF_DIR_TX,
tx_channel, len, tx_pkt_cnt, tx_end_intr - tx_start_intr, end_time - start_time);
}
else if (rx_channel > 0)
{
_perf_getIntrCnt(unit, PERF_DIR_RX, &rx_start_intr);
_perf_rxInit(unit, rx_channel, len);
/* wait 1st Rx GPD done */
osal_waitEvent(&_perf_rx_perf_cb.start_sync);
/* ------------- in-time ------------- */
osal_getTime(&start_time);
osal_waitEvent(&_perf_rx_perf_cb.end_sync);
osal_getTime(&end_time);
/* ------------- in-time ------------- */
_perf_rxDeinit(unit, rx_channel);
_perf_getIntrCnt(unit, PERF_DIR_RX, &rx_end_intr);
_perf_showPerf(PERF_DIR_RX,
rx_channel, len, PERF_RX_PERF_NUM, rx_end_intr - rx_start_intr, end_time - start_time);
}
return (rc);
}