⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smp.cxx

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -