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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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