OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [lwip_tcpip/] [current/] [tests/] [nc_test_slave.c] - Blame information for rev 865

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
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
#include <cyg/hal/hal_arch.h>
33
#include <cyg/infra/diag.h>
34
#include <cyg/infra/testcase.h>
35
 
36
#include <pkgconf/net_lwip.h>
37
 
38
#include <lwip.h>
39
#include <lwip/sockets.h>
40
 
41
#ifdef CYGFUN_LWIP_MODE_SEQUENTIAL
42
#if LWIP_SOCKET
43
#if LWIP_TCP
44
#if LWIP_UDP
45
#if LWIP_COMPAT_SOCKETS
46
#if LWIP_POSIX_SOCKETS_IO_NAMES
47
#if 1 // SO_REUSE
48
 
49
 
50
#ifndef CYGPKG_LIBC_STDIO
51
#include <cyg/error/errno.h>
52
#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
53
#else
54
#include <stdio.h>
55
#endif
56
 
57
#include "nc_test_framework.h"
58
 
59
 
60
#define STACK_SIZE               (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
61
#define MAX_LOAD_THREAD_LEVEL    20
62
#define MIN_LOAD_THREAD_LEVEL    0
63
#define NUM_LOAD_THREADS         10
64
#define CYGPKG_NET_THREAD_PRIORITY 7
65
#define IDLE_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY+3
66
#define LOAD_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-1
67
#define MAIN_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-2
68
#define DESIRED_BACKGROUND_LOAD  20
69
 
70
static char         main_thread_stack[STACK_SIZE];
71
static char         idle_thread_stack[STACK_SIZE];
72
static cyg_thread   idle_thread_data;
73
static cyg_handle_t idle_thread_handle;
74
static cyg_sem_t    idle_thread_sem;
75
volatile static long long    idle_thread_count;
76
static cyg_tick_count_t idle_thread_start_time;
77
static cyg_tick_count_t idle_thread_stop_time;
78
static char         load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
79
static cyg_thread   load_thread_data[NUM_LOAD_THREADS];
80
static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
81
static cyg_sem_t    load_thread_sem[NUM_LOAD_THREADS];
82
static long         load_thread_level;
83
static void calibrate_load(int load);
84
static void start_load(int load);
85
static void do_some_random_computation(int p);
86
#define abs(n) ((n) < 0 ? -(n) : (n))
87
 
88
#define test_param_t cyg_addrword_t
89
#ifdef CYGDBG_NET_TIMING_STATS
90
extern void show_net_times(void);
91
#endif
92
 
93
#define MAX_BUF 8192
94
static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF];
95
 
96
extern void
97
cyg_test_exit(void);
98
 
99
static void
100
test_delay(int ticks)
101
{
102
    cyg_thread_delay(ticks);
103
}
104
 
105
 
106
void
107
pexit(char *s)
108
{
109
    perror(s);
110
#ifdef CYGDBG_NET_TIMING_STATS
111
    show_net_times();
112
#endif
113
    cyg_test_exit();
114
}
115
 
116
//
117
// Generic UDP test
118
//
119
 
120
static void
121
do_udp_test(int s1, struct nc_request *req, struct sockaddr_in *master)
122
{
123
    int i, s, td_len, seq, seq_errors, lost;
124
    struct sockaddr_in test_chan_slave, test_chan_master;
125
    fd_set fds;
126
    struct timeval timeout;
127
    struct nc_test_results results;
128
    struct nc_test_data *tdp;
129
    int nsent, nrecvd;
130
    int need_recv, need_send;
131
 
132
    need_recv = true;  need_send = true;
133
    switch (ntohl(req->type)) {
134
    case NC_REQUEST_UDP_SEND:
135
        need_recv = false;
136
        need_send = true;
137
        break;
138
    case NC_REQUEST_UDP_RECV:
139
        need_recv = true;
140
        need_send = false;
141
        break;
142
    case NC_REQUEST_UDP_ECHO:
143
        break;
144
    }
145
 
146
    s = socket(AF_INET, SOCK_DGRAM, 0);
147
    if (s < 0) {
148
        pexit("datagram socket");
149
    }
150
 
151
    memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave));
152
    test_chan_slave.sin_family = AF_INET;
153
    test_chan_slave.sin_len = sizeof(test_chan_slave);
154
    test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY);
155
    test_chan_slave.sin_port = htons(ntohl(req->slave_port));
156
 
157
    if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) {
158
        perror("bind");
159
        close(s);
160
    }
161
 
162
    memcpy(&test_chan_master, master, sizeof(*master));
163
    test_chan_master.sin_port = htons(ntohl(req->master_port));
164
    nsent = 0;  nrecvd = 0;  seq = 0;  seq_errors = 0;  lost = 0;
165
    for (i = 0;  i < ntohl(req->nbufs);  i++) {
166
        if (need_recv) {
167
            FD_ZERO(&fds);
168
            FD_SET(s, &fds);
169
            timeout.tv_sec = NC_TEST_TIMEOUT;
170
            timeout.tv_usec = 0;
171
            if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
172
                test_printf("recvfrom timeout, expecting seq #%d\n", seq);
173
                if (++lost > MAX_ERRORS) {
174
                    test_printf("... giving up\n");
175
                    break;
176
                }
177
            } else {
178
                nrecvd++;
179
                tdp = (struct nc_test_data *)in_buf;
180
                td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
181
                if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) {
182
                    perror("recvfrom");
183
                    close(s);
184
                    return;
185
                }
186
                if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
187
                    (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
188
                    if (ntohl(tdp->seq) != seq) {
189
                        test_printf("Packets out of sequence - recvd: %lu, expected: %d\n",
190
                                    ntohl(tdp->seq), seq);
191
                        seq = ntohl(tdp->seq);
192
                        seq_errors++;
193
                    }
194
                } else {
195
                    test_printf("Bad data packet - key: %lx/%lx, seq: %lu\n",
196
                                ntohl(tdp->key1), ntohl(tdp->key2),
197
                                ntohl(tdp->seq));
198
                }
199
            }
200
        }
201
        if (need_send) {
202
            int retries = 10;
203
            int  sent = false;
204
            int res;
205
 
206
            tdp = (struct nc_test_data *)out_buf;
207
            tdp->key1 = htonl(NC_TEST_DATA_KEY1);
208
            tdp->key2 = htonl(NC_TEST_DATA_KEY2);
209
            tdp->seq = htonl(seq);
210
            td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
211
            tdp->len = htonl(td_len);
212
            while (!sent && (--retries >= 0)) {
213
                res = sendto(s, tdp, td_len, 0,
214
                             (struct sockaddr *)&test_chan_master, sizeof(test_chan_master));
215
                if (res > 0) {
216
                    sent = true;
217
                    break;
218
                }
219
                if (errno == ENOBUFS) {
220
                    // Saturated the system
221
                    test_delay(1);   // Time for 200 500 byte 10-baseT packets 
222
                } else {
223
                    // What else to do?
224
                    close(s);
225
                    return;
226
                }
227
            }
228
            if (sent) {
229
                nsent++;
230
            } else {
231
                perror("sendto");
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 results");
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, td_len, seq, seq_errors, lost, test_chan, res;
283
    struct sockaddr_in test_chan_slave, test_chan_master;
284
    socklen_t len;
285
    struct nc_test_results results;
286
    struct nc_test_data *tdp;
287
    int nsent, nrecvd;
288
    int need_recv, need_send;
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
#if SO_REUSE
311
        {
312
            int one = 1;
313
 
314
            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
315
                perror("setsockopt SO_REUSEADDR");
316
                return;
317
            }
318
            if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
319
                perror("setsockopt SO_REUSEPORT");
320
                return;
321
            }
322
        }
323
#endif
324
        memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave));
325
        test_chan_slave.sin_family = AF_INET;
326
        test_chan_slave.sin_len = sizeof(test_chan_slave);
327
        test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY);
328
        test_chan_slave.sin_port = htons(ntohl(req->slave_port));
329
 
330
        if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) {
331
            perror("bind");
332
            close(s);
333
        }
334
        listen(s, 128);
335
        slave_tcp_port = s;
336
    }
337
 
338
    s = slave_tcp_port;
339
    len = sizeof(test_chan_master);
340
    if ((test_chan = accept(s, (struct sockaddr *)&test_chan_master, &len)) < 0) {
341
        pexit("accept");
342
    }
343
    len = sizeof(test_chan_master);
344
    getpeername(test_chan, (struct sockaddr *)&test_chan_master, &len);
345
    test_printf("connection from %s.%d\n", inet_ntoa(test_chan_master.sin_addr),
346
                ntohs(test_chan_master.sin_port));
347
 
348
    nsent = 0;  nrecvd = 0;  seq = 0;  seq_errors = 0;  lost = 0;
349
    for (i = 0;  i < ntohl(req->nbufs);  i++) {
350
        if (need_recv) {
351
            tdp = (struct nc_test_data *)in_buf;
352
            td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
353
            res = do_read(test_chan, tdp, td_len);
354
            if (res != td_len) {
355
                test_printf("recvfrom timeout, expecting seq #%d\n", seq);
356
                if (++lost > MAX_ERRORS) {
357
                    test_printf("... giving up\n");
358
                    break;
359
                }
360
            } else {
361
                nrecvd++;
362
                if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
363
                    (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
364
                    if (ntohl(tdp->seq) != seq) {
365
                        test_printf("Packets out of sequence - recvd: %lu, expected: %d\n",
366
                                    ntohl(tdp->seq), seq);
367
                        seq = ntohl(tdp->seq);
368
                        seq_errors++;
369
                    }
370
                } else {
371
                    test_printf("Bad data packet - key: %lx/%lx, seq: %lu\n",
372
                                ntohl(tdp->key1), ntohl(tdp->key2),
373
                                ntohl(tdp->seq));
374
                }
375
            }
376
        }
377
        if (need_send) {
378
            tdp = (struct nc_test_data *)out_buf;
379
            tdp->key1 = htonl(NC_TEST_DATA_KEY1);
380
            tdp->key2 = htonl(NC_TEST_DATA_KEY2);
381
            tdp->seq = htonl(seq);
382
            td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
383
            tdp->len = htonl(td_len);
384
            if (write(test_chan, tdp, td_len) != td_len) {
385
                perror("write");
386
                if (errno == ENOBUFS) {
387
                    // Saturated the system
388
                    test_delay(25);
389
                } else {
390
                    // What else to do?
391
                    close(test_chan);
392
                    return;
393
                }
394
            } else {
395
                nsent++;
396
            }
397
        }
398
        seq++;
399
    }
400
    results.key1 = htonl(NC_TEST_RESULT_KEY1);
401
    results.key2 = htonl(NC_TEST_RESULT_KEY2);
402
    results.seq = req->seq;
403
    results.nsent = htonl(nsent);
404
    results.nrecvd = htonl(nrecvd);
405
    if (write(test_chan, &results, sizeof(results)) != sizeof(results)) {
406
        perror("write");
407
    }
408
    close(test_chan);
409
}
410
 
411
//
412
// Protocol driver for testing slave.
413
//
414
// This function is the main routine running here, handling requests sent from
415
// the master and providing various responses.
416
//
417
static void
418
nc_slave(test_param_t param)
419
{
420
    int s;
421
    struct sockaddr_in my_addr, master;
422
    socklen_t masterlen;
423
    struct nc_request req;
424
    struct nc_reply reply;
425
    int done = false;
426
 
427
    test_printf("Start test for eth%d\n", param);
428
 
429
    s = socket(AF_INET, SOCK_DGRAM, 0);
430
    if (s < 0) {
431
        pexit("datagram socket");
432
    }
433
 
434
    memset((char *) &my_addr, 0, sizeof(my_addr));
435
    my_addr.sin_family = AF_INET;
436
    my_addr.sin_len = sizeof(my_addr);
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
        test_printf("Request %lu from %s:%d\n", ntohl(req.type),
450
                    inet_ntoa(master.sin_addr), ntohs(master.sin_port));
451
        reply.response = htonl(NC_REPLY_ACK);
452
        reply.seq = req.seq;
453
        switch (ntohl(req.type)) {
454
        case NC_REQUEST_DISCONNECT:
455
            done = true;
456
            break;
457
        case NC_REQUEST_UDP_SEND:
458
            test_printf("UDP send - %lu buffers, %lu bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
459
            break;
460
        case NC_REQUEST_UDP_RECV:
461
            test_printf("UDP recv - %lu buffers, %lu bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
462
            break;
463
        case NC_REQUEST_UDP_ECHO:
464
            test_printf("UDP echo - %lu buffers, %lu bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
465
            break;
466
        case NC_REQUEST_TCP_SEND:
467
            test_printf("TCP send - %lu buffers, %lu bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
468
            break;
469
        case NC_REQUEST_TCP_RECV:
470
            test_printf("TCP recv - %lu buffers, %lu bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
471
            break;
472
        case NC_REQUEST_TCP_ECHO:
473
            test_printf("TCP echo - %lu buffers, %lu bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
474
            break;
475
        case NC_REQUEST_SET_LOAD:
476
            start_load(ntohl(req.nbufs));
477
            break;
478
        case NC_REQUEST_START_IDLE:
479
            test_printf("Start IDLE thread\n");
480
            idle_thread_count = 0;
481
            idle_thread_start_time = cyg_current_time();
482
            cyg_semaphore_post(&idle_thread_sem);
483
            break;
484
        case NC_REQUEST_STOP_IDLE:
485
            cyg_semaphore_wait(&idle_thread_sem);
486
            idle_thread_stop_time = cyg_current_time();
487
            test_printf("Stop IDLE thread\n");
488
            reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time);
489
            reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32);
490
            reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);
491
            break;
492
        default:
493
            test_printf("Unrecognized request: %lu\n", ntohl(req.type));
494
            reply.response = htonl(NC_REPLY_NAK);
495
            reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);
496
            break;
497
        }
498
        if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) {
499
            pexit("sendto");
500
        }
501
        if (reply.response == ntohl(NC_REPLY_NAK)) {
502
            continue;
503
        }
504
        switch (ntohl(req.type)) {
505
        case NC_REQUEST_UDP_SEND:
506
        case NC_REQUEST_UDP_RECV:
507
        case NC_REQUEST_UDP_ECHO:
508
            do_udp_test(s, &req, &master);
509
            break;
510
        case NC_REQUEST_TCP_SEND:
511
        case NC_REQUEST_TCP_RECV:
512
        case NC_REQUEST_TCP_ECHO:
513
            do_tcp_test(s, &req, &master);
514
            break;
515
        case NC_REQUEST_START_IDLE:
516
        case NC_REQUEST_STOP_IDLE:
517
        case NC_REQUEST_SET_LOAD:
518
        default:
519
            break;
520
        }
521
    }
522
    close(s);
523
}
524
 
525
void
526
net_test(void *arg)
527
{
528
    test_param_t param = (test_param_t)arg;
529
//    int i;
530
    if (param == 0) {
531
        test_printf("Start Network Characterization - SLAVE\n");
532
        calibrate_load(DESIRED_BACKGROUND_LOAD);
533
    }
534
    nc_slave(param);
535
#ifdef CYGDBG_NET_TIMING_STATS
536
    show_net_times();
537
#endif
538
#if LWIP_STATS_DISPLAY 
539
    stats_display();
540
#endif    
541
    cyg_test_exit();
542
}
543
 
544
 
545
//
546
// This function is called to calibrate the "background load" which can be
547
// applied during testing.  It will be called before any commands from the
548
// host are managed.
549
//
550
static void
551
calibrate_load(int desired_load)
552
{
553
    long long no_load_idle, load_idle;
554
    int percent_load;
555
    int high, low;
556
 
557
    // Set limits
558
    high = MAX_LOAD_THREAD_LEVEL;
559
    low = MIN_LOAD_THREAD_LEVEL;
560
 
561
    // Compute the "no load" idle value
562
    idle_thread_count = 0;
563
    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
564
    cyg_thread_delay(1*100);               // Pause for one second
565
    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
566
    no_load_idle = idle_thread_count;
567
    test_printf("No load = %d\n", (int)idle_thread_count);
568
 
569
    // First ensure that the HIGH level is indeed higher
570
    while (true) {
571
        load_thread_level = high;
572
        start_load(desired_load);              // Start up a given load
573
        idle_thread_count = 0;
574
        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
575
        cyg_thread_delay(1*100);               // Pause for one second
576
        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
577
        load_idle = idle_thread_count;
578
        start_load(0);                         // Shut down background load
579
        percent_load = 100 - ((load_idle * 100) / no_load_idle);
580
        test_printf("High Load[%ld] = %d => %d%%\n", load_thread_level,
581
                    (int)idle_thread_count, percent_load);
582
        if ( percent_load > desired_load )
583
            break; // HIGH level is indeed higher
584
        low = load_thread_level; // known to be lower
585
        high *= 2; // else double it and try again
586
    }
587
 
588
    // Now chop down to the level required
589
    while (true) {
590
        load_thread_level = (high + low) / 2;
591
        start_load(desired_load);              // Start up a given load
592
        idle_thread_count = 0;
593
        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
594
        cyg_thread_delay(1*100);               // Pause for one second
595
        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
596
        load_idle = idle_thread_count;
597
        start_load(0);                         // Shut down background load
598
        percent_load = 100 - ((load_idle * 100) / no_load_idle);
599
        test_printf("Load[%ld] = %d => %d%%\n", load_thread_level,
600
                    (int)idle_thread_count, percent_load);
601
        if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;
602
        if (percent_load < desired_load) {
603
            low = load_thread_level;
604
        } else {
605
            high = load_thread_level;
606
        }
607
    }
608
 
609
    // Now we are within a few percent of the target; scale the load
610
    // factor to get a better fit, and test it, print the answer.
611
    load_thread_level *= desired_load;
612
    load_thread_level /= percent_load;
613
    start_load(desired_load);              // Start up a given load
614
    idle_thread_count = 0;
615
    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
616
    cyg_thread_delay(1*100);               // Pause for one second
617
    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
618
    load_idle = idle_thread_count;
619
    start_load(0);                         // Shut down background load
620
    percent_load = 100 - ((load_idle * 100) / no_load_idle);
621
    test_printf("Final load[%ld] = %d => %d%%\n", load_thread_level,
622
                (int)idle_thread_count, percent_load);
623
//    no_load_idle_count_1_second = no_load_idle;
624
}
625
 
626
//
627
// This function is called to set up a load level of 'load' percent (given
628
// as a whole number, e.g. start_load(20) would mean initiate a background
629
// load of 20%, leaving the cpu 80% idle).
630
//
631
static void
632
start_load(int load)
633
{
634
    static int prev_load = 0;
635
    int i;
636
    test_printf("Set background load = %d%%\n", load);
637
    if (load == 0) {
638
        if (prev_load == 0) return;  // Nothing out there to stop
639
        for (i = 0;  i < prev_load/10;  i++) {
640
            cyg_semaphore_wait(&load_thread_sem[i]);
641
        }
642
        prev_load = 0;
643
    } else {
644
        for (i = 0;  i < load/10;  i++) {
645
            cyg_semaphore_post(&load_thread_sem[i]);
646
        }
647
        prev_load = load;
648
    }
649
}
650
 
651
//
652
// These thread(s) do some amount of "background" computing.  This is used
653
// to simulate a given load level.  They need to be run at a higher priority 
654
// than the network code itself.
655
//
656
// Like the "idle" thread, they run as long as their "switch" (aka semaphore)
657
// is enabled.
658
//
659
void
660
net_load(cyg_addrword_t who)
661
{
662
    int i;
663
    while (true) {
664
        cyg_semaphore_wait(&load_thread_sem[who]);
665
        for (i = 0;  i < load_thread_level;  i++) {
666
            do_some_random_computation(i);
667
        }
668
        cyg_thread_delay(1);  // Wait until the next 'tick'
669
        cyg_semaphore_post(&load_thread_sem[who]);
670
    }
671
}
672
 
673
//
674
// Some arbitrary computation, designed to use up the CPU and cause associated
675
// cache "thrash" behaviour - part of background load modelling.
676
//
677
static void
678
do_some_random_computation(int p)
679
{
680
    // Just something that might be "hard"
681
    volatile double x;
682
    x = ((p * 10) * 3.14159) / 180.0;  // radians
683
}
684
 
685
//
686
// This thread does nothing but count.  It will be allowed to count
687
// as long as the semaphore is "free".  
688
//
689
void
690
net_idle(cyg_addrword_t param)
691
{
692
    while (true) {
693
        cyg_semaphore_wait(&idle_thread_sem);
694
        idle_thread_count++;
695
        cyg_semaphore_post(&idle_thread_sem);
696
    }
697
}
698
 
699
static char stack[STACK_SIZE];
700
static cyg_thread thread_data;
701
static cyg_handle_t thread_handle;
702
 
703
void
704
tmain(cyg_addrword_t p)
705
{
706
    cyg_lwip_sequential_init();
707
    cyg_lwip_thread_new("main", net_test, NULL, main_thread_stack, STACK_SIZE, MAIN_THREAD_PRIORITY);
708
}
709
 
710
externC void
711
cyg_start( void )
712
{
713
    int i;
714
 
715
    CYG_TEST_INIT();
716
 
717
    // Create the idle thread environment
718
    cyg_semaphore_init(&idle_thread_sem, 0);
719
    cyg_thread_create(IDLE_THREAD_PRIORITY,     // Priority
720
                      net_idle,                 // entry
721
                      0,                        // entry parameter
722
                      "Network idle",           // Name
723
                      &idle_thread_stack[0],    // Stack
724
                      STACK_SIZE,               // Size
725
                      &idle_thread_handle,      // Handle
726
                      &idle_thread_data         // Thread data structure
727
    );
728
    cyg_thread_resume(idle_thread_handle);      // Start it
729
 
730
    // Create the load threads and their environment(s)
731
    for (i = 0;  i < NUM_LOAD_THREADS; i++) {
732
        cyg_semaphore_init(&load_thread_sem[i], 0);
733
        cyg_thread_create(LOAD_THREAD_PRIORITY,     // Priority
734
                          net_load,                 // entry
735
                          i,                        // entry parameter
736
                          "Background load",        // Name
737
                          &load_thread_stack[i][0], // Stack
738
                          STACK_SIZE,               // Size
739
                          &load_thread_handle[i],   // Handle
740
                          &load_thread_data[i]      // Thread data structure
741
        );
742
        cyg_thread_resume(load_thread_handle[i]);   // Start it
743
    }
744
 
745
    // Create a main thread, so we can run the scheduler and have time 'pass'
746
    cyg_thread_create(10,                       // Priority
747
                      tmain,                    // entry
748
                      0,                        // entry parameter
749
                      "socket echo test",       // Name
750
                      &stack[0],                // Stack
751
                      STACK_SIZE,               // Size
752
                      &thread_handle,           // Handle
753
                      &thread_data              // Thread data structure
754
            );
755
    cyg_thread_resume(thread_handle);           // Start it
756
 
757
    cyg_scheduler_start();
758
 
759
    CYG_TEST_FAIL_FINISH("Not reached");
760
}
761
 
762
#else // SO_REUSE
763
#define N_A_MSG "SO_REUSE currently unavailable"
764
#endif // SO_REUSE
765
 
766
#else // LWIP_POSIX_SOCKETS_IO_NAMES
767
#define N_A_MSG "POSIX socket function names disabled"
768
#endif
769
 
770
#else // LWIP_COMPAT_SOCKETS
771
#define N_A_MSG "Compatible socket support disabled"
772
#endif // LWIP_COMPAT_SOCKETS
773
 
774
#else // LWIP_UDP
775
#define N_A_MSG "UDP support disabled"
776
#endif // LWIP_UDP
777
 
778
#else // LWIP_TCP
779
#define N_A_MSG "TCP support disabled"
780
#endif // LWIP_TCP
781
 
782
#else // LWIP_SOCKET
783
#define N_A_MSG "Socket support disabled"
784
#endif // LWIP_SOCKET
785
 
786
#else // CYGFUN_LWIP_MODE_SEQUENTIAL
787
#define N_A_MSG "Not configured in 'Sequential' mode"
788
#endif // CYGFUN_LWIP_MODE_SEQUENTIAL
789
 
790
#ifdef N_A_MSG
791
externC void
792
cyg_start( void )
793
{
794
    CYG_TEST_INIT();
795
    CYG_TEST_NA(N_A_MSG);
796
}
797
#endif // N_A_MSG

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.