Move runtime checks to use arch_num_cpus() and build checks to use CONFIG_MP_MAX_NUM_CPUS. This is to allow runtime determination of the number of CPUs in the future. Signed-off-by: Kumar Gala <kumar.gala@intel.com>
205 lines
5.9 KiB
C
205 lines
5.9 KiB
C
/*
|
|
* Copyright (c) 2020 Synopsys, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "pktqueue.h"
|
|
#include "main.h"
|
|
|
|
static struct k_thread tthread[THREADS_NUM*QUEUE_NUM];
|
|
static struct k_thread qthread[QUEUE_NUM];
|
|
|
|
/* Each queue has its own mutex */
|
|
struct k_mutex sender_queue_mtx[QUEUE_NUM];
|
|
struct k_mutex receiver_queue_mtx[QUEUE_NUM];
|
|
|
|
/* Variable which indicates the amount of processed queues */
|
|
int queues_remain = QUEUE_NUM;
|
|
/* Variable to define current queue in thread */
|
|
int current_queue;
|
|
|
|
/* Array of packet header descriptors */
|
|
struct phdr_desc descriptors[QUEUE_NUM][SIZE_OF_QUEUE];
|
|
|
|
/* Arrays of receiver and sender queues */
|
|
struct phdr_desc_queue sender[QUEUE_NUM], receiver[QUEUE_NUM];
|
|
|
|
/* Array of packet headers */
|
|
uint8_t headers[QUEUE_NUM][SIZE_OF_QUEUE][SIZE_OF_HEADER];
|
|
|
|
static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREADS_NUM*QUEUE_NUM, STACK_SIZE);
|
|
static K_THREAD_STACK_ARRAY_DEFINE(qstack, QUEUE_NUM, STACK_SIZE);
|
|
|
|
K_MUTEX_DEFINE(fetch_queue_mtx);
|
|
|
|
/* Function for initializing "sender" packet header queue */
|
|
void init_datagram_queue(struct phdr_desc_queue *queue, int queue_num)
|
|
{
|
|
queue->head = descriptors[queue_num];
|
|
|
|
for (int i = 0; i < SIZE_OF_QUEUE; i++) {
|
|
queue->tail = &descriptors[queue_num][i];
|
|
descriptors[queue_num][i].ptr = (uint8_t *)&headers[queue_num][i];
|
|
/* Fill packet header with random values */
|
|
for (int j = 0; j < SIZE_OF_HEADER; j++) {
|
|
/* leave crc field zeroed */
|
|
if (j < CRC_BYTE_1 || j > CRC_BYTE_2) {
|
|
descriptors[queue_num][i].ptr[j] = (uint8_t)sys_rand32_get();
|
|
} else {
|
|
descriptors[queue_num][i].ptr[j] = 0;
|
|
}
|
|
}
|
|
/* Compute crc for further comparison */
|
|
uint16_t crc;
|
|
|
|
crc = crc16(POLYNOMIAL, 0x0000,
|
|
descriptors[queue_num][i].ptr, SIZE_OF_HEADER);
|
|
|
|
/* Save crc value in header[CRC_BYTE_1-CRC_BYTE_2] field */
|
|
descriptors[queue_num][i].ptr[CRC_BYTE_1] = (uint8_t)(crc >> 8);
|
|
descriptors[queue_num][i].ptr[CRC_BYTE_2] = (uint8_t)(crc);
|
|
queue->count++;
|
|
descriptors[queue_num][i].next = &descriptors[queue_num][i+1];
|
|
}
|
|
}
|
|
|
|
/* Thread takes packet from "sender" queue and puts it to "receiver" queue.
|
|
* Each queue can be accessed only by one thread in a time. */
|
|
void test_thread(void *arg1, void *arg2, void *arg3)
|
|
{
|
|
struct phdr_desc_queue *sender_queue = (struct phdr_desc_queue *)arg1;
|
|
struct phdr_desc_queue *receiver_queue = (struct phdr_desc_queue *)arg2;
|
|
struct phdr_desc *qin_ptr = NULL;
|
|
int queue_num = *(int *)arg3;
|
|
|
|
/* Fetching one queue */
|
|
uint16_t crc, crc_orig;
|
|
|
|
qin_ptr = phdr_desc_dequeue(sender_queue, &sender_queue_mtx[queue_num]);
|
|
while (qin_ptr != NULL) {
|
|
/* Store original crc value from header */
|
|
crc_orig = qin_ptr->ptr[CRC_BYTE_1] << 8;
|
|
crc_orig |= qin_ptr->ptr[11];
|
|
|
|
/* Crc field should be zero before crc calculation */
|
|
qin_ptr->ptr[CRC_BYTE_1] = 0;
|
|
qin_ptr->ptr[CRC_BYTE_2] = 0;
|
|
crc = crc16(POLYNOMIAL, 0x0000, qin_ptr->ptr, SIZE_OF_HEADER);
|
|
|
|
/* Compare computed crc with crc from phdr_desc->crc */
|
|
if (crc == crc_orig) {
|
|
phdr_desc_enqueue(receiver_queue, qin_ptr,
|
|
&receiver_queue_mtx[queue_num]);
|
|
}
|
|
/* Take next element from "sender queue" */
|
|
qin_ptr = phdr_desc_dequeue(sender_queue,
|
|
&sender_queue_mtx[queue_num]);
|
|
}
|
|
}
|
|
|
|
/* Thread that processes one pair of sender/receiver queue */
|
|
void queue_thread(void *arg1, void *arg2, void *arg3)
|
|
{
|
|
|
|
ARG_UNUSED(arg1);
|
|
ARG_UNUSED(arg2);
|
|
ARG_UNUSED(arg3);
|
|
|
|
int queue_num;
|
|
|
|
/* Fetching one queue */
|
|
k_mutex_lock(&fetch_queue_mtx, K_FOREVER);
|
|
queue_num = current_queue;
|
|
current_queue++;
|
|
k_mutex_unlock(&fetch_queue_mtx);
|
|
|
|
for (int i = 0; i < THREADS_NUM; i++)
|
|
k_thread_create(&tthread[i+THREADS_NUM*queue_num],
|
|
tstack[i+THREADS_NUM*queue_num], STACK_SIZE,
|
|
(k_thread_entry_t)test_thread,
|
|
(void *)&sender[queue_num],
|
|
(void *)&receiver[queue_num], (void *)&queue_num,
|
|
K_PRIO_PREEMPT(10), 0, K_NO_WAIT);
|
|
|
|
/* Wait until sender queue is not empty */
|
|
while (sender[queue_num].count != 0) {
|
|
k_sleep(K_MSEC(1));
|
|
}
|
|
|
|
/* Decrementing queue counter */
|
|
k_mutex_lock(&fetch_queue_mtx, K_FOREVER);
|
|
queues_remain--;
|
|
k_mutex_unlock(&fetch_queue_mtx);
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
uint32_t start_time, stop_time, cycles_spent, nanoseconds_spent;
|
|
|
|
current_queue = 0;
|
|
printk("Simulating IP header validation on multiple cores.\n");
|
|
printk("Each of %d parallel queues is processed by %d threads"
|
|
" on %d cores and contain %d packet headers.\n",
|
|
QUEUE_NUM, THREADS_NUM, arch_num_cpus(), SIZE_OF_QUEUE);
|
|
printk("Bytes in packet header: %d\n\n", SIZE_OF_HEADER);
|
|
|
|
/* initializing "sender" queue */
|
|
for (int i = 0; i < QUEUE_NUM; i++) {
|
|
init_datagram_queue(&sender[i], i);
|
|
k_mutex_init(&sender_queue_mtx[i]);
|
|
k_mutex_init(&receiver_queue_mtx[i]);
|
|
}
|
|
|
|
/* Capture initial time stamp */
|
|
start_time = k_cycle_get_32();
|
|
|
|
for (int i = 0; i < QUEUE_NUM; i++)
|
|
k_thread_create(&qthread[i], qstack[i], STACK_SIZE,
|
|
(k_thread_entry_t)queue_thread,
|
|
(void *)&sender[i], (void *)&receiver[i],
|
|
(void *)&i, K_PRIO_PREEMPT(11), 0, K_NO_WAIT);
|
|
|
|
/* Wait until all queues are not processed */
|
|
while (queues_remain > 0) {
|
|
k_sleep(K_MSEC(1));
|
|
}
|
|
|
|
/* Capture final time stamp */
|
|
stop_time = k_cycle_get_32();
|
|
cycles_spent = stop_time - start_time;
|
|
nanoseconds_spent = (uint32_t)k_cyc_to_ns_floor64(cycles_spent);
|
|
|
|
/* Verify result of packet transmission
|
|
* The counter of correct receiver queues */
|
|
int correct = 0;
|
|
struct phdr_desc *tmp;
|
|
/* Iterate and count amount of packages in receiver queues */
|
|
for (int i = 0; i < QUEUE_NUM; i++) {
|
|
int count = 0;
|
|
|
|
tmp = receiver[i].head;
|
|
while (tmp != NULL) {
|
|
tmp = tmp->next;
|
|
count++;
|
|
}
|
|
if (receiver[i].count == SIZE_OF_QUEUE && count == SIZE_OF_QUEUE) {
|
|
correct++;
|
|
}
|
|
}
|
|
if (correct == QUEUE_NUM) {
|
|
printk("RESULT: OK\n"
|
|
"Application ran successfully.\n"
|
|
"All %d headers were processed in %d msec\n",
|
|
SIZE_OF_QUEUE*QUEUE_NUM,
|
|
nanoseconds_spent / 1000 / 1000);
|
|
} else {
|
|
printk("RESULT: FAIL\n"
|
|
"Application failed.\n"
|
|
"The amount of packets in receiver queue "
|
|
"is less than expected.\n");
|
|
}
|
|
|
|
k_sleep(K_MSEC(10));
|
|
}
|