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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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