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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [tests/] [smp.cxx] - Blame information for rev 786

Details | Compare with Previous | View Log

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