📄 tcp_echo.c
字号:
//==========================================================================
//
// tests/tcp_echo.c
//
// Simple TCP throughput test - echo component
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-01-10
// Purpose:
// Description: This is the middle part of a three part test. The idea is
// to test the throughput of box in a configuration like this:
//
// +------+ port +----+ port +----+
// |SOURCE|=========>|ECHO|============>|SINK|
// +------+ 9990 +----+ 9991 +----+
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/system.h>
#include <pkgconf/net.h>
#ifdef CYGBLD_DEVS_ETH_DEVICE_H // Get the device config if it exists
#include CYGBLD_DEVS_ETH_DEVICE_H // May provide CYGTST_DEVS_ETH_TEST_NET_REALTIME
#endif
#ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test?
# ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists
# include CYGTST_DEVS_ETH_TEST_NET_REALTIME
# endif
#endif
// Fill in the blanks if necessary
#ifndef TNR_OFF
# define TNR_OFF()
#endif
#ifndef TNR_ON
# define TNR_ON()
#endif
#ifndef TNR_INIT
# define TNR_INIT()
#endif
#ifndef TNR_PRINT_ACTIVITY
# define TNR_PRINT_ACTIVITY()
#endif
// Network throughput test code
#include <network.h>
static __inline__ unsigned int
max(unsigned int m, unsigned int n)
{
return m > n ? m : n;
}
#define SOURCE_PORT 9990
#define SINK_PORT 9991
#define MAX_BUF 8192
static unsigned char data_buf[MAX_BUF];
struct test_params {
long nbufs;
long bufsize;
long load;
};
struct test_status {
long ok;
};
#ifndef CYGPKG_LIBC_STDIO
#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
#endif
#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
static char stack[STACK_SIZE];
static cyg_thread thread_data;
static cyg_handle_t thread_handle;
// Background load stuff
#define NUM_LOAD_THREADS 20 // Get 5% granularity
#define IDLE_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY+3
#define LOAD_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-3
#define MAIN_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-4
#define DESIRED_BACKGROUND_LOAD 50 // should be accurate enough over range
// starting points for load calculation
#define MAX_LOAD_THREAD_LEVEL 100
#define MIN_LOAD_THREAD_LEVEL 0
static char idle_thread_stack[STACK_SIZE];
static cyg_thread idle_thread_data;
static cyg_handle_t idle_thread_handle;
static cyg_sem_t idle_thread_sem;
volatile static long long idle_thread_count;
static char load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
static cyg_thread load_thread_data[NUM_LOAD_THREADS];
static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
static cyg_sem_t load_thread_sem[NUM_LOAD_THREADS];
static long load_thread_level;
static void calibrate_load(int load);
static void start_load(int load);
static void do_some_random_computation(int p,int id);
#define abs(n) ((n) < 0 ? -(n) : (n))
static long long no_load_idle_count_1_second;
extern void
cyg_test_exit(void);
void
pexit(char *s)
{
TNR_OFF();
perror(s);
cyg_test_exit();
}
int
do_read(int s, void *_buf, int len)
{
int total, slen, rlen;
unsigned char *buf = (unsigned char *)_buf;
total = 0;
rlen = len;
while (total < len) {
slen = read(s, buf, rlen);
if (slen != rlen) {
if (slen < 0) {
diag_printf("Error after reading %d bytes\n", total);
return -1;
}
rlen -= slen;
buf += slen;
}
total += slen;
}
return total;
}
int
do_write(int s, void *_buf, int len)
{
int total, slen, rlen;
unsigned char *buf = (unsigned char *)_buf;
total = 0;
rlen = len;
while (total < len) {
slen = write(s, buf, rlen);
if (slen != rlen) {
if (slen < 0) {
diag_printf("Error after writing %d bytes\n", total);
return -1;
}
rlen -= slen;
buf += slen;
}
total += slen;
}
return total;
}
//
// This function is called to calibrate the "background load" which can be
// applied during testing. It will be called before any commands from the
// host are managed.
//
static void
calibrate_load(int desired_load)
{
long long no_load_idle, load_idle;
int percent_load;
int high, low;
// Set limits
high = MAX_LOAD_THREAD_LEVEL;
low = MIN_LOAD_THREAD_LEVEL;
// Compute the "no load" idle value
idle_thread_count = 0;
cyg_semaphore_post(&idle_thread_sem); // Start idle thread
cyg_thread_delay(1*100); // Pause for one second
cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
no_load_idle = idle_thread_count;
diag_printf("No load = %d\n", (int)idle_thread_count);
// First ensure that the HIGH level is indeed higher
while (true) {
load_thread_level = high;
start_load(desired_load); // Start up a given load
idle_thread_count = 0;
cyg_semaphore_post(&idle_thread_sem); // Start idle thread
cyg_thread_delay(1*100); // Pause for one second
cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
load_idle = idle_thread_count;
start_load(0); // Shut down background load
percent_load = 100 - ((load_idle * 100) / no_load_idle);
diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level,
(int)idle_thread_count, percent_load);
if ( percent_load > desired_load )
break; // HIGH level is indeed higher
low = load_thread_level; // known to be lower
high *= 2; // else double it and try again
}
// Now chop down to the level required
while (true) {
load_thread_level = (high + low) / 2;
start_load(desired_load); // Start up a given load
idle_thread_count = 0;
cyg_semaphore_post(&idle_thread_sem); // Start idle thread
cyg_thread_delay(1*100); // Pause for one second
cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
load_idle = idle_thread_count;
start_load(0); // Shut down background load
percent_load = 100 - ((load_idle * 100) / no_load_idle);
diag_printf("Load[%d] = %d => %d%%\n", load_thread_level,
(int)idle_thread_count, percent_load);
if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;
if (percent_load < desired_load) {
low = load_thread_level;
} else {
high = load_thread_level;
}
}
// Now we are within a few percent of the target; scale the load
// factor to get a better fit, and test it, print the answer.
load_thread_level *= desired_load;
load_thread_level /= percent_load;
start_load(desired_load); // Start up a given load
idle_thread_count = 0;
cyg_semaphore_post(&idle_thread_sem); // Start idle thread
cyg_thread_delay(1*100); // Pause for one second
cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
load_idle = idle_thread_count;
start_load(0); // Shut down background load
percent_load = 100 - ((load_idle * 100) / no_load_idle);
diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level,
(int)idle_thread_count, percent_load);
no_load_idle_count_1_second = no_load_idle;
}
//
// This function is called to set up a load level of 'load' percent (given
// as a whole number, e.g. start_load(20) would mean initiate a background
// load of 20%, leaving the cpu 80% idle).
//
static void
start_load(int load)
{
static int prev_load = 0;
int i;
if (load == 0) {
diag_printf("Set no background load\n");
if (prev_load == 0) return; // Nothing out there to stop
for (i = 0; i < prev_load * NUM_LOAD_THREADS/100; i++) {
cyg_semaphore_wait(&load_thread_sem[i]);
}
prev_load = 0;
} else {
diag_printf("Set background load = %d%% starting %d threads\n",
load, load * NUM_LOAD_THREADS/100 );
for (i = 0; i < load * NUM_LOAD_THREADS/100; i++) {
cyg_semaphore_post(&load_thread_sem[i]);
}
prev_load = load;
}
}
//
// These thread(s) do some amount of "background" computing. This is used
// to simulate a given load level. They need to be run at a higher priority
// than the network code itself.
//
// Like the "idle" thread, they run as long as their "switch" (aka semaphore)
// is enabled.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -