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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [common/] [current/] [tests/] [nc6_test_slave.c] - Blame information for rev 856

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

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

powered by: WebSVN 2.1.0

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