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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [common/] [v2_0/] [tests/] [nc6_test_slave.c] - Blame information for rev 307

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

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

powered by: WebSVN 2.1.0

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