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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [kernel/] [v2_0/] [tests/] [smp.cxx] - Blame information for rev 1774

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

Line No. Rev Author Line
1 1254 phoenix
//==========================================================================
2
//
3
//        smp.cxx
4
//
5
//        SMP tests
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):     nickg
44
// Contributors:  nickg
45
// Date:          2001-06-18
46
// Description:   Some basic SMP tests.
47
//
48
//####DESCRIPTIONEND####
49
//==========================================================================
50
 
51
#include <pkgconf/kernel.h>
52
#include <pkgconf/hal.h>
53
 
54
#if 1
55
#include <cyg/kernel/sched.hxx>
56
#include <cyg/kernel/thread.hxx>
57
#include <cyg/kernel/thread.inl>
58
#include <cyg/kernel/mutex.hxx>
59
#include <cyg/kernel/sema.hxx>
60
#include <cyg/kernel/sched.inl>
61
#include <cyg/kernel/clock.hxx>
62
#include <cyg/kernel/clock.inl>
63
#endif
64
 
65
#include <cyg/kernel/kapi.h>
66
 
67
#include <cyg/infra/testcase.h>
68
#include <cyg/infra/diag.h>
69
 
70
//==========================================================================
71
 
72
#if defined(CYGPKG_KERNEL_SMP_SUPPORT) &&       \
73
    defined(CYGFUN_KERNEL_API_C) &&             \
74
    defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&     \
75
    defined(CYGVAR_KERNEL_COUNTERS_CLOCK) &&    \
76
    !defined(CYGPKG_HAL_I386_LINUX) &&          \
77
    !defined(CYGDBG_INFRA_DIAG_USE_DEVICE) &&   \
78
    (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
79
 
80
//==========================================================================
81
 
82
#define NTHREADS 1
83
#include "testaux.hxx"
84
 
85
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
86
 
87
#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*3)
88
 
89
static int ncpus = CYGNUM_KERNEL_CPU_MAX;
90
static int nthread = NTHREADS_MAX;
91
 
92
static char stacks[NTHREADS_MAX][STACK_SIZE];
93
static cyg_thread test_threads[NTHREADS_MAX];
94
static cyg_handle_t threads[NTHREADS_MAX];
95
 
96
static volatile cyg_uint32 cpu_run[CYGNUM_KERNEL_CPU_MAX];
97
static volatile int failed = false;
98
static volatile cyg_uint32 cpu_thread[CYGNUM_KERNEL_CPU_MAX];
99
 
100
static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX];
101
 
102
 
103
static cyg_mutex_t mx;
104
 
105
 
106
//==========================================================================
107
// Compute a name for a thread
108
char *
109
thread_name(char *basename, int indx) {
110
    return "<<NULL>>";  // Not currently used
111
}
112
 
113
//==========================================================================
114
 
115
void
116
test_thread_cpu(CYG_ADDRESS id)
117
{
118
    for(;;)
119
        cpu_run[CYG_KERNEL_CPU_THIS()] = true;
120
}
121
 
122
//==========================================================================
123
// First test: just run as many threads as CPUs and check that we
124
// get to run on each CPU.
125
 
126
void run_smp_test_cpus()
127
{
128
    int i;
129
 
130
    CYG_TEST_INFO( "CPU Test: Check CPUs functional");
131
 
132
    // Init flags.
133
    for (i = 0;  i < ncpus;  i++)
134
        cpu_run[i] = false;
135
 
136
    // Set my priority higher than any I plan to create
137
    cyg_thread_set_priority(cyg_thread_self(), 2);
138
 
139
    for (i = 0;  i < ncpus;  i++) {
140
        cyg_thread_create(10,              // Priority - just a number
141
                          test_thread_cpu, // entry
142
                          i,               // index
143
                          thread_name("thread", i),     // Name
144
                          &stacks[i][0],   // Stack
145
                          STACK_SIZE,      // Size
146
                          &threads[i],     // Handle
147
                          &test_threads[i] // Thread data structure
148
            );
149
        cyg_thread_resume( threads[i]);
150
    }
151
 
152
    // Just wait a while, until the threads have all run for a bit.
153
    cyg_thread_delay( 10 );
154
 
155
    // Delete all the threads
156
    for (i = 0;  i < ncpus;  i++) {
157
        cyg_thread_delete(threads[i]);
158
    }
159
 
160
    // And check that a thread ran on each CPU
161
    for (i = 0;  i < ncpus;  i++) {
162
//        CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
163
        if( !cpu_run[i] )
164
        {
165
            CYG_TEST_INFO( "CPU didn't run" );
166
            failed++;
167
        }
168
    }
169
 
170
    CYG_TEST_INFO( "CPU Test: done");
171
}
172
 
173
 
174
//==========================================================================
175
 
176
void
177
test_thread_pri(CYG_ADDRESS id)
178
{
179
    for(;;)
180
    {
181
        cpu_thread[CYG_KERNEL_CPU_THIS()] = id;
182
    }
183
}
184
 
185
//==========================================================================
186
// Second test: Run a thread on each CPU and then by manipulating the
187
// priorities, get the current thread to migrate to each CPU in turn.
188
 
189
 
190
void run_smp_test_pri()
191
{
192
    int i;
193
 
194
    CYG_TEST_INFO( "Pri Test: Check set_priority functionality");
195
 
196
    // Init flags.
197
    for (i = 0;  i < ncpus;  i++)
198
        cpu_run[i] = false;
199
 
200
    // Set my priority higher than any I plan to creat
201
    cyg_thread_set_priority(cyg_thread_self(), 2);
202
 
203
    for (i = 0;  i < ncpus;  i++) {
204
        cyg_thread_create(10,              // Priority - just a number
205
                          test_thread_pri, // entry
206
                          i,               // index
207
                          thread_name("thread", i),     // Name
208
                          &stacks[i][0],   // Stack
209
                          STACK_SIZE,      // Size
210
                          &threads[i],     // Handle
211
                          &test_threads[i] // Thread data structure
212
            );
213
        cyg_thread_resume( threads[i]);
214
    }
215
 
216
    cyg_thread_delay( 2 );
217
 
218
    cyg_handle_t cthread = threads[0];
219
    cyg_thread_set_priority(cthread, 25);
220
 
221
    // Just wait a while, until the threads have all run for a bit.
222
    cyg_thread_delay( 2 );
223
 
224
    for (i = 0;  i < ncpus*500;  i++)
225
    {
226
        HAL_SMP_CPU_TYPE cpu = i % CYG_KERNEL_CPU_COUNT();
227
 
228
        if( cpu != CYG_KERNEL_CPU_THIS() )
229
        {
230
            // At this point we have the current thread running on a
231
            // CPU at priority 2, ncpus-1 threads running at priority
232
            // 10 and the last thread (cthread) in the run queue at
233
            // priority 25.
234
 
235
            // Pick a thread on a different CPU
236
            cyg_handle_t dthread;
237
 
238
            do
239
            {
240
                dthread = threads[cpu_thread[cpu]];
241
            } while( dthread == cthread );
242
 
243
            // Change the priority of the victim thread to 20. It is
244
            // still higher priority than cthread so it will continue
245
            // running.
246
 
247
            cyg_thread_set_priority(dthread, 20);
248
 
249
            // Now change our priority to 15. We are still higher
250
            // priority that cthread so we will still run.
251
 
252
            cyg_thread_set_priority(cyg_thread_self(), 15);
253
 
254
            // Finally change the priority of cthread to 10. This will
255
            // cause it to preempt us on the current CPU. In turn we
256
            // will preempt dthread on its CPU.
257
 
258
            // NOTE: This relies somewhat on the SMP scheduler doing
259
            // what we expect here. Specifically, that it will preempt
260
            // the current thread with cthread locally. A more
261
            // sophisticated scheduler might decide that the most
262
            // efficient thing to do is to preempt dthread with
263
            // cthread remotely, leaving the current thread where it
264
            // is. If we ever bother to implement this, then this test
265
            // will need to change.
266
 
267
            cyg_thread_set_priority(cthread, 10);
268
 
269
            // Spin here a while until the scheduler sorts itself out.
270
 
271
            for( int j = 0; j < 100000; j++ );
272
 
273
            // Indicate that we have run on this CPU
274
            cpu_run[CYG_KERNEL_CPU_THIS()]++;
275
 
276
            // Restore our priority to 2 and depress dthread to 25 and
277
            // make it the new cthread.
278
 
279
            cyg_thread_set_priority(cyg_thread_self(), 2);
280
            cyg_thread_set_priority(dthread, 25);
281
            cthread = dthread;
282
        }
283
    }
284
 
285
 
286
    // Delete all the threads
287
    for (i = 0;  i < ncpus;  i++) {
288
        cyg_thread_delete(threads[i]);
289
    }
290
 
291
    // And check that a thread ran on each CPU
292
    for (i = 0;  i < ncpus;  i++) {
293
//        CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
294
        if( !cpu_run[i] )
295
        {
296
            CYG_TEST_INFO( "CPU didn't run" );
297
            failed++;
298
        }
299
    }
300
 
301
    CYG_TEST_INFO( "PRI Test: done");
302
}
303
 
304
//==========================================================================
305
 
306
void
307
test_thread_timeslice(CYG_ADDRESS id)
308
{
309
    for(;;)
310
        slicerun[id][CYG_KERNEL_CPU_THIS()]++;
311
}
312
 
313
//==========================================================================
314
// First test: just run as many threads as CPUs and check that we
315
// get to run on each CPU.
316
 
317
void run_smp_test_timeslice()
318
{
319
    int i;
320
 
321
    CYG_TEST_INFO( "Timeslice Test: Check timeslicing works");
322
 
323
    // Init flags.
324
    for (i = 0;  i < nthread;  i++)
325
        for( int j = 0; j < ncpus; j++ )
326
            slicerun[i][j] = 0;
327
 
328
    // Set my priority higher than any I plan to create
329
    cyg_thread_set_priority(cyg_thread_self(), 2);
330
 
331
    for (i = 0;  i < nthread;  i++) {
332
        cyg_thread_create(10,              // Priority - just a number
333
                          test_thread_timeslice, // entry
334
                          i,               // index
335
                          thread_name("thread", i),     // Name
336
                          &stacks[i][0],   // Stack
337
                          STACK_SIZE,      // Size
338
                          &threads[i],     // Handle
339
                          &test_threads[i] // Thread data structure
340
            );
341
        cyg_thread_resume( threads[i]);
342
    }
343
 
344
    // Just wait a while, until the threads have all run for a bit.
345
    cyg_thread_delay( 200 );
346
 
347
    // Delete all the threads
348
    for (i = 0;  i < nthread;  i++) {
349
        cyg_thread_suspend(threads[i]);
350
    }
351
 
352
 
353
    // And check that a thread ran on each CPU
354
 
355
    cyg_uint32 cpu_total[ncpus];
356
    cyg_uint32 cpu_threads[ncpus];
357
    cyg_uint32 thread_total[nthread];
358
 
359
    diag_printf(" Thread ");
360
    for( int j = 0; j < ncpus; j++ )
361
    {
362
        cpu_total[j] = 0;
363
        cpu_threads[j] = 0;
364
        diag_printf("   CPU %2d",j);
365
    }
366
    diag_printf("   Total\n");
367
    for (i = 0;  i < nthread;  i++)
368
    {
369
        thread_total[i] = 0;
370
        diag_printf("     %2d ",i);
371
        for( int j = 0; j < ncpus; j++ )
372
        {
373
            thread_total[i] += slicerun[i][j];
374
            cpu_total[j] += slicerun[i][j];
375
            if( slicerun[i][j] > 0 )
376
                cpu_threads[j]++;
377
            diag_printf(" %8d",slicerun[i][j]);
378
        }
379
        diag_printf("%8d\n",thread_total[i]);
380
    }
381
    diag_printf(" Total  ");
382
    for( int j = 0; j < ncpus; j++ )
383
        diag_printf(" %8d",cpu_total[j]);
384
    diag_printf("\n");
385
    diag_printf("Threads ");
386
    for( int j = 0; j < ncpus; j++ )
387
    {
388
        diag_printf(" %8d",cpu_threads[j]);
389
        if( cpu_threads[j] < 2 )
390
            failed++;
391
    }
392
    diag_printf("\n");
393
 
394
    // Delete all the threads
395
    for (i = 0;  i < nthread;  i++) {
396
        cyg_thread_delete(threads[i]);
397
    }
398
 
399
    CYG_TEST_INFO( "Timeslice Test: done");
400
}
401
 
402
 
403
//==========================================================================
404
 
405
void
406
run_smp_tests(CYG_ADDRESS id)
407
{
408
    cyg_mutex_init( &mx );
409
 
410
    for( int i = 0; i < 100; i++ )
411
    {
412
        run_smp_test_cpus();
413
        run_smp_test_pri();
414
        run_smp_test_timeslice();
415
    }
416
 
417
    if( failed )
418
        CYG_TEST_FAIL_FINISH("SMP tests failed\n");
419
 
420
    CYG_TEST_PASS_FINISH("SMP tests OK");
421
}
422
 
423
//==========================================================================
424
 
425
void smp_main( void )
426
{
427
    CYG_TEST_INIT();
428
 
429
    // Work out how many CPUs we actually have.
430
    ncpus = CYG_KERNEL_CPU_COUNT();
431
 
432
    new_thread(run_smp_tests, 0);
433
 
434
    cyg_scheduler_start();
435
}
436
 
437
//==========================================================================
438
 
439
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
440
externC void
441
cyg_hal_invoke_constructors();
442
#endif
443
 
444
externC void
445
cyg_start( void )
446
{
447
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
448
    cyg_hal_invoke_constructors();
449
#endif
450
    smp_main();
451
}
452
 
453
//==========================================================================
454
 
455
#else // CYGPKG_KERNEL_SMP_SUPPORT etc.
456
 
457
externC void
458
cyg_start( void )
459
{
460
    CYG_TEST_INIT();
461
    CYG_TEST_NA("SMP test requires:\n"
462
                "CYGPKG_KERNEL_SMP_SUPPORT &&\n"
463
                "CYGFUN_KERNEL_API_C && \n"
464
                "CYGSEM_KERNEL_SCHED_MLQUEUE &&\n"
465
                "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
466
                "!CYGPKG_HAL_I386_LINUX &&\n"
467
                "!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n"
468
                "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
469
}
470
#endif // CYGPKG_KERNEL_SMP_SUPPORT etc.
471
 
472
//==========================================================================
473
// EOF tm_basic.cxx

powered by: WebSVN 2.1.0

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