📄 tcp_echo.c
字号:
//==========================================================================
//
// tests/tcp_echo.c
//
// Simple TCP throughput test - echo component
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Portions created by Nick Garnett are
// Copyright (C) 2003 eCosCentric Ltd.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos 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 along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas, nickg
// Contributors: gthomas, nickg
// 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>
#include <cyg/io/io.h>
#include <cyg/io/serialio.h>
#include <cyg/ppp/ppp.h>
#include <cyg/infra/testcase.h>
#include "ppp_test_support.inl"
// 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 CYGNUM_PPP_PPPD_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)
{
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.
//
void
net_load(cyg_addrword_t who)
{
int i;
while (true) {
cyg_semaphore_wait(&load_thread_sem[who]);
for (i = 0; i < load_thread_level; i++) {
do_some_random_computation(i,who);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -