comparison packages/net/common/current/tests/nc_test_slave.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children 75bb10dfa0df
comparison
equal deleted inserted replaced
207:74c807ddde34 208:e0c0827131d1
1 //==========================================================================
2 //
3 // tests/nc_test_slave.c
4 //
5 // Network characterizations test (slave portion)
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s): gthomas
22 // Contributors: gthomas
23 // Date: 2000-01-10
24 // Purpose:
25 // Description:
26 //
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32 // Network characterization test code - slave portion
33
34 #include "nc_test_framework.h"
35 #include <math.h>
36
37 #ifdef __ECOS
38 #ifndef CYGPKG_LIBC_STDIO
39 #define perror(s) diag_printf(#s ": %s\n", strerror(errno))
40 #endif
41 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
42 #define MAX_LOAD_THREAD_LEVEL 20
43 #define MIN_LOAD_THREAD_LEVEL 0
44 #define NUM_LOAD_THREADS 10
45 #define IDLE_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY+3
46 #define LOAD_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-1
47 #define MAIN_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-2
48 #define DESIRED_BACKGROUND_LOAD 20
49 static char main_thread_stack[CYGHWR_NET_DRIVERS][STACK_SIZE];
50 static cyg_thread main_thread_data[CYGHWR_NET_DRIVERS];
51 static cyg_handle_t main_thread_handle[CYGHWR_NET_DRIVERS];
52 static char idle_thread_stack[STACK_SIZE];
53 static cyg_thread idle_thread_data;
54 static cyg_handle_t idle_thread_handle;
55 static cyg_sem_t idle_thread_sem;
56 volatile static long long idle_thread_count;
57 static cyg_tick_count_t idle_thread_start_time;
58 static cyg_tick_count_t idle_thread_stop_time;
59 static char load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
60 static cyg_thread load_thread_data[NUM_LOAD_THREADS];
61 static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
62 static cyg_sem_t load_thread_sem[NUM_LOAD_THREADS];
63 static long load_thread_level;
64 static void calibrate_load(int load);
65 static void start_load(int load);
66 static void do_some_random_computation(int p);
67 #define abs(n) ((n) < 0 ? -(n) : (n))
68 #endif
69
70 #ifdef __ECOS
71 #define test_param_t cyg_addrword_t
72 #ifdef CYGDBG_NET_TIMING_STATS
73 extern void show_net_times(void);
74 #endif
75 #else
76 #define test_param_t int
77 #endif
78
79 #define MAX_BUF 8192
80 static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF];
81
82 #ifdef __ECOS
83 extern void
84 cyg_test_exit(void);
85 #else
86 void
87 cyg_test_exit(void)
88 {
89 test_printf("... Done\n");
90 exit(1);
91 }
92
93 static void
94 show_net_times(void)
95 {
96 }
97 #endif
98
99 #ifdef __ECOS
100 static void
101 test_delay(int ticks)
102 {
103 cyg_thread_delay(ticks);
104 }
105
106 #else
107
108 static void
109 test_delay(int ticks)
110 {
111 usleep(ticks * 10000);
112 }
113 #endif
114
115 void
116 pexit(char *s)
117 {
118 perror(s);
119 #ifdef CYGDBG_NET_TIMING_STATS
120 show_net_times();
121 #endif
122 cyg_test_exit();
123 }
124
125 //
126 // Generic UDP test
127 //
128
129 static void
130 do_udp_test(int s1, struct nc_request *req, struct sockaddr_in *master)
131 {
132 int i, s, td_len, seq, seq_errors, lost;
133 struct sockaddr_in test_chan_slave, test_chan_master;
134 fd_set fds;
135 struct timeval timeout;
136 struct nc_test_results results;
137 struct nc_test_data *tdp;
138 int nsent, nrecvd;
139 int need_recv, need_send;
140
141 need_recv = true; need_send = true;
142 switch (ntohl(req->type)) {
143 case NC_REQUEST_UDP_SEND:
144 need_recv = false;
145 need_send = true;
146 break;
147 case NC_REQUEST_UDP_RECV:
148 need_recv = true;
149 need_send = false;
150 break;
151 case NC_REQUEST_UDP_ECHO:
152 break;
153 }
154
155 s = socket(AF_INET, SOCK_DGRAM, 0);
156 if (s < 0) {
157 pexit("datagram socket");
158 }
159
160 memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave));
161 test_chan_slave.sin_family = AF_INET;
162 #ifdef __ECOS
163 test_chan_slave.sin_len = sizeof(test_chan_slave);
164 #endif
165 test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY);
166 test_chan_slave.sin_port = htons(ntohl(req->slave_port));
167
168 if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) {
169 perror("bind");
170 close(s);
171 }
172
173 memcpy(&test_chan_master, master, sizeof(*master));
174 test_chan_master.sin_port = htons(ntohl(req->master_port));
175 nsent = 0; nrecvd = 0; seq = 0; seq_errors = 0; lost = 0;
176 for (i = 0; i < ntohl(req->nbufs); i++) {
177 if (need_recv) {
178 FD_ZERO(&fds);
179 FD_SET(s, &fds);
180 timeout.tv_sec = NC_TEST_TIMEOUT;
181 timeout.tv_usec = 0;
182 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
183 test_printf("recvfrom timeout, expecting seq #%d\n", seq);
184 if (++lost > MAX_ERRORS) {
185 test_printf("... giving up\n");
186 break;
187 }
188 } else {
189 nrecvd++;
190 tdp = (struct nc_test_data *)in_buf;
191 td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
192 if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) {
193 perror("recvfrom");
194 close(s);
195 return;
196 }
197 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
198 (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
199 if (ntohl(tdp->seq) != seq) {
200 test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
201 ntohl(tdp->seq), seq);
202 seq = ntohl(tdp->seq);
203 seq_errors++;
204 }
205 } else {
206 test_printf("Bad data packet - key: %x/%x, seq: %d\n",
207 ntohl(tdp->key1), ntohl(tdp->key2),
208 ntohl(tdp->seq));
209 }
210 }
211 }
212 if (need_send) {
213 tdp = (struct nc_test_data *)out_buf;
214 tdp->key1 = htonl(NC_TEST_DATA_KEY1);
215 tdp->key2 = htonl(NC_TEST_DATA_KEY2);
216 tdp->seq = htonl(seq);
217 td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
218 tdp->len = htonl(td_len);
219 if (sendto(s, tdp, td_len, 0,
220 (struct sockaddr *)&test_chan_master, sizeof(test_chan_master)) < 0) {
221 perror("sendto");
222 if (errno == ENOBUFS) {
223 // Saturated the system
224 test_delay(10); // Time for 200 500 byte 10-baseT packets
225 } else {
226 // What else to do?
227 close(s);
228 return;
229 }
230 } else {
231 nsent++;
232 }
233 }
234 seq++;
235 }
236 results.key1 = htonl(NC_TEST_RESULT_KEY1);
237 results.key2 = htonl(NC_TEST_RESULT_KEY2);
238 results.seq = req->seq;
239 results.nsent = htonl(nsent);
240 results.nrecvd = htonl(nrecvd);
241 if (sendto(s, &results, sizeof(results), 0,
242 (struct sockaddr *)&test_chan_master, sizeof(test_chan_master)) < 0) {
243 perror("sendto");
244 }
245 close(s);
246 }
247
248 //
249 // Read data from a stream, accounting for the fact that packet 'boundaries'
250 // are not preserved. This can also timeout (which would probably wreck the
251 // data boundaries).
252 //
253
254 int
255 do_read(int fd, void *buf, int buflen)
256 {
257 char *p = (char *)buf;
258 int len = buflen;
259 int res;
260 while (len) {
261 res = read(fd, p, len);
262 if (res < 0) {
263 perror("read");
264 } else {
265 len -= res;
266 p += res;
267 if (res == 0) {
268 break;
269 }
270 }
271 }
272 return (buflen - len);
273 }
274
275 //
276 // Generic TCP test
277 //
278
279 static void
280 do_tcp_test(int s1, struct nc_request *req, struct sockaddr_in *master)
281 {
282 int i, s, len, td_len, seq, seq_errors, lost, test_chan, res;
283 struct sockaddr_in test_chan_slave, test_chan_master;
284 struct nc_test_results results;
285 struct nc_test_data *tdp;
286 int nsent, nrecvd;
287 int need_recv, need_send;
288 int one = 1;
289 static int slave_tcp_port = -1;
290
291 need_recv = true; need_send = true;
292 switch (ntohl(req->type)) {
293 case NC_REQUEST_TCP_SEND:
294 need_recv = false;
295 need_send = true;
296 break;
297 case NC_REQUEST_TCP_RECV:
298 need_recv = true;
299 need_send = false;
300 break;
301 case NC_REQUEST_TCP_ECHO:
302 break;
303 }
304
305 if (slave_tcp_port < 0) {
306 s = socket(AF_INET, SOCK_STREAM, 0);
307 if (s < 0) {
308 pexit("datagram socket");
309 }
310
311 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
312 perror("setsockopt SO_REUSEADDR");
313 return;
314 }
315 #ifdef SO_REUSEPORT
316 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
317 perror("setsockopt SO_REUSEPORT");
318 return;
319 }
320 #endif
321 memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave));
322 test_chan_slave.sin_family = AF_INET;
323 #ifdef __ECOS
324 test_chan_slave.sin_len = sizeof(test_chan_slave);
325 #endif
326 test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY);
327 test_chan_slave.sin_port = htons(ntohl(req->slave_port));
328
329 if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) {
330 perror("bind");
331 close(s);
332 }
333 listen(s, SOMAXCONN);
334 slave_tcp_port = s;
335 }
336
337 s = slave_tcp_port;
338 len = sizeof(test_chan_master);
339 if ((test_chan = accept(s, (struct sockaddr *)&test_chan_master, &len)) < 0) {
340 pexit("accept");
341 }
342 len = sizeof(test_chan_master);
343 getpeername(test_chan, (struct sockaddr *)&test_chan_master, &len);
344 test_printf("connection from %s.%d\n", inet_ntoa(test_chan_master.sin_addr),
345 ntohs(test_chan_master.sin_port));
346
347 nsent = 0; nrecvd = 0; seq = 0; seq_errors = 0; lost = 0;
348 for (i = 0; i < ntohl(req->nbufs); i++) {
349 if (need_recv) {
350 tdp = (struct nc_test_data *)in_buf;
351 td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
352 res = do_read(test_chan, tdp, td_len);
353 if (res != td_len) {
354 test_printf("recvfrom timeout, expecting seq #%d\n", seq);
355 if (++lost > MAX_ERRORS) {
356 test_printf("... giving up\n");
357 break;
358 }
359 } else {
360 nrecvd++;
361 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
362 (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
363 if (ntohl(tdp->seq) != seq) {
364 test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
365 ntohl(tdp->seq), seq);
366 seq = ntohl(tdp->seq);
367 seq_errors++;
368 }
369 } else {
370 test_printf("Bad data packet - key: %x/%x, seq: %d\n",
371 ntohl(tdp->key1), ntohl(tdp->key2),
372 ntohl(tdp->seq));
373 }
374 }
375 }
376 if (need_send) {
377 tdp = (struct nc_test_data *)out_buf;
378 tdp->key1 = htonl(NC_TEST_DATA_KEY1);
379 tdp->key2 = htonl(NC_TEST_DATA_KEY2);
380 tdp->seq = htonl(seq);
381 td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
382 tdp->len = htonl(td_len);
383 if (write(test_chan, tdp, td_len) != td_len) {
384 perror("write");
385 if (errno == ENOBUFS) {
386 // Saturated the system
387 test_delay(25);
388 } else {
389 // What else to do?
390 close(test_chan);
391 return;
392 }
393 } else {
394 nsent++;
395 }
396 }
397 seq++;
398 }
399 results.key1 = htonl(NC_TEST_RESULT_KEY1);
400 results.key2 = htonl(NC_TEST_RESULT_KEY2);
401 results.seq = req->seq;
402 results.nsent = htonl(nsent);
403 results.nrecvd = htonl(nrecvd);
404 if (write(test_chan, &results, sizeof(results)) != sizeof(results)) {
405 perror("write");
406 }
407 close(test_chan);
408 }
409
410 //
411 // Protocol driver for testing slave.
412 //
413 // This function is the main routine running here, handling requests sent from
414 // the master and providing various responses.
415 //
416 static void
417 nc_slave(test_param_t param)
418 {
419 int s, masterlen;
420 struct sockaddr_in my_addr, master;
421 struct nc_request req;
422 struct nc_reply reply;
423 int done = false;
424
425 test_printf("Start test for eth%d\n", param);
426
427 s = socket(AF_INET, SOCK_DGRAM, 0);
428 if (s < 0) {
429 pexit("datagram socket");
430 }
431
432 memset((char *) &my_addr, 0, sizeof(my_addr));
433 my_addr.sin_family = AF_INET;
434 #ifdef __ECOS
435 my_addr.sin_len = sizeof(my_addr);
436 #endif
437 my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
438 my_addr.sin_port = htons(NC_SLAVE_PORT);
439
440 if (bind(s, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
441 pexit("bind");
442 }
443
444 while (!done) {
445 masterlen = sizeof(master);
446 if (recvfrom(s, &req, sizeof(req), 0, (struct sockaddr *)&master, &masterlen) < 0) {
447 pexit("recvfrom");
448 }
449 #if 0
450 test_printf("Request %d from %s:%d\n", ntohl(req.type),
451 inet_ntoa(master.sin_addr), ntohs(master.sin_port));
452 #endif
453 reply.response = htonl(NC_REPLY_ACK);
454 reply.seq = req.seq;
455 switch (ntohl(req.type)) {
456 case NC_REQUEST_DISCONNECT:
457 done = true;
458 break;
459 case NC_REQUEST_UDP_SEND:
460 test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
461 break;
462 case NC_REQUEST_UDP_RECV:
463 test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
464 break;
465 case NC_REQUEST_UDP_ECHO:
466 test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
467 break;
468 case NC_REQUEST_TCP_SEND:
469 test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
470 break;
471 case NC_REQUEST_TCP_RECV:
472 test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
473 break;
474 case NC_REQUEST_TCP_ECHO:
475 test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
476 break;
477 #ifdef __ECOS
478 case NC_REQUEST_SET_LOAD:
479 start_load(ntohl(req.nbufs));
480 break;
481 case NC_REQUEST_START_IDLE:
482 test_printf("Start IDLE thread\n");
483 idle_thread_count = 0;
484 idle_thread_start_time = cyg_current_time();
485 cyg_semaphore_post(&idle_thread_sem);
486 break;
487 case NC_REQUEST_STOP_IDLE:
488 cyg_semaphore_wait(&idle_thread_sem);
489 idle_thread_stop_time = cyg_current_time();
490 test_printf("Stop IDLE thread\n");
491 reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time);
492 reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32);
493 reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);
494 break;
495 #endif
496 default:
497 test_printf("Unrecognized request: %d\n", ntohl(req.type));
498 reply.response = htonl(NC_REPLY_NAK);
499 reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);
500 break;
501 }
502 if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) {
503 pexit("sendto");
504 }
505 if (reply.response == ntohl(NC_REPLY_NAK)) {
506 continue;
507 }
508 switch (ntohl(req.type)) {
509 case NC_REQUEST_UDP_SEND:
510 case NC_REQUEST_UDP_RECV:
511 case NC_REQUEST_UDP_ECHO:
512 do_udp_test(s, &req, &master);
513 break;
514 case NC_REQUEST_TCP_SEND:
515 case NC_REQUEST_TCP_RECV:
516 case NC_REQUEST_TCP_ECHO:
517 do_tcp_test(s, &req, &master);
518 break;
519 case NC_REQUEST_START_IDLE:
520 case NC_REQUEST_STOP_IDLE:
521 case NC_REQUEST_SET_LOAD:
522 default:
523 break;
524 }
525 }
526 close(s);
527 }
528
529 void
530 net_test(test_param_t param)
531 {
532 // int i;
533 if (param == 0) {
534 test_printf("Start Network Characterization - SLAVE\n");
535 #ifdef __ECOS
536 init_all_network_interfaces();
537 calibrate_load(DESIRED_BACKGROUND_LOAD);
538 #if 0
539 // I can see what this is trying to do, but I get "bind: Address already in
540 // use" errors from the 2nd interface - and the parameter is not used
541 // anyway, so one thread does quite well enough (but only tests one i/f at
542 // once).
543
544 // Comment in the 'int i' above too.
545 for (i = 1; i < CYGHWR_NET_DRIVERS; i++) {
546 cyg_thread_resume(main_thread_handle[i]); // Start other threads
547 }
548 #endif
549 #endif
550 }
551 nc_slave(param);
552 #ifdef CYGDBG_NET_TIMING_STATS
553 show_net_times();
554 #endif
555 cyg_test_exit();
556 }
557
558 #ifdef __ECOS
559
560 //
561 // This function is called to calibrate the "background load" which can be
562 // applied during testing. It will be called before any commands from the
563 // host are managed.
564 //
565 static void
566 calibrate_load(int desired_load)
567 {
568 long long no_load_idle, load_idle;
569 int percent_load;
570 int high, low;
571
572 // Set limits
573 high = MAX_LOAD_THREAD_LEVEL;
574 low = MIN_LOAD_THREAD_LEVEL;
575
576 // Compute the "no load" idle value
577 idle_thread_count = 0;
578 cyg_semaphore_post(&idle_thread_sem); // Start idle thread
579 cyg_thread_delay(1*100); // Pause for one second
580 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
581 no_load_idle = idle_thread_count;
582 diag_printf("No load = %d\n", (int)idle_thread_count);
583
584 // First ensure that the HIGH level is indeed higher
585 while (true) {
586 load_thread_level = high;
587 start_load(desired_load); // Start up a given load
588 idle_thread_count = 0;
589 cyg_semaphore_post(&idle_thread_sem); // Start idle thread
590 cyg_thread_delay(1*100); // Pause for one second
591 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
592 load_idle = idle_thread_count;
593 start_load(0); // Shut down background load
594 percent_load = 100 - ((load_idle * 100) / no_load_idle);
595 diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level,
596 (int)idle_thread_count, percent_load);
597 if ( percent_load > desired_load )
598 break; // HIGH level is indeed higher
599 low = load_thread_level; // known to be lower
600 high *= 2; // else double it and try again
601 }
602
603 // Now chop down to the level required
604 while (true) {
605 load_thread_level = (high + low) / 2;
606 start_load(desired_load); // Start up a given load
607 idle_thread_count = 0;
608 cyg_semaphore_post(&idle_thread_sem); // Start idle thread
609 cyg_thread_delay(1*100); // Pause for one second
610 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
611 load_idle = idle_thread_count;
612 start_load(0); // Shut down background load
613 percent_load = 100 - ((load_idle * 100) / no_load_idle);
614 diag_printf("Load[%d] = %d => %d%%\n", load_thread_level,
615 (int)idle_thread_count, percent_load);
616 if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;
617 if (percent_load < desired_load) {
618 low = load_thread_level;
619 } else {
620 high = load_thread_level;
621 }
622 }
623
624 // Now we are within a few percent of the target; scale the load
625 // factor to get a better fit, and test it, print the answer.
626 load_thread_level *= desired_load;
627 load_thread_level /= percent_load;
628 start_load(desired_load); // Start up a given load
629 idle_thread_count = 0;
630 cyg_semaphore_post(&idle_thread_sem); // Start idle thread
631 cyg_thread_delay(1*100); // Pause for one second
632 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread
633 load_idle = idle_thread_count;
634 start_load(0); // Shut down background load
635 percent_load = 100 - ((load_idle * 100) / no_load_idle);
636 diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level,
637 (int)idle_thread_count, percent_load);
638 // no_load_idle_count_1_second = no_load_idle;
639 }
640
641 //
642 // This function is called to set up a load level of 'load' percent (given
643 // as a whole number, e.g. start_load(20) would mean initiate a background
644 // load of 20%, leaving the cpu 80% idle).
645 //
646 static void
647 start_load(int load)
648 {
649 static int prev_load = 0;
650 int i;
651 test_printf("Set background load = %d%%\n", load);
652 if (load == 0) {
653 if (prev_load == 0) return; // Nothing out there to stop
654 for (i = 0; i < prev_load/10; i++) {
655 cyg_semaphore_wait(&load_thread_sem[i]);
656 }
657 prev_load = 0;
658 } else {
659 for (i = 0; i < load/10; i++) {
660 cyg_semaphore_post(&load_thread_sem[i]);
661 }
662 prev_load = load;
663 }
664 }
665
666 //
667 // These thread(s) do some amount of "background" computing. This is used
668 // to simulate a given load level. They need to be run at a higher priority
669 // than the network code itself.
670 //
671 // Like the "idle" thread, they run as long as their "switch" (aka semaphore)
672 // is enabled.
673 //
674 void
675 net_load(cyg_addrword_t who)
676 {
677 int i;
678 while (true) {
679 cyg_semaphore_wait(&load_thread_sem[who]);
680 for (i = 0; i < load_thread_level; i++) {
681 do_some_random_computation(i);
682 }
683 cyg_thread_delay(1); // Wait until the next 'tick'
684 cyg_semaphore_post(&load_thread_sem[who]);
685 }
686 }
687
688 //
689 // Some arbitrary computation, designed to use up the CPU and cause associated
690 // cache "thrash" behaviour - part of background load modelling.
691 //
692 static void
693 do_some_random_computation(int p)
694 {
695 // Just something that might be "hard"
696 volatile double x;
697 x = ((p * 10) * 3.14159) / 180.0; // radians
698 }
699
700 //
701 // This thread does nothing but count. It will be allowed to count
702 // as long as the semaphore is "free".
703 //
704 void
705 net_idle(cyg_addrword_t param)
706 {
707 while (true) {
708 cyg_semaphore_wait(&idle_thread_sem);
709 idle_thread_count++;
710 cyg_semaphore_post(&idle_thread_sem);
711 }
712 }
713
714 void
715 cyg_start(void)
716 {
717 int i;
718 // Create processing threads
719 for (i = 0; i < CYGHWR_NET_DRIVERS; i++) {
720 cyg_thread_create(MAIN_THREAD_PRIORITY, // Priority
721 net_test, // entry
722 i, // entry parameter
723 "Network test", // Name
724 &main_thread_stack[i][0], // Stack
725 STACK_SIZE, // Size
726 &main_thread_handle[i], // Handle
727 &main_thread_data[i] // Thread data structure
728 );
729 }
730 cyg_thread_resume(main_thread_handle[0]); // Start first one
731 // Create the idle thread environment
732 cyg_semaphore_init(&idle_thread_sem, 0);
733 cyg_thread_create(IDLE_THREAD_PRIORITY, // Priority
734 net_idle, // entry
735 0, // entry parameter
736 "Network idle", // Name
737 &idle_thread_stack[0], // Stack
738 STACK_SIZE, // Size
739 &idle_thread_handle, // Handle
740 &idle_thread_data // Thread data structure
741 );
742 cyg_thread_resume(idle_thread_handle); // Start it
743 // Create the load threads and their environment(s)
744 for (i = 0; i < NUM_LOAD_THREADS; i++) {
745 cyg_semaphore_init(&load_thread_sem[i], 0);
746 cyg_thread_create(LOAD_THREAD_PRIORITY, // Priority
747 net_load, // entry
748 i, // entry parameter
749 "Background load", // Name
750 &load_thread_stack[i][0], // Stack
751 STACK_SIZE, // Size
752 &load_thread_handle[i], // Handle
753 &load_thread_data[i] // Thread data structure
754 );
755 cyg_thread_resume(load_thread_handle[i]); // Start it
756 }
757 cyg_scheduler_start();
758 }
759
760 #else
761
762 int
763 main(int argc, char *argv[])
764 {
765 net_test(0);
766 }
767 #endif