📄 nc_test_slave.c
字号:
tdp->seq = htonl(seq);
td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
tdp->len = htonl(td_len);
if (write(test_chan, tdp, td_len) != td_len) {
perror("write");
if (errno == ENOBUFS) {
// Saturated the system
test_delay(25);
} else {
// What else to do?
close(test_chan);
return;
}
} else {
nsent++;
}
}
seq++;
}
results.key1 = htonl(NC_TEST_RESULT_KEY1);
results.key2 = htonl(NC_TEST_RESULT_KEY2);
results.seq = req->seq;
results.nsent = htonl(nsent);
results.nrecvd = htonl(nrecvd);
if (write(test_chan, &results, sizeof(results)) != sizeof(results)) {
perror("write");
}
close(test_chan);
}
//
// Protocol driver for testing slave.
//
// This function is the main routine running here, handling requests sent from
// the master and providing various responses.
//
static void
nc_slave(test_param_t param)
{
int s, masterlen;
struct sockaddr_in my_addr, master;
struct nc_request req;
struct nc_reply reply;
int done = false;
test_printf("Start test for eth%d\n", param);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
pexit("datagram socket");
}
memset((char *) &my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
#ifdef __ECOS
my_addr.sin_len = sizeof(my_addr);
#endif
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.sin_port = htons(NC_SLAVE_PORT);
if (bind(s, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
pexit("bind");
}
while (!done) {
masterlen = sizeof(master);
if (recvfrom(s, &req, sizeof(req), 0, (struct sockaddr *)&master, &masterlen) < 0) {
pexit("recvfrom");
}
#if 0
test_printf("Request %d from %s:%d\n", ntohl(req.type),
inet_ntoa(master.sin_addr), ntohs(master.sin_port));
#endif
reply.response = htonl(NC_REPLY_ACK);
reply.seq = req.seq;
switch (ntohl(req.type)) {
case NC_REQUEST_DISCONNECT:
done = true;
break;
case NC_REQUEST_UDP_SEND:
test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
break;
case NC_REQUEST_UDP_RECV:
test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
break;
case NC_REQUEST_UDP_ECHO:
test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
break;
case NC_REQUEST_TCP_SEND:
test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
break;
case NC_REQUEST_TCP_RECV:
test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
break;
case NC_REQUEST_TCP_ECHO:
test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
break;
#ifdef __ECOS
case NC_REQUEST_SET_LOAD:
start_load(ntohl(req.nbufs));
break;
case NC_REQUEST_START_IDLE:
test_printf("Start IDLE thread\n");
idle_thread_count = 0;
idle_thread_start_time = cyg_current_time();
cyg_semaphore_post(&idle_thread_sem);
break;
case NC_REQUEST_STOP_IDLE:
cyg_semaphore_wait(&idle_thread_sem);
idle_thread_stop_time = cyg_current_time();
test_printf("Stop IDLE thread\n");
reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time);
reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32);
reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);
break;
#endif
default:
test_printf("Unrecognized request: %d\n", ntohl(req.type));
reply.response = htonl(NC_REPLY_NAK);
reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);
break;
}
if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) {
pexit("sendto");
}
if (reply.response == ntohl(NC_REPLY_NAK)) {
continue;
}
switch (ntohl(req.type)) {
case NC_REQUEST_UDP_SEND:
case NC_REQUEST_UDP_RECV:
case NC_REQUEST_UDP_ECHO:
do_udp_test(s, &req, &master);
break;
case NC_REQUEST_TCP_SEND:
case NC_REQUEST_TCP_RECV:
case NC_REQUEST_TCP_ECHO:
do_tcp_test(s, &req, &master);
break;
case NC_REQUEST_START_IDLE:
case NC_REQUEST_STOP_IDLE:
case NC_REQUEST_SET_LOAD:
default:
break;
}
}
close(s);
}
void
net_test(test_param_t param)
{
// int i;
if (param == 0) {
test_printf("Start Network Characterization - SLAVE\n");
#ifdef __ECOS
init_all_network_interfaces();
calibrate_load(DESIRED_BACKGROUND_LOAD);
#if 0
// I can see what this is trying to do, but I get "bind: Address already in
// use" errors from the 2nd interface - and the parameter is not used
// anyway, so one thread does quite well enough (but only tests one i/f at
// once).
// Comment in the 'int i' above too.
for (i = 1; i < CYGHWR_NET_DRIVERS; i++) {
cyg_thread_resume(main_thread_handle[i]); // Start other threads
}
#endif
#endif
}
nc_slave(param);
#ifdef CYGDBG_NET_TIMING_STATS
show_net_times();
#endif
cyg_test_exit();
}
#ifdef __ECOS
//
// 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;
test_printf("Set background load = %d%%\n", load);
if (load == 0) {
if (prev_load == 0) return; // Nothing out there to stop
for (i = 0; i < prev_load/10; i++) {
cyg_semaphore_wait(&load_thread_sem[i]);
}
prev_load = 0;
} else {
for (i = 0; i < load/10; 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);
}
cyg_thread_delay(1); // Wait until the next 'tick'
cyg_semaphore_post(&load_thread_sem[who]);
}
}
//
// Some arbitrary computation, designed to use up the CPU and cause associated
// cache "thrash" behaviour - part of background load modelling.
//
static void
do_some_random_computation(int p)
{
// Just something that might be "hard"
volatile double x;
x = ((p * 10) * 3.14159) / 180.0; // radians
}
//
// This thread does nothing but count. It will be allowed to count
// as long as the semaphore is "free".
//
void
net_idle(cyg_addrword_t param)
{
while (true) {
cyg_semaphore_wait(&idle_thread_sem);
idle_thread_count++;
cyg_semaphore_post(&idle_thread_sem);
}
}
void
cyg_start(void)
{
int i;
// Create processing threads
for (i = 0; i < CYGHWR_NET_DRIVERS; i++) {
cyg_thread_create(MAIN_THREAD_PRIORITY, // Priority
net_test, // entry
i, // entry parameter
"Network test", // Name
&main_thread_stack[i][0], // Stack
STACK_SIZE, // Size
&main_thread_handle[i], // Handle
&main_thread_data[i] // Thread data structure
);
}
cyg_thread_resume(main_thread_handle[0]); // Start first one
// Create the idle thread environment
cyg_semaphore_init(&idle_thread_sem, 0);
cyg_thread_create(IDLE_THREAD_PRIORITY, // Priority
net_idle, // entry
0, // entry parameter
"Network idle", // Name
&idle_thread_stack[0], // Stack
STACK_SIZE, // Size
&idle_thread_handle, // Handle
&idle_thread_data // Thread data structure
);
cyg_thread_resume(idle_thread_handle); // Start it
// Create the load threads and their environment(s)
for (i = 0; i < NUM_LOAD_THREADS; i++) {
cyg_semaphore_init(&load_thread_sem[i], 0);
cyg_thread_create(LOAD_THREAD_PRIORITY, // Priority
net_load, // entry
i, // entry parameter
"Background load", // Name
&load_thread_stack[i][0], // Stack
STACK_SIZE, // Size
&load_thread_handle[i], // Handle
&load_thread_data[i] // Thread data structure
);
cyg_thread_resume(load_thread_handle[i]); // Start it
}
cyg_scheduler_start();
}
#else
int
main(int argc, char *argv[])
{
net_test(0);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -