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

powered by: WebSVN 2.1.0

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