📄 tm_basic.cxx
字号:
//==========================================================================
//
// tm_basic.cxx
//
// Basic timing test / scaffolding
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002, 2003 Gary Thomas
//
// 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): gthomas
// Contributors: gthomas
// Date: 1998-10-19
// Description: Very simple kernel timing test
//####DESCRIPTIONEND####
#include <pkgconf/kernel.h>
#include <pkgconf/hal.h>
#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/flag.hxx>
#include <cyg/kernel/sched.inl>
#include <cyg/kernel/clock.hxx>
#include <cyg/kernel/clock.inl>
#include <cyg/kernel/kapi.h>
#include <cyg/infra/testcase.h>
#include <cyg/infra/diag.h>
#include <cyg/kernel/test/stackmon.h>
#include CYGHWR_MEMORY_LAYOUT_H
// Define this to see the statistics with the first sample datum removed.
// This can expose the effects of caches on the speed of operations.
#undef STATS_WITHOUT_FIRST_SAMPLE
#if defined(CYGFUN_KERNEL_API_C) && \ defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ !defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \ (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
#define NTHREADS 1
#include "testaux.hxx"
// Structure used to keep track of times
typedef struct fun_times {
cyg_uint32 start;
cyg_uint32 end;
} fun_times;
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
#ifdef CYGMEM_REGION_ram_SIZE
#define CYG_THREAD_OVERHEAD (STACK_SIZE+sizeof(cyg_thread)+(sizeof(fun_times)*2))
#define NTEST_THREADS ((CYGMEM_REGION_ram_SIZE/16)/CYG_THREAD_OVERHEAD)
#define CYG_MUTEX_OVERHEAD (sizeof(cyg_mutex_t)+sizeof(fun_times))
#define NMUTEXES ((CYGMEM_REGION_ram_SIZE/16)/CYG_MUTEX_OVERHEAD)
#define CYG_MBOX_OVERHEAD (sizeof(cyg_mbox)+sizeof(fun_times))
#define NMBOXES ((CYGMEM_REGION_ram_SIZE/24)/CYG_MBOX_OVERHEAD)
#define CYG_SEMAPHORE_OVERHEAD (sizeof(cyg_sem_t)+sizeof(fun_times))
#define NSEMAPHORES ((CYGMEM_REGION_ram_SIZE/16)/CYG_SEMAPHORE_OVERHEAD)
#define CYG_COUNTER_OVERHEAD (sizeof(cyg_counter)+sizeof(fun_times))
#define NCOUNTERS ((CYGMEM_REGION_ram_SIZE/24)/CYG_COUNTER_OVERHEAD)
#define CYG_FLAG_OVERHEAD (sizeof(cyg_flag_t)+sizeof(fun_times))
#define NFLAGS ((CYGMEM_REGION_ram_SIZE/24)/CYG_FLAG_OVERHEAD)
#define CYG_ALARM_OVERHEAD (sizeof(cyg_alarm)+sizeof(fun_times))
#define NALARMS ((CYGMEM_REGION_ram_SIZE/16)/CYG_ALARM_OVERHEAD)
#else
// Defaults
#define NTEST_THREADS 16
#define NMUTEXES 32
#define NMBOXES 32
#define NSEMAPHORES 32
#define NFLAGS 32
#define NCOUNTERS 32
#define NALARMS 32
#endif
#define NSAMPLES 32
#define NTHREAD_SWITCHES 128
#define NSCHEDS 128
#define NSAMPLES_SIM 2
#define NTEST_THREADS_SIM 2
#define NTHREAD_SWITCHES_SIM 4
#define NMUTEXES_SIM 2
#define NMBOXES_SIM 2
#define NSEMAPHORES_SIM 2
#define NSCHEDS_SIM 4
#define NFLAGS_SIM 2
#define NCOUNTERS_SIM 2
#define NALARMS_SIM 2
static int nsamples;
static int ntest_threads;
static int nthread_switches;
static int nmutexes;
static int nmboxes;
static int nsemaphores;
static int nscheds;
static int nflags;
static int ncounters;
static int nalarms;
static char stacks[NTEST_THREADS][STACK_SIZE];
static cyg_thread test_threads[NTEST_THREADS];
static cyg_handle_t threads[NTEST_THREADS];
static int overhead;
static cyg_sem_t synchro;
static fun_times thread_ft[NTEST_THREADS];
static fun_times test2_ft[NTHREAD_SWITCHES];
static cyg_mutex_t test_mutexes[NMUTEXES];
static fun_times mutex_ft[NMUTEXES];
static cyg_thread mutex_test_thread;
static cyg_handle_t mutex_test_thread_handle;
static cyg_mbox test_mboxes[NMBOXES];
static cyg_handle_t test_mbox_handles[NMBOXES];
static fun_times mbox_ft[NMBOXES];
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
static cyg_thread mbox_test_thread;
static cyg_handle_t mbox_test_thread_handle;
#endif
static cyg_sem_t test_semaphores[NSEMAPHORES];
static fun_times semaphore_ft[NSEMAPHORES];
static cyg_thread semaphore_test_thread;
static cyg_handle_t semaphore_test_thread_handle;
static fun_times sched_ft[NSCHEDS];
static cyg_counter test_counters[NCOUNTERS];
static cyg_handle_t counters[NCOUNTERS];
static fun_times counter_ft[NCOUNTERS];
static cyg_flag_t test_flags[NFLAGS];
static fun_times flag_ft[NFLAGS];
static cyg_alarm test_alarms[NALARMS];
static cyg_handle_t alarms[NALARMS];
static fun_times alarm_ft[NALARMS];
static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
static long ns_per_system_clock;
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
// Data kept by kernel real time clock measuring clock interrupt latency
extern cyg_tick_count total_clock_latency, total_clock_interrupts;
extern cyg_int32 min_clock_latency, max_clock_latency;
extern bool measure_clock_latency;
#endif
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;
extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency;
extern bool measure_clock_latency;
#endif
void run_sched_tests(void);
void run_thread_tests(void);
void run_thread_switch_test(void);
void run_mutex_tests(void);
void run_mutex_circuit_test(void);
void run_mbox_tests(void);
void run_mbox_circuit_test(void);
void run_semaphore_tests(void);
void run_semaphore_circuit_test(void);
void run_counter_tests(void);
void run_flag_tests(void);
void run_alarm_tests(void);
#ifndef max
#define max(n,m) (m > n ? n : m)
#endif
// Wait until a clock tick [real time clock] has passed. This should keep it
// from happening again during a measurement, thus minimizing any fluctuations
void
wait_for_tick(void)
{
cyg_tick_count_t tv0, tv1;
tv0 = cyg_current_time();
while (true) {
tv1 = cyg_current_time();
if (tv1 != tv0) break;
}
}
// Display a number of ticks as microseconds
// Note: for improved calculation significance, values are kept in ticks*1000
void
show_ticks_in_us(cyg_uint32 ticks)
{
long long ns;
ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
ns += 5; // for rounding to .01us
diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10));
}
//
// If the kernel is instrumented to measure clock interrupt latency, these
// measurements can be drastically perturbed by printing via "diag_printf()"
// since that code may run with interrupts disabled for long periods.
//
// In order to get accurate/reasonable latency figures _for the kernel
// primitive functions beint tested_, the kernel's latency measurements
// are suspended while the printing actually takes place.
//
// The measurements are reenabled after the printing, thus allowing for
// fair measurements of the kernel primitives, which are not distorted
// by the printing mechanisms.
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
void
disable_clock_latency_measurement(void)
{
wait_for_tick();
measure_clock_latency = false;
}
void
enable_clock_latency_measurement(void)
{
wait_for_tick();
measure_clock_latency = true;
}
// Ensure that the measurements are reasonable (no startup anomalies)
void
reset_clock_latency_measurement(void)
{
disable_clock_latency_measurement();
total_clock_latency = 0;
total_clock_interrupts = 0;
min_clock_latency = 0x7FFFFFFF;
max_clock_latency = 0;
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
total_clock_dsr_latency = 0;
total_clock_dsr_calls = 0;
min_clock_dsr_latency = 0x7FFFFFFF;
max_clock_dsr_latency = 0;
#endif
enable_clock_latency_measurement();
}
#else
#define disable_clock_latency_measurement()
#define enable_clock_latency_measurement()
#define reset_clock_latency_measurement()
#endif
void
show_times_hdr(void)
{
disable_clock_latency_measurement();
diag_printf("\n");
diag_printf(" Confidence\n");
diag_printf(" Ave Min Max Var Ave Min Function\n");
diag_printf(" ====== ====== ====== ====== ========== ========\n");
enable_clock_latency_measurement();
}
void
show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first)
{
int i, delta, min, max, con_ave, con_min, ave_dev;
int start_sample, total_samples;
cyg_int32 total, ave;
if (ignore_first) {
start_sample = 1;
total_samples = nsamples-1;
} else {
start_sample = 0;
total_samples = nsamples;
}
total = 0;
min = 0x7FFFFFFF;
max = 0;
for (i = start_sample; i < nsamples; i++) {
if (ft[i].end < ft[i].start) {
// Clock wrapped around (timer tick)
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
} else {
delta = ft[i].end - ft[i].start;
}
delta -= overhead;
if (delta < 0) delta = 0;
delta *= 1000;
total += delta;
if (delta < min) min = delta;
if (delta > max) max = delta;
}
ave = total / total_samples;
total = 0;
ave_dev = 0;
for (i = start_sample; i < nsamples; i++) {
if (ft[i].end < ft[i].start) {
// Clock wrapped around (timer tick)
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
} else {
delta = ft[i].end - ft[i].start;
}
delta -= overhead;
if (delta < 0) delta = 0;
delta *= 1000;
delta = delta - ave;
if (delta < 0) delta = -delta;
ave_dev += delta;
}
ave_dev /= total_samples;
con_ave = 0;
con_min = 0;
for (i = start_sample; i < nsamples; i++) {
if (ft[i].end < ft[i].start) {
// Clock wrapped around (timer tick)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -