//==========================================================================
|
//==========================================================================
|
//
|
//
|
// smp.cxx
|
// smp.cxx
|
//
|
//
|
// SMP tests
|
// SMP tests
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// eCos is free software; you can redistribute it and/or modify it under
|
// the terms of the GNU General Public License as published by the Free
|
// the terms of the GNU General Public License as published by the Free
|
// Software Foundation; either version 2 or (at your option) any later version.
|
// Software Foundation; either version 2 or (at your option) any later version.
|
//
|
//
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use macros
|
// As a special exception, if other files instantiate templates or use macros
|
// or inline functions from this file, or you compile this file and link it
|
// or inline functions from this file, or you compile this file and link it
|
// with other works to produce a work based on this file, this file does not
|
// with other works to produce a work based on this file, this file does not
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// License. However the source code for this file must still be made available
|
// License. However the source code for this file must still be made available
|
// in accordance with section (3) of the GNU General Public License.
|
// in accordance with section (3) of the GNU General Public License.
|
//
|
//
|
// This exception does not invalidate any other reasons why a work based on
|
// This exception does not invalidate any other reasons why a work based on
|
// this file might be covered by the GNU General Public License.
|
// this file might be covered by the GNU General Public License.
|
//
|
//
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// -------------------------------------------
|
// -------------------------------------------
|
//####ECOSGPLCOPYRIGHTEND####
|
//####ECOSGPLCOPYRIGHTEND####
|
//==========================================================================
|
//==========================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): nickg
|
// Author(s): nickg
|
// Contributors: nickg
|
// Contributors: nickg
|
// Date: 2001-06-18
|
// Date: 2001-06-18
|
// Description: Some basic SMP tests.
|
// Description: Some basic SMP tests.
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//==========================================================================
|
//==========================================================================
|
|
|
#include <pkgconf/kernel.h>
|
#include <pkgconf/kernel.h>
|
#include <pkgconf/hal.h>
|
#include <pkgconf/hal.h>
|
|
|
#if 1
|
#if 1
|
#include <cyg/kernel/sched.hxx>
|
#include <cyg/kernel/sched.hxx>
|
#include <cyg/kernel/thread.hxx>
|
#include <cyg/kernel/thread.hxx>
|
#include <cyg/kernel/thread.inl>
|
#include <cyg/kernel/thread.inl>
|
#include <cyg/kernel/mutex.hxx>
|
#include <cyg/kernel/mutex.hxx>
|
#include <cyg/kernel/sema.hxx>
|
#include <cyg/kernel/sema.hxx>
|
#include <cyg/kernel/sched.inl>
|
#include <cyg/kernel/sched.inl>
|
#include <cyg/kernel/clock.hxx>
|
#include <cyg/kernel/clock.hxx>
|
#include <cyg/kernel/clock.inl>
|
#include <cyg/kernel/clock.inl>
|
#endif
|
#endif
|
|
|
#include <cyg/kernel/kapi.h>
|
#include <cyg/kernel/kapi.h>
|
|
|
#include <cyg/infra/testcase.h>
|
#include <cyg/infra/testcase.h>
|
#include <cyg/infra/diag.h>
|
#include <cyg/infra/diag.h>
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
#if defined(CYGPKG_KERNEL_SMP_SUPPORT) && \
|
#if defined(CYGPKG_KERNEL_SMP_SUPPORT) && \
|
defined(CYGFUN_KERNEL_API_C) && \
|
defined(CYGFUN_KERNEL_API_C) && \
|
defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \
|
defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \
|
defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
|
defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
|
!defined(CYGPKG_HAL_I386_LINUX) && \
|
!defined(CYGPKG_HAL_I386_LINUX) && \
|
!defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \
|
!defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \
|
(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
|
(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
#define NTHREADS 1
|
#define NTHREADS 1
|
#include "testaux.hxx"
|
#include "testaux.hxx"
|
|
|
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
|
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
|
|
|
#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*3)
|
#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*3)
|
|
|
static int ncpus = CYGNUM_KERNEL_CPU_MAX;
|
static int ncpus = CYGNUM_KERNEL_CPU_MAX;
|
static int nthread = NTHREADS_MAX;
|
static int nthread = NTHREADS_MAX;
|
|
|
static char stacks[NTHREADS_MAX][STACK_SIZE];
|
static char stacks[NTHREADS_MAX][STACK_SIZE];
|
static cyg_thread test_threads[NTHREADS_MAX];
|
static cyg_thread test_threads[NTHREADS_MAX];
|
static cyg_handle_t threads[NTHREADS_MAX];
|
static cyg_handle_t threads[NTHREADS_MAX];
|
|
|
static volatile cyg_uint32 cpu_run[CYGNUM_KERNEL_CPU_MAX];
|
static volatile cyg_uint32 cpu_run[CYGNUM_KERNEL_CPU_MAX];
|
static volatile int failed = false;
|
static volatile int failed = false;
|
static volatile cyg_uint32 cpu_thread[CYGNUM_KERNEL_CPU_MAX];
|
static volatile cyg_uint32 cpu_thread[CYGNUM_KERNEL_CPU_MAX];
|
|
|
static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX];
|
static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX];
|
|
|
|
|
static cyg_mutex_t mx;
|
static cyg_mutex_t mx;
|
|
|
|
|
//==========================================================================
|
//==========================================================================
|
// Compute a name for a thread
|
// Compute a name for a thread
|
char *
|
char *
|
thread_name(char *basename, int indx) {
|
thread_name(char *basename, int indx) {
|
return "<<NULL>>"; // Not currently used
|
return "<<NULL>>"; // Not currently used
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
void
|
void
|
test_thread_cpu(CYG_ADDRESS id)
|
test_thread_cpu(CYG_ADDRESS id)
|
{
|
{
|
for(;;)
|
for(;;)
|
cpu_run[CYG_KERNEL_CPU_THIS()] = true;
|
cpu_run[CYG_KERNEL_CPU_THIS()] = true;
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
// First test: just run as many threads as CPUs and check that we
|
// First test: just run as many threads as CPUs and check that we
|
// get to run on each CPU.
|
// get to run on each CPU.
|
|
|
void run_smp_test_cpus()
|
void run_smp_test_cpus()
|
{
|
{
|
int i;
|
int i;
|
|
|
CYG_TEST_INFO( "CPU Test: Check CPUs functional");
|
CYG_TEST_INFO( "CPU Test: Check CPUs functional");
|
|
|
// Init flags.
|
// Init flags.
|
for (i = 0; i < ncpus; i++)
|
for (i = 0; i < ncpus; i++)
|
cpu_run[i] = false;
|
cpu_run[i] = false;
|
|
|
// Set my priority higher than any I plan to create
|
// Set my priority higher than any I plan to create
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
|
|
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
cyg_thread_create(10, // Priority - just a number
|
cyg_thread_create(10, // Priority - just a number
|
test_thread_cpu, // entry
|
test_thread_cpu, // entry
|
i, // index
|
i, // index
|
thread_name("thread", i), // Name
|
thread_name("thread", i), // Name
|
&stacks[i][0], // Stack
|
&stacks[i][0], // Stack
|
STACK_SIZE, // Size
|
STACK_SIZE, // Size
|
&threads[i], // Handle
|
&threads[i], // Handle
|
&test_threads[i] // Thread data structure
|
&test_threads[i] // Thread data structure
|
);
|
);
|
cyg_thread_resume( threads[i]);
|
cyg_thread_resume( threads[i]);
|
}
|
}
|
|
|
// Just wait a while, until the threads have all run for a bit.
|
// Just wait a while, until the threads have all run for a bit.
|
cyg_thread_delay( 10 );
|
cyg_thread_delay( 10 );
|
|
|
// Delete all the threads
|
// Delete all the threads
|
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
cyg_thread_delete(threads[i]);
|
cyg_thread_delete(threads[i]);
|
}
|
}
|
|
|
// And check that a thread ran on each CPU
|
// And check that a thread ran on each CPU
|
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
|
// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
|
if( !cpu_run[i] )
|
if( !cpu_run[i] )
|
{
|
{
|
CYG_TEST_INFO( "CPU didn't run" );
|
CYG_TEST_INFO( "CPU didn't run" );
|
failed++;
|
failed++;
|
}
|
}
|
}
|
}
|
|
|
CYG_TEST_INFO( "CPU Test: done");
|
CYG_TEST_INFO( "CPU Test: done");
|
}
|
}
|
|
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
void
|
void
|
test_thread_pri(CYG_ADDRESS id)
|
test_thread_pri(CYG_ADDRESS id)
|
{
|
{
|
for(;;)
|
for(;;)
|
{
|
{
|
cpu_thread[CYG_KERNEL_CPU_THIS()] = id;
|
cpu_thread[CYG_KERNEL_CPU_THIS()] = id;
|
}
|
}
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
// Second test: Run a thread on each CPU and then by manipulating the
|
// Second test: Run a thread on each CPU and then by manipulating the
|
// priorities, get the current thread to migrate to each CPU in turn.
|
// priorities, get the current thread to migrate to each CPU in turn.
|
|
|
|
|
void run_smp_test_pri()
|
void run_smp_test_pri()
|
{
|
{
|
int i;
|
int i;
|
|
|
CYG_TEST_INFO( "Pri Test: Check set_priority functionality");
|
CYG_TEST_INFO( "Pri Test: Check set_priority functionality");
|
|
|
// Init flags.
|
// Init flags.
|
for (i = 0; i < ncpus; i++)
|
for (i = 0; i < ncpus; i++)
|
cpu_run[i] = false;
|
cpu_run[i] = false;
|
|
|
// Set my priority higher than any I plan to creat
|
// Set my priority higher than any I plan to creat
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
|
|
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
cyg_thread_create(10, // Priority - just a number
|
cyg_thread_create(10, // Priority - just a number
|
test_thread_pri, // entry
|
test_thread_pri, // entry
|
i, // index
|
i, // index
|
thread_name("thread", i), // Name
|
thread_name("thread", i), // Name
|
&stacks[i][0], // Stack
|
&stacks[i][0], // Stack
|
STACK_SIZE, // Size
|
STACK_SIZE, // Size
|
&threads[i], // Handle
|
&threads[i], // Handle
|
&test_threads[i] // Thread data structure
|
&test_threads[i] // Thread data structure
|
);
|
);
|
cyg_thread_resume( threads[i]);
|
cyg_thread_resume( threads[i]);
|
}
|
}
|
|
|
cyg_thread_delay( 2 );
|
cyg_thread_delay( 2 );
|
|
|
cyg_handle_t cthread = threads[0];
|
cyg_handle_t cthread = threads[0];
|
cyg_thread_set_priority(cthread, 25);
|
cyg_thread_set_priority(cthread, 25);
|
|
|
// Just wait a while, until the threads have all run for a bit.
|
// Just wait a while, until the threads have all run for a bit.
|
cyg_thread_delay( 2 );
|
cyg_thread_delay( 2 );
|
|
|
for (i = 0; i < ncpus*500; i++)
|
for (i = 0; i < ncpus*500; i++)
|
{
|
{
|
HAL_SMP_CPU_TYPE cpu = i % CYG_KERNEL_CPU_COUNT();
|
HAL_SMP_CPU_TYPE cpu = i % CYG_KERNEL_CPU_COUNT();
|
|
|
if( cpu != CYG_KERNEL_CPU_THIS() )
|
if( cpu != CYG_KERNEL_CPU_THIS() )
|
{
|
{
|
// At this point we have the current thread running on a
|
// At this point we have the current thread running on a
|
// CPU at priority 2, ncpus-1 threads running at priority
|
// CPU at priority 2, ncpus-1 threads running at priority
|
// 10 and the last thread (cthread) in the run queue at
|
// 10 and the last thread (cthread) in the run queue at
|
// priority 25.
|
// priority 25.
|
|
|
// Pick a thread on a different CPU
|
// Pick a thread on a different CPU
|
cyg_handle_t dthread;
|
cyg_handle_t dthread;
|
|
|
do
|
do
|
{
|
{
|
dthread = threads[cpu_thread[cpu]];
|
dthread = threads[cpu_thread[cpu]];
|
} while( dthread == cthread );
|
} while( dthread == cthread );
|
|
|
// Change the priority of the victim thread to 20. It is
|
// Change the priority of the victim thread to 20. It is
|
// still higher priority than cthread so it will continue
|
// still higher priority than cthread so it will continue
|
// running.
|
// running.
|
|
|
cyg_thread_set_priority(dthread, 20);
|
cyg_thread_set_priority(dthread, 20);
|
|
|
// Now change our priority to 15. We are still higher
|
// Now change our priority to 15. We are still higher
|
// priority that cthread so we will still run.
|
// priority that cthread so we will still run.
|
|
|
cyg_thread_set_priority(cyg_thread_self(), 15);
|
cyg_thread_set_priority(cyg_thread_self(), 15);
|
|
|
// Finally change the priority of cthread to 10. This will
|
// Finally change the priority of cthread to 10. This will
|
// cause it to preempt us on the current CPU. In turn we
|
// cause it to preempt us on the current CPU. In turn we
|
// will preempt dthread on its CPU.
|
// will preempt dthread on its CPU.
|
|
|
// NOTE: This relies somewhat on the SMP scheduler doing
|
// NOTE: This relies somewhat on the SMP scheduler doing
|
// what we expect here. Specifically, that it will preempt
|
// what we expect here. Specifically, that it will preempt
|
// the current thread with cthread locally. A more
|
// the current thread with cthread locally. A more
|
// sophisticated scheduler might decide that the most
|
// sophisticated scheduler might decide that the most
|
// efficient thing to do is to preempt dthread with
|
// efficient thing to do is to preempt dthread with
|
// cthread remotely, leaving the current thread where it
|
// cthread remotely, leaving the current thread where it
|
// is. If we ever bother to implement this, then this test
|
// is. If we ever bother to implement this, then this test
|
// will need to change.
|
// will need to change.
|
|
|
cyg_thread_set_priority(cthread, 10);
|
cyg_thread_set_priority(cthread, 10);
|
|
|
// Spin here a while until the scheduler sorts itself out.
|
// Spin here a while until the scheduler sorts itself out.
|
|
|
for( int j = 0; j < 100000; j++ );
|
for( int j = 0; j < 100000; j++ );
|
|
|
// Indicate that we have run on this CPU
|
// Indicate that we have run on this CPU
|
cpu_run[CYG_KERNEL_CPU_THIS()]++;
|
cpu_run[CYG_KERNEL_CPU_THIS()]++;
|
|
|
// Restore our priority to 2 and depress dthread to 25 and
|
// Restore our priority to 2 and depress dthread to 25 and
|
// make it the new cthread.
|
// make it the new cthread.
|
|
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
cyg_thread_set_priority(dthread, 25);
|
cyg_thread_set_priority(dthread, 25);
|
cthread = dthread;
|
cthread = dthread;
|
}
|
}
|
}
|
}
|
|
|
|
|
// Delete all the threads
|
// Delete all the threads
|
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
cyg_thread_delete(threads[i]);
|
cyg_thread_delete(threads[i]);
|
}
|
}
|
|
|
// And check that a thread ran on each CPU
|
// And check that a thread ran on each CPU
|
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
|
// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
|
if( !cpu_run[i] )
|
if( !cpu_run[i] )
|
{
|
{
|
CYG_TEST_INFO( "CPU didn't run" );
|
CYG_TEST_INFO( "CPU didn't run" );
|
failed++;
|
failed++;
|
}
|
}
|
}
|
}
|
|
|
CYG_TEST_INFO( "PRI Test: done");
|
CYG_TEST_INFO( "PRI Test: done");
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
void
|
void
|
test_thread_timeslice(CYG_ADDRESS id)
|
test_thread_timeslice(CYG_ADDRESS id)
|
{
|
{
|
for(;;)
|
for(;;)
|
slicerun[id][CYG_KERNEL_CPU_THIS()]++;
|
slicerun[id][CYG_KERNEL_CPU_THIS()]++;
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
// First test: just run as many threads as CPUs and check that we
|
// First test: just run as many threads as CPUs and check that we
|
// get to run on each CPU.
|
// get to run on each CPU.
|
|
|
void run_smp_test_timeslice()
|
void run_smp_test_timeslice()
|
{
|
{
|
int i;
|
int i;
|
|
|
CYG_TEST_INFO( "Timeslice Test: Check timeslicing works");
|
CYG_TEST_INFO( "Timeslice Test: Check timeslicing works");
|
|
|
// Init flags.
|
// Init flags.
|
for (i = 0; i < nthread; i++)
|
for (i = 0; i < nthread; i++)
|
for( int j = 0; j < ncpus; j++ )
|
for( int j = 0; j < ncpus; j++ )
|
slicerun[i][j] = 0;
|
slicerun[i][j] = 0;
|
|
|
// Set my priority higher than any I plan to create
|
// Set my priority higher than any I plan to create
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
cyg_thread_set_priority(cyg_thread_self(), 2);
|
|
|
for (i = 0; i < nthread; i++) {
|
for (i = 0; i < nthread; i++) {
|
cyg_thread_create(10, // Priority - just a number
|
cyg_thread_create(10, // Priority - just a number
|
test_thread_timeslice, // entry
|
test_thread_timeslice, // entry
|
i, // index
|
i, // index
|
thread_name("thread", i), // Name
|
thread_name("thread", i), // Name
|
&stacks[i][0], // Stack
|
&stacks[i][0], // Stack
|
STACK_SIZE, // Size
|
STACK_SIZE, // Size
|
&threads[i], // Handle
|
&threads[i], // Handle
|
&test_threads[i] // Thread data structure
|
&test_threads[i] // Thread data structure
|
);
|
);
|
cyg_thread_resume( threads[i]);
|
cyg_thread_resume( threads[i]);
|
}
|
}
|
|
|
// Just wait a while, until the threads have all run for a bit.
|
// Just wait a while, until the threads have all run for a bit.
|
cyg_thread_delay( 200 );
|
cyg_thread_delay( 200 );
|
|
|
// Delete all the threads
|
// Delete all the threads
|
for (i = 0; i < nthread; i++) {
|
for (i = 0; i < nthread; i++) {
|
cyg_thread_suspend(threads[i]);
|
cyg_thread_suspend(threads[i]);
|
}
|
}
|
|
|
|
|
// And check that a thread ran on each CPU
|
// And check that a thread ran on each CPU
|
|
|
cyg_uint32 cpu_total[ncpus];
|
cyg_uint32 cpu_total[ncpus];
|
cyg_uint32 cpu_threads[ncpus];
|
cyg_uint32 cpu_threads[ncpus];
|
cyg_uint32 thread_total[nthread];
|
cyg_uint32 thread_total[nthread];
|
|
|
diag_printf(" Thread ");
|
diag_printf(" Thread ");
|
for( int j = 0; j < ncpus; j++ )
|
for( int j = 0; j < ncpus; j++ )
|
{
|
{
|
cpu_total[j] = 0;
|
cpu_total[j] = 0;
|
cpu_threads[j] = 0;
|
cpu_threads[j] = 0;
|
diag_printf(" CPU %2d",j);
|
diag_printf(" CPU %2d",j);
|
}
|
}
|
diag_printf(" Total\n");
|
diag_printf(" Total\n");
|
for (i = 0; i < nthread; i++)
|
for (i = 0; i < nthread; i++)
|
{
|
{
|
thread_total[i] = 0;
|
thread_total[i] = 0;
|
diag_printf(" %2d ",i);
|
diag_printf(" %2d ",i);
|
for( int j = 0; j < ncpus; j++ )
|
for( int j = 0; j < ncpus; j++ )
|
{
|
{
|
thread_total[i] += slicerun[i][j];
|
thread_total[i] += slicerun[i][j];
|
cpu_total[j] += slicerun[i][j];
|
cpu_total[j] += slicerun[i][j];
|
if( slicerun[i][j] > 0 )
|
if( slicerun[i][j] > 0 )
|
cpu_threads[j]++;
|
cpu_threads[j]++;
|
diag_printf(" %8d",slicerun[i][j]);
|
diag_printf(" %8d",slicerun[i][j]);
|
}
|
}
|
diag_printf("%8d\n",thread_total[i]);
|
diag_printf("%8d\n",thread_total[i]);
|
}
|
}
|
diag_printf(" Total ");
|
diag_printf(" Total ");
|
for( int j = 0; j < ncpus; j++ )
|
for( int j = 0; j < ncpus; j++ )
|
diag_printf(" %8d",cpu_total[j]);
|
diag_printf(" %8d",cpu_total[j]);
|
diag_printf("\n");
|
diag_printf("\n");
|
diag_printf("Threads ");
|
diag_printf("Threads ");
|
for( int j = 0; j < ncpus; j++ )
|
for( int j = 0; j < ncpus; j++ )
|
{
|
{
|
diag_printf(" %8d",cpu_threads[j]);
|
diag_printf(" %8d",cpu_threads[j]);
|
if( cpu_threads[j] < 2 )
|
if( cpu_threads[j] < 2 )
|
failed++;
|
failed++;
|
}
|
}
|
diag_printf("\n");
|
diag_printf("\n");
|
|
|
// Delete all the threads
|
// Delete all the threads
|
for (i = 0; i < nthread; i++) {
|
for (i = 0; i < nthread; i++) {
|
cyg_thread_delete(threads[i]);
|
cyg_thread_delete(threads[i]);
|
}
|
}
|
|
|
CYG_TEST_INFO( "Timeslice Test: done");
|
CYG_TEST_INFO( "Timeslice Test: done");
|
}
|
}
|
|
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
void
|
void
|
run_smp_tests(CYG_ADDRESS id)
|
run_smp_tests(CYG_ADDRESS id)
|
{
|
{
|
cyg_mutex_init( &mx );
|
cyg_mutex_init( &mx );
|
|
|
for( int i = 0; i < 100; i++ )
|
for( int i = 0; i < 100; i++ )
|
{
|
{
|
run_smp_test_cpus();
|
run_smp_test_cpus();
|
run_smp_test_pri();
|
run_smp_test_pri();
|
run_smp_test_timeslice();
|
run_smp_test_timeslice();
|
}
|
}
|
|
|
if( failed )
|
if( failed )
|
CYG_TEST_FAIL_FINISH("SMP tests failed\n");
|
CYG_TEST_FAIL_FINISH("SMP tests failed\n");
|
|
|
CYG_TEST_PASS_FINISH("SMP tests OK");
|
CYG_TEST_PASS_FINISH("SMP tests OK");
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
void smp_main( void )
|
void smp_main( void )
|
{
|
{
|
CYG_TEST_INIT();
|
CYG_TEST_INIT();
|
|
|
// Work out how many CPUs we actually have.
|
// Work out how many CPUs we actually have.
|
ncpus = CYG_KERNEL_CPU_COUNT();
|
ncpus = CYG_KERNEL_CPU_COUNT();
|
|
|
new_thread(run_smp_tests, 0);
|
new_thread(run_smp_tests, 0);
|
|
|
cyg_scheduler_start();
|
cyg_scheduler_start();
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
|
externC void
|
externC void
|
cyg_hal_invoke_constructors();
|
cyg_hal_invoke_constructors();
|
#endif
|
#endif
|
|
|
externC void
|
externC void
|
cyg_start( void )
|
cyg_start( void )
|
{
|
{
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
|
#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
|
cyg_hal_invoke_constructors();
|
cyg_hal_invoke_constructors();
|
#endif
|
#endif
|
smp_main();
|
smp_main();
|
}
|
}
|
|
|
//==========================================================================
|
//==========================================================================
|
|
|
#else // CYGPKG_KERNEL_SMP_SUPPORT etc.
|
#else // CYGPKG_KERNEL_SMP_SUPPORT etc.
|
|
|
externC void
|
externC void
|
cyg_start( void )
|
cyg_start( void )
|
{
|
{
|
CYG_TEST_INIT();
|
CYG_TEST_INIT();
|
CYG_TEST_NA("SMP test requires:\n"
|
CYG_TEST_NA("SMP test requires:\n"
|
"CYGPKG_KERNEL_SMP_SUPPORT &&\n"
|
"CYGPKG_KERNEL_SMP_SUPPORT &&\n"
|
"CYGFUN_KERNEL_API_C && \n"
|
"CYGFUN_KERNEL_API_C && \n"
|
"CYGSEM_KERNEL_SCHED_MLQUEUE &&\n"
|
"CYGSEM_KERNEL_SCHED_MLQUEUE &&\n"
|
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
|
"CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
|
"!CYGPKG_HAL_I386_LINUX &&\n"
|
"!CYGPKG_HAL_I386_LINUX &&\n"
|
"!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n"
|
"!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n"
|
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
|
"(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
|
}
|
}
|
#endif // CYGPKG_KERNEL_SMP_SUPPORT etc.
|
#endif // CYGPKG_KERNEL_SMP_SUPPORT etc.
|
|
|
//==========================================================================
|
//==========================================================================
|
// EOF tm_basic.cxx
|
// EOF tm_basic.cxx
|
|
|